| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | module token |
| 5 | |
| 6 | const orm_custom_operators = ['like', 'ilike'] |
| 7 | |
| 8 | @[minify] |
| 9 | pub struct Token { |
| 10 | pub: |
| 11 | kind Kind // the token number/enum; for quick comparisons |
| 12 | lit string // literal representation of the token |
| 13 | line_nr int // the line number in the source where the token occurred |
| 14 | col u16 // the column in the source where the token occurred |
| 15 | file_idx i16 // file idx in the global table `filelist` |
| 16 | pos int // the position of the token in scanner text |
| 17 | len int // length of the literal |
| 18 | tidx int // the index of the token |
| 19 | } |
| 20 | |
| 21 | pub enum Kind { |
| 22 | unknown |
| 23 | eof |
| 24 | name // user |
| 25 | number // 123 |
| 26 | string // 'foo' |
| 27 | str_inter // 'name=${user.name}' |
| 28 | chartoken // `A` - rune |
| 29 | plus // + |
| 30 | minus // - |
| 31 | mul // * |
| 32 | power // ** |
| 33 | div // / |
| 34 | mod // % |
| 35 | xor // ^ |
| 36 | pipe // | |
| 37 | inc // ++ |
| 38 | dec // -- |
| 39 | and // && |
| 40 | logical_or // || |
| 41 | not // ! |
| 42 | bit_not // ~ |
| 43 | question // ? |
| 44 | comma // , |
| 45 | semicolon // ; |
| 46 | colon // : |
| 47 | arrow // <- |
| 48 | amp // & |
| 49 | hash // # |
| 50 | dollar // $ |
| 51 | at // @ |
| 52 | str_dollar |
| 53 | left_shift // << |
| 54 | right_shift // >> |
| 55 | unsigned_right_shift // >>> |
| 56 | not_in // !in |
| 57 | not_is // !is |
| 58 | assign // = |
| 59 | decl_assign // := |
| 60 | plus_assign // += |
| 61 | minus_assign // -= |
| 62 | div_assign // /= |
| 63 | mult_assign // *= |
| 64 | power_assign // **= |
| 65 | xor_assign // ^= |
| 66 | mod_assign // %= |
| 67 | or_assign // |= |
| 68 | and_assign // &= |
| 69 | right_shift_assign // <<= |
| 70 | left_shift_assign // >>= |
| 71 | unsigned_right_shift_assign // >>>= |
| 72 | boolean_and_assign // &&= |
| 73 | boolean_or_assign // ||= |
| 74 | lcbr // { |
| 75 | rcbr // } |
| 76 | lpar // ( |
| 77 | rpar // ) |
| 78 | lsbr // [ |
| 79 | nilsbr // #[ |
| 80 | rsbr // ] |
| 81 | eq // == |
| 82 | ne // != |
| 83 | gt // > |
| 84 | lt // < |
| 85 | ge // >= |
| 86 | le // <= |
| 87 | comment |
| 88 | nl |
| 89 | dot // . |
| 90 | dotdot // .. |
| 91 | ellipsis // ... |
| 92 | keyword_beg |
| 93 | key_as |
| 94 | key_asm |
| 95 | key_assert |
| 96 | key_atomic |
| 97 | key_break |
| 98 | key_const |
| 99 | key_continue |
| 100 | key_defer |
| 101 | key_else |
| 102 | key_enum |
| 103 | key_false |
| 104 | key_for |
| 105 | key_fn |
| 106 | key_global |
| 107 | key_go |
| 108 | key_goto |
| 109 | key_if |
| 110 | key_import |
| 111 | key_in |
| 112 | key_interface |
| 113 | key_is |
| 114 | key_match |
| 115 | key_module |
| 116 | key_mut |
| 117 | key_nil |
| 118 | key_shared |
| 119 | key_lock |
| 120 | key_rlock |
| 121 | key_none |
| 122 | key_return |
| 123 | key_select |
| 124 | key_like |
| 125 | key_ilike |
| 126 | key_sizeof |
| 127 | key_isreftype |
| 128 | key_likely |
| 129 | key_unlikely |
| 130 | key_offsetof |
| 131 | key_struct |
| 132 | key_true |
| 133 | key_type |
| 134 | key_typeof |
| 135 | key_dump |
| 136 | key_orelse |
| 137 | key_union |
| 138 | key_pub |
| 139 | key_static |
| 140 | key_volatile |
| 141 | key_unsafe |
| 142 | key_spawn |
| 143 | key_implements |
| 144 | keyword_end |
| 145 | _end_ |
| 146 | } |
| 147 | |
| 148 | // @FN => will be substituted with the name of the current V function |
| 149 | // @METHOD => will be substituted with ReceiverType.MethodName |
| 150 | // @MOD => will be substituted with the name of the current V module |
| 151 | // @STRUCT => will be substituted with the name of the current V struct |
| 152 | // @FILE => will be substituted with the path of the V source file |
| 153 | // @LINE => will be substituted with the V line number where it appears (as a string). |
| 154 | // @COLUMN => will be substituted with the column where it appears (as a string). |
| 155 | // @VHASH => will be substituted with the shortened commit hash of the V compiler (as a string). |
| 156 | // @VMOD_FILE => will be substituted with the contents of the nearest v.mod file (as a string). |
| 157 | // @VMODROOT => will be substituted with the *folder* where the nearest v.mod file is (as a string). |
| 158 | // @VEXE => will be substituted with the path to the V compiler |
| 159 | // @VEXEROOT => will be substituted with the *folder* where the V executable is (as a string). |
| 160 | // @VROOT => the old name for @VMODROOT; sometimes it was used as @VEXEROOT; |
| 161 | // Note: @VROOT is now deprecated, use either @VMODROOT or @VEXEROOT instead. |
| 162 | // Note: @VEXEROOT & @VMODROOT are used for compilation options like this: |
| 163 | // #include "@VMODROOT/include/abc.h" |
| 164 | // #flag -L@VEXEROOT/thirdparty/libgc |
| 165 | // |
| 166 | // The @XYZ tokens allow for code like this: |
| 167 | // println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @MOD + '.' + @FN) |
| 168 | // ... which is useful while debugging/tracing. |
| 169 | // |
| 170 | // @<type> is allowed for keyword variable names. E.g. 'type' |
| 171 | pub enum AtKind { |
| 172 | unknown |
| 173 | fn_name |
| 174 | method_name |
| 175 | mod_name |
| 176 | struct_name |
| 177 | vexe_path |
| 178 | file_path |
| 179 | file_dir |
| 180 | line_nr |
| 181 | column_nr |
| 182 | vhash |
| 183 | v_current_hash |
| 184 | vmod_file |
| 185 | vmodroot_path |
| 186 | vmod_hash |
| 187 | vroot_path // obsolete |
| 188 | vexeroot_path |
| 189 | file_path_line_nr |
| 190 | location |
| 191 | build_date |
| 192 | build_time |
| 193 | build_timestamp |
| 194 | os |
| 195 | ccompiler |
| 196 | backend |
| 197 | platform |
| 198 | } |
| 199 | |
| 200 | pub const assign_tokens = [Kind.assign, .decl_assign, .plus_assign, .minus_assign, .mult_assign, |
| 201 | .power_assign, .div_assign, .xor_assign, .mod_assign, .or_assign, .and_assign, |
| 202 | .right_shift_assign, .left_shift_assign, .unsigned_right_shift_assign, .boolean_and_assign, |
| 203 | .boolean_or_assign] |
| 204 | |
| 205 | pub const valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT', |
| 206 | '@VEXE', '@FILE', '@DIR', '@LINE', '@COLUMN', '@VHASH', '@VCURRENTHASH', '@VMOD_FILE', |
| 207 | '@VMODHASH', '@FILE_LINE', '@LOCATION', '@BUILD_DATE', '@BUILD_TIME', '@BUILD_TIMESTAMP', '@OS', |
| 208 | '@CCOMPILER', '@BACKEND', '@PLATFORM'] |
| 209 | |
| 210 | pub const token_str = build_token_str() |
| 211 | |
| 212 | pub const keywords = build_keys() |
| 213 | |
| 214 | pub const scanner_matcher = new_keywords_matcher_trie[Kind](keywords) |
| 215 | |
| 216 | // build_keys generates a map with keywords' string values: |
| 217 | // Keywords['return'] == .key_return |
| 218 | @[direct_array_access] |
| 219 | fn build_keys() map[string]Kind { |
| 220 | mut res := map[string]Kind{} |
| 221 | for t in int(Kind.keyword_beg) + 1 .. int(Kind.keyword_end) { |
| 222 | key := token_str[t] |
| 223 | |
| 224 | // Exclude custom ORM operators from V keyword list |
| 225 | if key in orm_custom_operators { |
| 226 | continue |
| 227 | } |
| 228 | |
| 229 | res[key] = unsafe { Kind(t) } |
| 230 | } |
| 231 | return res |
| 232 | } |
| 233 | |
| 234 | // TODO: remove once we have `enum Kind { name('name') if('if') ... }` |
| 235 | @[direct_array_access] |
| 236 | fn build_token_str() []string { |
| 237 | mut s := []string{len: int(Kind._end_)} |
| 238 | s[Kind.unknown] = 'unknown' |
| 239 | s[Kind.eof] = 'eof' |
| 240 | s[Kind.name] = 'name' |
| 241 | s[Kind.number] = 'number' |
| 242 | s[Kind.string] = 'string' |
| 243 | s[Kind.chartoken] = 'char' |
| 244 | s[Kind.plus] = '+' |
| 245 | s[Kind.minus] = '-' |
| 246 | s[Kind.mul] = '*' |
| 247 | s[Kind.power] = '**' |
| 248 | s[Kind.div] = '/' |
| 249 | s[Kind.mod] = '%' |
| 250 | s[Kind.xor] = '^' |
| 251 | s[Kind.bit_not] = '~' |
| 252 | s[Kind.pipe] = '|' |
| 253 | s[Kind.hash] = '#' |
| 254 | s[Kind.amp] = '&' |
| 255 | s[Kind.inc] = '++' |
| 256 | s[Kind.dec] = '--' |
| 257 | s[Kind.and] = '&&' |
| 258 | s[Kind.logical_or] = '||' |
| 259 | s[Kind.not] = '!' |
| 260 | s[Kind.dot] = '.' |
| 261 | s[Kind.dotdot] = '..' |
| 262 | s[Kind.ellipsis] = '...' |
| 263 | s[Kind.comma] = ',' |
| 264 | s[Kind.not_in] = '!in' |
| 265 | s[Kind.not_is] = '!is' |
| 266 | s[Kind.semicolon] = ';' |
| 267 | s[Kind.colon] = ':' |
| 268 | s[Kind.arrow] = '<-' |
| 269 | s[Kind.assign] = '=' |
| 270 | s[Kind.decl_assign] = ':=' |
| 271 | s[Kind.plus_assign] = '+=' |
| 272 | s[Kind.minus_assign] = '-=' |
| 273 | s[Kind.mult_assign] = '*=' |
| 274 | s[Kind.power_assign] = '**=' |
| 275 | s[Kind.div_assign] = '/=' |
| 276 | s[Kind.xor_assign] = '^=' |
| 277 | s[Kind.mod_assign] = '%=' |
| 278 | s[Kind.or_assign] = '|=' |
| 279 | s[Kind.and_assign] = '&=' |
| 280 | s[Kind.right_shift_assign] = '>>=' |
| 281 | s[Kind.unsigned_right_shift_assign] = '>>>=' |
| 282 | s[Kind.left_shift_assign] = '<<=' |
| 283 | s[Kind.boolean_or_assign] = '||=' |
| 284 | s[Kind.boolean_and_assign] = '&&=' |
| 285 | s[Kind.lcbr] = '{' |
| 286 | s[Kind.rcbr] = '}' |
| 287 | s[Kind.lpar] = '(' |
| 288 | s[Kind.rpar] = ')' |
| 289 | s[Kind.lsbr] = '[' |
| 290 | s[Kind.nilsbr] = '#[' |
| 291 | s[Kind.rsbr] = ']' |
| 292 | s[Kind.eq] = '==' |
| 293 | s[Kind.ne] = '!=' |
| 294 | s[Kind.gt] = '>' |
| 295 | s[Kind.lt] = '<' |
| 296 | s[Kind.ge] = '>=' |
| 297 | s[Kind.le] = '<=' |
| 298 | s[Kind.question] = '?' |
| 299 | s[Kind.left_shift] = '<<' |
| 300 | s[Kind.right_shift] = '>>' |
| 301 | s[Kind.unsigned_right_shift] = '>>>' |
| 302 | s[Kind.comment] = 'comment' |
| 303 | s[Kind.nl] = 'NLL' |
| 304 | s[Kind.dollar] = '$' |
| 305 | s[Kind.at] = '@' |
| 306 | s[Kind.str_dollar] = '$2' |
| 307 | s[Kind.key_assert] = 'assert' |
| 308 | s[Kind.key_struct] = 'struct' |
| 309 | s[Kind.key_if] = 'if' |
| 310 | // s[Kind.key_it] = 'it' |
| 311 | s[Kind.key_else] = 'else' |
| 312 | s[Kind.key_asm] = 'asm' |
| 313 | s[Kind.key_return] = 'return' |
| 314 | s[Kind.key_module] = 'module' |
| 315 | s[Kind.key_sizeof] = 'sizeof' |
| 316 | s[Kind.key_isreftype] = 'isreftype' |
| 317 | s[Kind.key_likely] = '_likely_' |
| 318 | s[Kind.key_unlikely] = '_unlikely_' |
| 319 | s[Kind.key_go] = 'go' |
| 320 | s[Kind.key_goto] = 'goto' |
| 321 | s[Kind.key_const] = 'const' |
| 322 | s[Kind.key_mut] = 'mut' |
| 323 | s[Kind.key_shared] = 'shared' |
| 324 | s[Kind.key_lock] = 'lock' |
| 325 | s[Kind.key_rlock] = 'rlock' |
| 326 | s[Kind.key_type] = 'type' |
| 327 | s[Kind.key_for] = 'for' |
| 328 | s[Kind.key_fn] = 'fn' |
| 329 | s[Kind.key_true] = 'true' |
| 330 | s[Kind.key_false] = 'false' |
| 331 | s[Kind.key_continue] = 'continue' |
| 332 | s[Kind.key_break] = 'break' |
| 333 | s[Kind.key_import] = 'import' |
| 334 | s[Kind.key_unsafe] = 'unsafe' |
| 335 | s[Kind.key_typeof] = 'typeof' |
| 336 | s[Kind.key_dump] = 'dump' |
| 337 | s[Kind.key_enum] = 'enum' |
| 338 | s[Kind.key_interface] = 'interface' |
| 339 | s[Kind.key_pub] = 'pub' |
| 340 | s[Kind.key_in] = 'in' |
| 341 | s[Kind.key_atomic] = 'atomic' |
| 342 | s[Kind.key_orelse] = 'or' |
| 343 | s[Kind.key_global] = '__global' |
| 344 | s[Kind.key_union] = 'union' |
| 345 | s[Kind.key_static] = 'static' |
| 346 | s[Kind.key_volatile] = 'volatile' |
| 347 | s[Kind.key_as] = 'as' |
| 348 | s[Kind.key_defer] = 'defer' |
| 349 | s[Kind.key_match] = 'match' |
| 350 | s[Kind.key_select] = 'select' |
| 351 | s[Kind.key_like] = 'like' |
| 352 | s[Kind.key_ilike] = 'ilike' |
| 353 | s[Kind.key_none] = 'none' |
| 354 | s[Kind.key_nil] = 'nil' |
| 355 | s[Kind.key_offsetof] = '__offsetof' |
| 356 | s[Kind.key_is] = 'is' |
| 357 | s[Kind.key_spawn] = 'spawn' |
| 358 | s[Kind.key_implements] = 'implements' |
| 359 | // The following kinds are not for tokens returned by the V scanner. |
| 360 | // They are used just for organisation/ease of checking: |
| 361 | s[Kind.keyword_beg] = 'keyword_beg' |
| 362 | s[Kind.keyword_end] = 'keyword_end' |
| 363 | s[Kind.str_inter] = 'str_inter' |
| 364 | $if debug_build_token_str ? { |
| 365 | for k, v in s { |
| 366 | if v == '' { |
| 367 | eprintln('>>> ${@MOD}.${@METHOD} missing k: ${k} | .${kind_to_string(unsafe { Kind(k) })}') |
| 368 | } |
| 369 | } |
| 370 | } |
| 371 | return s |
| 372 | } |
| 373 | |
| 374 | @[inline] |
| 375 | pub fn is_key(key string) bool { |
| 376 | return int(keywords[key]) > 0 |
| 377 | } |
| 378 | |
| 379 | @[inline] |
| 380 | pub fn is_decl(t Kind) bool { |
| 381 | return t in [.key_enum, .key_interface, .key_fn, .key_struct, .key_type, .key_const, .key_pub, |
| 382 | .eof] |
| 383 | } |
| 384 | |
| 385 | @[inline] |
| 386 | pub fn (t Kind) is_assign() bool { |
| 387 | return t in assign_tokens |
| 388 | } |
| 389 | |
| 390 | // note: used for some code generation, so no quoting |
| 391 | @[direct_array_access; inline] |
| 392 | pub fn (t Kind) str() string { |
| 393 | idx := int(t) |
| 394 | if idx < 0 || token_str.len <= idx { |
| 395 | return 'unknown' |
| 396 | } |
| 397 | return token_str[idx] |
| 398 | } |
| 399 | |
| 400 | @[inline] |
| 401 | pub fn (t Token) is_next_to(pre_token Token) bool { |
| 402 | return t.pos - pre_token.pos == pre_token.len |
| 403 | } |
| 404 | |
| 405 | @[inline] |
| 406 | pub fn (t Token) is_key() bool { |
| 407 | return int(t.kind) > int(Kind.keyword_beg) && int(t.kind) < int(Kind.keyword_end) |
| 408 | } |
| 409 | |
| 410 | @[direct_array_access] |
| 411 | pub fn (t Token) str() string { |
| 412 | mut s := t.kind.str() |
| 413 | if s.len == 0 { |
| 414 | eprintln('missing token kind string') |
| 415 | } else if !s[0].is_letter() { |
| 416 | // punctuation, operators |
| 417 | return 'token `${s}`' |
| 418 | } |
| 419 | if is_key(t.lit) { |
| 420 | s = 'keyword' |
| 421 | } |
| 422 | if t.lit != '' { |
| 423 | // string contents etc |
| 424 | s += ' `${t.lit}`' |
| 425 | } |
| 426 | return s |
| 427 | } |
| 428 | |
| 429 | pub fn (t Token) debug() string { |
| 430 | ks := kind_to_string(t.kind) |
| 431 | s := if t.lit == '' { t.kind.str() } else { t.lit } |
| 432 | return 'tok: .${ks:-12} | lit: `${s}`' |
| 433 | } |
| 434 | |
| 435 | // Representation of highest and lowest precedence |
| 436 | pub enum Precedence { |
| 437 | lowest |
| 438 | cond // OR or AND |
| 439 | in_as |
| 440 | assign // = |
| 441 | eq // == or != |
| 442 | // less_greater // > or < |
| 443 | sum // + - | ^ |
| 444 | product // * / << >> >>> & |
| 445 | // mod // % |
| 446 | prefix // -X or !X; TODO: seems unused |
| 447 | power // ** |
| 448 | postfix // ++ or -- |
| 449 | call // func(X) or foo.method(X) |
| 450 | index // array[index], map[key] |
| 451 | highest |
| 452 | } |
| 453 | |
| 454 | @[direct_array_access] |
| 455 | pub fn build_precedences() []Precedence { |
| 456 | mut p := []Precedence{len: int(Kind._end_), init: Precedence.lowest} |
| 457 | p[Kind.lsbr] = .index |
| 458 | p[Kind.nilsbr] = .index |
| 459 | p[Kind.dot] = .call |
| 460 | // `++` | `--` | `?` |
| 461 | p[Kind.inc] = .postfix |
| 462 | p[Kind.dec] = .postfix |
| 463 | p[Kind.question] = .postfix |
| 464 | // `*` | `/` | `%` | `<<` | `>>` | `>>>` | `&` |
| 465 | p[Kind.mul] = .product |
| 466 | p[Kind.div] = .product |
| 467 | p[Kind.mod] = .product |
| 468 | p[Kind.left_shift] = .product |
| 469 | p[Kind.right_shift] = .product |
| 470 | p[Kind.unsigned_right_shift] = .product |
| 471 | p[Kind.amp] = .product |
| 472 | p[Kind.arrow] = .product |
| 473 | p[Kind.power] = .power |
| 474 | // `+` | `-` | `|` | `^` |
| 475 | p[Kind.plus] = .sum |
| 476 | p[Kind.minus] = .sum |
| 477 | p[Kind.pipe] = .sum |
| 478 | p[Kind.xor] = .sum |
| 479 | // `==` | `!=` | `<` | `<=` | `>` | `>=` | `like` |
| 480 | p[Kind.eq] = .eq |
| 481 | p[Kind.ne] = .eq |
| 482 | p[Kind.lt] = .eq |
| 483 | p[Kind.le] = .eq |
| 484 | p[Kind.gt] = .eq |
| 485 | p[Kind.ge] = .eq |
| 486 | p[Kind.key_like] = .eq |
| 487 | p[Kind.key_ilike] = .eq |
| 488 | // `=` | `+=` | ... |
| 489 | p[Kind.assign] = .assign |
| 490 | p[Kind.plus_assign] = .assign |
| 491 | p[Kind.minus_assign] = .assign |
| 492 | p[Kind.power_assign] = .assign |
| 493 | p[Kind.div_assign] = .assign |
| 494 | p[Kind.mod_assign] = .assign |
| 495 | p[Kind.or_assign] = .assign |
| 496 | p[Kind.and_assign] = .assign |
| 497 | // <<= | *= | ... |
| 498 | p[Kind.left_shift_assign] = .assign |
| 499 | p[Kind.right_shift_assign] = .assign |
| 500 | p[Kind.unsigned_right_shift_assign] = .assign |
| 501 | p[Kind.mult_assign] = .assign |
| 502 | p[Kind.xor_assign] = .assign |
| 503 | p[Kind.boolean_or_assign] = .assign |
| 504 | p[Kind.boolean_and_assign] = .assign |
| 505 | p[Kind.key_in] = .in_as |
| 506 | p[Kind.not_in] = .in_as |
| 507 | p[Kind.key_as] = .in_as |
| 508 | p[Kind.key_is] = .in_as |
| 509 | p[Kind.not_is] = .in_as |
| 510 | p[Kind.logical_or] = .cond |
| 511 | p[Kind.and] = .cond |
| 512 | return p |
| 513 | } |
| 514 | |
| 515 | const precedences = build_precedences() |
| 516 | |
| 517 | // precedence returns a tokens precedence if defined, otherwise 0 |
| 518 | @[direct_array_access; inline] |
| 519 | pub fn (tok Token) precedence() int { |
| 520 | return int(precedences[tok.kind]) |
| 521 | } |
| 522 | |
| 523 | // precedence returns the precedence of the given token `kind` if defined, otherwise 0 |
| 524 | @[direct_array_access; inline] |
| 525 | pub fn (kind Kind) precedence() int { |
| 526 | return int(precedences[kind]) |
| 527 | } |
| 528 | |
| 529 | // is_scalar returns true if the token is a scalar |
| 530 | @[inline] |
| 531 | pub fn (tok Token) is_scalar() bool { |
| 532 | return tok.kind in [.number, .string] |
| 533 | } |
| 534 | |
| 535 | // is_unary returns true if the token can be in a unary expression |
| 536 | @[inline] |
| 537 | pub fn (tok Token) is_unary() bool { |
| 538 | // `+` | `-` | `!` | `~` | `*` | `&` | `<-` |
| 539 | return tok.kind in [.plus, .minus, .not, .bit_not, .mul, .amp, .arrow] |
| 540 | } |
| 541 | |
| 542 | @[inline] |
| 543 | pub fn (tok Kind) is_relational() bool { |
| 544 | // `<` | `<=` | `>` | `>=` | `==` | `!=` |
| 545 | return tok in [.lt, .le, .gt, .ge, .eq, .ne] |
| 546 | } |
| 547 | |
| 548 | @[inline] |
| 549 | pub fn (k Kind) is_start_of_type() bool { |
| 550 | return k in [.name, .lpar, .amp, .lsbr, .question, .key_shared, .not] |
| 551 | } |
| 552 | |
| 553 | @[inline] |
| 554 | pub fn (kind Kind) is_prefix() bool { |
| 555 | return kind in [.minus, .amp, .mul, .not, .bit_not] |
| 556 | } |
| 557 | |
| 558 | @[inline] |
| 559 | pub fn (kind Kind) is_infix() bool { |
| 560 | return kind in [.plus, .minus, .mod, .mul, .power, .div, .eq, .ne, .gt, .lt, .key_in, .key_as, |
| 561 | .ge, .le, .logical_or, .xor, .not_in, .key_is, .not_is, .and, .dot, .pipe, .amp, .left_shift, |
| 562 | .right_shift, .unsigned_right_shift, .arrow, .key_like, .key_ilike] |
| 563 | } |
| 564 | |
| 565 | @[inline] |
| 566 | pub fn (kind Kind) is_postfix() bool { |
| 567 | return kind in [.inc, .dec, .question] |
| 568 | } |
| 569 | |
| 570 | pub fn kind_to_string(k Kind) string { |
| 571 | return match k { |
| 572 | .unknown { 'unknown' } |
| 573 | .eof { 'eof' } |
| 574 | .name { 'name' } |
| 575 | .number { 'number' } |
| 576 | .string { 'string' } |
| 577 | .str_inter { 'str_inter' } |
| 578 | .chartoken { 'chartoken' } |
| 579 | .plus { 'plus' } |
| 580 | .minus { 'minus' } |
| 581 | .mul { 'mul' } |
| 582 | .power { 'power' } |
| 583 | .div { 'div' } |
| 584 | .mod { 'mod' } |
| 585 | .xor { 'xor' } |
| 586 | .pipe { 'pipe' } |
| 587 | .inc { 'inc' } |
| 588 | .dec { 'dec' } |
| 589 | .and { 'and' } |
| 590 | .logical_or { 'logical_or' } |
| 591 | .not { 'not' } |
| 592 | .bit_not { 'bit_not' } |
| 593 | .question { 'question' } |
| 594 | .comma { 'comma' } |
| 595 | .semicolon { 'semicolon' } |
| 596 | .colon { 'colon' } |
| 597 | .arrow { 'arrow' } |
| 598 | .amp { 'amp' } |
| 599 | .hash { 'hash' } |
| 600 | .dollar { 'dollar' } |
| 601 | .at { 'at' } |
| 602 | .str_dollar { 'str_dollar' } |
| 603 | .left_shift { 'left_shift' } |
| 604 | .right_shift { 'right_shift' } |
| 605 | .unsigned_right_shift { 'unsigned_right_shift' } |
| 606 | .not_in { 'not_in' } |
| 607 | .not_is { 'not_is' } |
| 608 | .assign { 'assign' } |
| 609 | .decl_assign { 'decl_assign' } |
| 610 | .plus_assign { 'plus_assign' } |
| 611 | .minus_assign { 'minus_assign' } |
| 612 | .div_assign { 'div_assign' } |
| 613 | .mult_assign { 'mult_assign' } |
| 614 | .power_assign { 'power_assign' } |
| 615 | .xor_assign { 'xor_assign' } |
| 616 | .mod_assign { 'mod_assign' } |
| 617 | .or_assign { 'or_assign' } |
| 618 | .and_assign { 'and_assign' } |
| 619 | .right_shift_assign { 'right_shift_assign' } |
| 620 | .left_shift_assign { 'left_shift_assign' } |
| 621 | .unsigned_right_shift_assign { 'unsigned_right_shift_assign' } |
| 622 | .boolean_and_assign { 'boolean_and_assign' } |
| 623 | .boolean_or_assign { 'boolean_or_assign' } |
| 624 | .lcbr { 'lcbr' } |
| 625 | .rcbr { 'rcbr' } |
| 626 | .lpar { 'lpar' } |
| 627 | .rpar { 'rpar' } |
| 628 | .lsbr { 'lsbr' } |
| 629 | .nilsbr { 'nilsbr' } |
| 630 | .rsbr { 'rsbr' } |
| 631 | .eq { 'eq' } |
| 632 | .ne { 'ne' } |
| 633 | .gt { 'gt' } |
| 634 | .lt { 'lt' } |
| 635 | .ge { 'ge' } |
| 636 | .le { 'le' } |
| 637 | .comment { 'comment' } |
| 638 | .nl { 'nl' } |
| 639 | .dot { 'dot' } |
| 640 | .dotdot { 'dotdot' } |
| 641 | .ellipsis { 'ellipsis' } |
| 642 | .keyword_beg { 'keyword_beg' } |
| 643 | .key_as { 'key_as' } |
| 644 | .key_asm { 'key_asm' } |
| 645 | .key_assert { 'key_assert' } |
| 646 | .key_atomic { 'key_atomic' } |
| 647 | .key_break { 'key_break' } |
| 648 | .key_const { 'key_const' } |
| 649 | .key_continue { 'key_continue' } |
| 650 | .key_defer { 'key_defer' } |
| 651 | .key_else { 'key_else' } |
| 652 | .key_enum { 'key_enum' } |
| 653 | .key_false { 'key_false' } |
| 654 | .key_for { 'key_for' } |
| 655 | .key_fn { 'key_fn' } |
| 656 | .key_global { 'key_global' } |
| 657 | .key_go { 'key_go' } |
| 658 | .key_goto { 'key_goto' } |
| 659 | .key_if { 'key_if' } |
| 660 | .key_import { 'key_import' } |
| 661 | .key_in { 'key_in' } |
| 662 | .key_interface { 'key_interface' } |
| 663 | .key_is { 'key_is' } |
| 664 | .key_match { 'key_match' } |
| 665 | .key_module { 'key_module' } |
| 666 | .key_mut { 'key_mut' } |
| 667 | .key_shared { 'key_shared' } |
| 668 | .key_lock { 'key_lock' } |
| 669 | .key_rlock { 'key_rlock' } |
| 670 | .key_none { 'key_none' } |
| 671 | .key_return { 'key_return' } |
| 672 | .key_select { 'key_select' } |
| 673 | .key_like { 'key_like' } |
| 674 | .key_ilike { 'key_ilike' } |
| 675 | .key_sizeof { 'key_sizeof' } |
| 676 | .key_isreftype { 'key_isreftype' } |
| 677 | .key_likely { 'key_likely' } |
| 678 | .key_unlikely { 'key_unlikely' } |
| 679 | .key_offsetof { 'key_offsetof' } |
| 680 | .key_struct { 'key_struct' } |
| 681 | .key_true { 'key_true' } |
| 682 | .key_type { 'key_type' } |
| 683 | .key_typeof { 'key_typeof' } |
| 684 | .key_dump { 'key_dump' } |
| 685 | .key_orelse { 'key_orelse' } |
| 686 | .key_union { 'key_union' } |
| 687 | .key_pub { 'key_pub' } |
| 688 | .key_static { 'key_static' } |
| 689 | .key_volatile { 'key_volatile' } |
| 690 | .key_unsafe { 'key_unsafe' } |
| 691 | .key_spawn { 'key_spawn' } |
| 692 | .key_implements { 'key_implements' } |
| 693 | .keyword_end { 'keyword_end' } |
| 694 | ._end_ { '_end_' } |
| 695 | .key_nil { 'key_nil' } |
| 696 | } |
| 697 | } |
| 698 | |
| 699 | pub fn assign_op_to_infix_op(op Kind) Kind { |
| 700 | return match op { |
| 701 | .plus_assign { .plus } |
| 702 | .minus_assign { .minus } |
| 703 | .mult_assign { .mul } |
| 704 | .power_assign { .power } |
| 705 | .div_assign { .div } |
| 706 | .xor_assign { .xor } |
| 707 | .mod_assign { .mod } |
| 708 | .or_assign { .pipe } |
| 709 | .and_assign { .amp } |
| 710 | .right_shift_assign { .right_shift } |
| 711 | .unsigned_right_shift_assign { .unsigned_right_shift } |
| 712 | .left_shift_assign { .left_shift } |
| 713 | .boolean_and_assign { .and } |
| 714 | .boolean_or_assign { .logical_or } |
| 715 | else { ._end_ } |
| 716 | } |
| 717 | } |
| 718 | |