v2 / vlib / v / ast / ast.v
3369 lines · 3154 sloc · 82.46 KB · d5578efae67ef01ab3a63866d429b7dacf6c237d
Raw
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@[has_globals]
5module ast
6
7import v.token
8import v.errors
9import v.util
10import v.pref
11import sync.stdatomic
12
13// V type names that cannot be used as global var name
14pub const global_reserved_type_names = ['byte', 'bool', 'char', 'i8', 'i16', 'i32', 'int', 'i64',
15 'u8', 'u16', 'u32', 'u64', 'f32', 'f64', 'map', 'string', 'rune', 'usize', 'isize', 'voidptr',
16 'thread', 'array']
17
18pub const result_name = '_result'
19pub const option_name = '_option'
20
21// V builtin types defined on .v files
22pub const builtins = ['string', 'array', 'DenseArray', 'map', 'Error', 'IError', 'SliceIndex',
23 option_name, result_name]
24
25pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
26
27pub const int_type_name = $if new_int ? && x64 { 'vint_t' } $else { 'int' }
28
29pub type Expr = NodeError
30 | AnonFn
31 | ArrayDecompose
32 | ArrayInit
33 | AsCast
34 | Assoc
35 | AtExpr
36 | BoolLiteral
37 | CTempVar
38 | CallExpr
39 | CastExpr
40 | ChanInit
41 | CharLiteral
42 | Comment
43 | ComptimeCall
44 | ComptimeSelector
45 | ComptimeType
46 | ConcatExpr
47 | DumpExpr
48 | EmptyExpr
49 | EnumVal
50 | FloatLiteral
51 | GoExpr
52 | Ident
53 | IfExpr
54 | IfGuardExpr
55 | IndexExpr
56 | InfixExpr
57 | IntegerLiteral
58 | IsRefType
59 | LambdaExpr
60 | Likely
61 | LockExpr
62 | MapInit
63 | MatchExpr
64 | Nil
65 | None
66 | OffsetOf
67 | OrExpr
68 | ParExpr
69 | PostfixExpr
70 | PrefixExpr
71 | RangeExpr
72 | SelectExpr
73 | SelectorExpr
74 | SizeOf
75 | SpawnExpr
76 | SqlExpr
77 | SqlQueryDataExpr
78 | StringInterLiteral
79 | StringLiteral
80 | StructInit
81 | TypeNode
82 | TypeOf
83 | UnsafeExpr
84
85pub type Stmt = AsmStmt
86 | AssertStmt
87 | AssignStmt
88 | Block
89 | BranchStmt
90 | ComptimeFor
91 | ConstDecl
92 | DebuggerStmt
93 | DeferStmt
94 | EmptyStmt
95 | EnumDecl
96 | ExprStmt
97 | FnDecl
98 | ForCStmt
99 | ForInStmt
100 | ForStmt
101 | GlobalDecl
102 | GotoLabel
103 | GotoStmt
104 | HashStmt
105 | Import
106 | InterfaceDecl
107 | Module
108 | NodeError
109 | Return
110 | SemicolonStmt
111 | SqlStmt
112 | StructDecl
113 | TypeDecl
114
115pub type HashStmtNode = IfExpr | HashStmt
116
117pub struct EmptyScopeObject {
118pub mut:
119 name string
120 typ Type
121}
122
123pub type ScopeObject = EmptyScopeObject | AsmRegister | ConstField | GlobalField | Var
124
125// TODO: replace Param
126pub type Node = CallArg
127 | ConstField
128 | EmptyNode
129 | EnumField
130 | Expr
131 | File
132 | GlobalField
133 | IfBranch
134 | MatchBranch
135 | NodeError
136 | Param
137 | ScopeObject
138 | SelectBranch
139 | Stmt
140 | StructField
141 | StructInitField
142
143pub struct TypeNode {
144pub:
145 pos token.Pos
146pub mut:
147 typ Type
148 stmt Stmt = empty_stmt // for anon struct
149 end_comments []Comment // comments that after current type node
150}
151
152pub enum ComptimeTypeKind {
153 unknown
154 map
155 int
156 float
157 struct
158 iface
159 array
160 array_fixed
161 array_dynamic
162 sum_type
163 enum
164 alias
165 function
166 option
167 shared
168 string
169 pointer
170 voidptr
171}
172
173pub struct ComptimeType {
174pub:
175 kind ComptimeTypeKind
176 pos token.Pos
177}
178
179pub fn (cty ComptimeType) str() string {
180 return match cty.kind {
181 .unknown { '\$unknown' }
182 .map { '\$map' }
183 .int { '\$int' }
184 .float { '\$float' }
185 .struct { '\$struct' }
186 .iface { '\$interface' }
187 .array { '\$array' }
188 .array_dynamic { '\$array_dynamic' }
189 .array_fixed { '\$array_fixed' }
190 .sum_type { '\$sumtype' }
191 .enum { '\$enum' }
192 .alias { '\$alias' }
193 .function { '\$function' }
194 .option { '\$option' }
195 .shared { '\$shared' }
196 .string { '\$string' }
197 .pointer { '\$pointer' }
198 .voidptr { '\$voidptr' }
199 }
200}
201
202pub type EmptyExpr = u8
203
204pub struct EmptyStmt {
205pub:
206 pos token.Pos
207}
208
209pub struct EmptyNode {
210pub:
211 pos token.Pos
212}
213
214pub const empty_expr = Expr(EmptyExpr(0))
215pub const empty_stmt = Stmt(EmptyStmt{})
216pub const empty_node = Node(EmptyNode{})
217pub const empty_scope_object = ScopeObject(EmptyScopeObject{'empty_scope_object', 0})
218pub const empty_comptime_const_value = ComptTimeConstValue(EmptyExpr(0))
219
220// `{stmts}` or `unsafe {stmts}`
221pub struct Block {
222pub:
223 is_unsafe bool
224 pos token.Pos
225 scope &Scope
226pub mut:
227 stmts []Stmt
228}
229
230// | IncDecStmt k
231// Stand-alone expression in a statement list.
232pub struct ExprStmt {
233pub:
234 pos token.Pos
235 comments []Comment
236pub mut:
237 expr Expr
238 is_expr bool
239 typ Type
240}
241
242pub struct IntegerLiteral {
243pub:
244 val string
245 pos token.Pos
246}
247
248pub struct FloatLiteral {
249pub:
250 val string
251 pos token.Pos
252}
253
254@[minify]
255pub struct StringLiteral {
256pub:
257 val string
258 is_raw bool
259 language Language
260 pos token.Pos
261}
262
263// 'name: ${name}'
264pub struct StringInterLiteral {
265pub:
266 vals []string
267 fwidths []int
268 precisions []int
269 pluss []bool
270 fills []bool
271 fmt_poss []token.Pos
272 pos token.Pos
273pub mut:
274 exprs []Expr
275 expr_types []Type
276 fwidth_exprs []Expr
277 precision_exprs []Expr
278 fmts []u8
279 need_fmts []bool // an explicit non-default fmt required, e.g. `x`
280}
281
282pub struct CharLiteral {
283pub:
284 val string
285 pos token.Pos
286}
287
288pub struct BoolLiteral {
289pub:
290 val bool
291 pos token.Pos
292}
293
294pub struct Nil {
295pub:
296 pos token.Pos
297}
298
299pub enum GenericKindField {
300 unknown
301 name
302 typ
303 unaliased_typ
304 indirections
305}
306
307// `foo.bar`
308@[minify]
309pub struct SelectorExpr {
310pub:
311 pos token.Pos
312 field_name string
313 is_mut bool // is used for the case `if mut ident.selector is MyType {`, it indicates if the root ident is mutable
314 mut_pos token.Pos
315 next_token token.Kind
316pub mut:
317 expr Expr // expr.field_name
318 expr_type Type // type of `Foo` in `Foo.bar`
319 typ Type // type of the entire thing (`Foo.bar`)
320 name_type Type // T in `T.name` or typeof in `typeof(expr).name`
321 or_block OrExpr
322 gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
323 scope &Scope = unsafe { nil }
324 from_embed_types []Type // holds the type of the embed that the method is called from
325 generic_from_embed_types [][]Type // holds the types of the embeds for each generic instance when the same generic method is called.
326 has_hidden_receiver bool
327 is_field_typ bool // var.typ for comptime $for var
328}
329
330// root_ident returns the origin ident where the selector started.
331pub fn (e &SelectorExpr) root_ident() ?Ident {
332 mut root := e.expr
333 for {
334 mut next_root := Expr(EmptyExpr{})
335 if mut root is SelectorExpr {
336 next_root = root.expr
337 } else {
338 break
339 }
340 root = next_root
341 }
342 if mut root is Ident {
343 return root
344 }
345
346 return none
347}
348
349// module declaration
350pub struct Module {
351pub:
352 name string // encoding.base64
353 short_name string // base64
354 attrs []Attr
355 pos token.Pos
356 name_pos token.Pos // `name` in import name
357 is_skipped bool // module main can be skipped in single file programs
358}
359
360pub struct SemicolonStmt {
361pub:
362 pos token.Pos
363}
364
365@[minify]
366pub struct StructField {
367pub:
368 pos token.Pos
369 type_pos token.Pos
370 option_pos token.Pos
371 pre_comments []Comment
372 comments []Comment
373 i int
374 has_default_expr bool
375 has_prev_newline bool
376 has_break_line bool
377 is_pub bool
378 default_val string
379 is_mut bool
380 is_global bool
381 is_volatile bool
382 is_deprecated bool
383 is_embed bool
384pub mut:
385 attrs []Attr
386 next_comments []Comment
387 is_recursive bool
388 is_part_of_union bool
389 container_typ Type
390 default_expr Expr
391 default_expr_typ Type
392 name string
393 typ Type
394 unaliased_typ Type
395 anon_struct_decl StructDecl // only if the field is an anonymous struct
396}
397
398pub fn (f &StructField) equals(o &StructField) bool {
399 // TODO: f.is_mut == o.is_mut was removed here to allow read only access
400 // to (mut/not mut), but otherwise equal fields; some other new checks are needed:
401 // - if node is declared mut, and we mutate node.stmts, all stmts fields must be mutable
402 // - same goes for pub and global, if we call the field from another module
403 return f.name == o.name && f.typ == o.typ && f.is_pub == o.is_pub && f.is_global == o.is_global
404}
405
406// const field in const declaration group
407pub struct ConstField {
408pub:
409 mod string
410 name string
411 is_pub bool
412 is_markused bool // an explicit `@[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
413 is_exported bool // an explicit `@[export]` tag; the const will NOT be removed by `-skip-unused`, no matter what
414 pos token.Pos
415 attrs []Attr // same value as `attrs` of the ConstDecl to which it belongs
416 is_virtual_c bool // `const C.MY_CONST u8`
417pub mut:
418 expr Expr // the value expr of field; everything after `=`
419 typ Type // the type of the const field, it can be any type in V
420 comments []Comment // comments before current const field
421 end_comments []Comment // comments that after const field
422 // the comptime_expr_value field is filled by the checker, when it has enough
423 // info to evaluate the constant at compile time
424 comptime_expr_value ComptTimeConstValue = empty_comptime_const_value
425}
426
427// const declaration
428@[minify]
429pub struct ConstDecl {
430pub:
431 is_pub bool
432 pos token.Pos
433 attrs []Attr // tags like `@[markused]`, valid for all the consts in the list
434pub mut:
435 fields []ConstField // all the const fields in the `const (...)` block
436 end_comments []Comment // comments that after last const field
437 is_block bool // const() block
438}
439
440@[minify]
441pub struct StructDecl {
442pub:
443 pos token.Pos
444 name string
445 scoped_name string
446 generic_types []Type
447 is_pub bool
448 // _pos fields for vfmt
449 mut_pos int = -1 // mut:
450 pub_pos int = -1 // pub:
451 pub_mut_pos int = -1 // pub mut:
452 global_pos int = -1 // __global:
453 module_pos int = -1 // module:
454 is_union bool
455 is_option bool
456 is_aligned bool
457 attrs []Attr
458 pre_comments []Comment
459 end_comments []Comment
460 embeds []Embed
461 is_implements bool
462 implements_types []TypeNode
463pub mut:
464 language Language
465 fields []StructField
466 idx int
467}
468
469pub struct Embed {
470pub:
471 typ Type
472 pos token.Pos
473 comments []Comment
474}
475
476pub struct InterfaceEmbedding {
477pub:
478 name string
479 typ Type
480 pos token.Pos
481 comments []Comment
482}
483
484@[minify]
485pub struct InterfaceDecl {
486pub:
487 name string
488 typ Type
489 name_pos token.Pos
490 language Language
491 field_names []string
492 is_pub bool
493 mut_pos int // mut:
494 pos token.Pos
495 pre_comments []Comment
496 generic_types []Type
497 attrs []Attr
498pub mut:
499 methods []FnDecl
500 fields []StructField
501 embeds []InterfaceEmbedding
502 are_embeds_expanded bool
503}
504
505// `field1: val1`
506pub struct StructInitField {
507pub:
508 pos token.Pos
509 name_pos token.Pos
510 pre_comments []Comment
511 end_comments []Comment
512 next_comments []Comment
513 has_prev_newline bool
514 has_break_line bool
515 is_embed bool
516pub mut:
517 expr Expr // `val1`
518 name string // 'field1'
519 typ Type // the type of this field
520 expected_type Type
521 parent_type Type
522}
523
524// `s := Foo{
525// ...a
526// field1: 'hello'
527// }`
528@[minify]
529pub struct StructInit {
530pub:
531 pos token.Pos
532 name_pos token.Pos
533 no_keys bool // `Foo{val1, val2}`
534 is_short_syntax bool // `foo(field1: val1, field2: val2)`
535 is_anon bool // `x: struct{ foo: bar }`
536pub mut:
537 unresolved bool
538 pre_comments []Comment
539 typ_str string // 'Foo'
540 typ Type // the type of this struct
541 typ_expr Expr = EmptyExpr{} // `typeof(x).idx` in `typeof(x).idx{}`
542 generic_typ Type // original generic struct type; reused for later concrete instantiations
543 update_expr Expr // `a` in `...a`
544 update_expr_type Type
545 update_expr_pos token.Pos
546 update_expr_comments []Comment
547 is_update_embed bool
548 has_update_expr bool // has `...a`
549 init_fields []StructInitField
550 generic_types []Type
551 language Language
552}
553
554pub enum StructInitKind {
555 normal
556 short_syntax
557 anon
558}
559
560// import statement
561pub struct Import {
562pub:
563 source_name string // The original name in the source, `import abc.def` -> 'abc.def', *no matter* how the module is resolved
564
565 mod string // the module name of the import
566 alias string // the `x` in `import xxx as x`
567 pos token.Pos
568 mod_pos token.Pos
569 alias_pos token.Pos
570 syms_pos token.Pos
571pub mut:
572 syms []ImportSymbol // the list of symbols in `import {symbol1, symbol2}`
573 comments []Comment
574 next_comments []Comment
575}
576
577// import symbol,for import {symbol} syntax
578pub struct ImportSymbol {
579pub:
580 pos token.Pos
581 name string
582}
583
584// anonymous function
585pub struct AnonFn {
586pub mut:
587 decl FnDecl
588 inherited_vars []Param // note: closures have inherited_vars.len > 0
589 has_ct_var bool // has $for var as inherited var
590 typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
591 has_gen map[string]bool // a map of the names of all generic anon functions, generated from it
592}
593
594// function or method declaration
595@[minify]
596pub struct FnDecl {
597pub:
598 name string // 'math.bits.normalize'
599 short_name string // 'normalize'
600 mod string // 'math.bits'
601 kind CallKind
602 is_deprecated bool
603 is_pub bool
604 is_c_variadic bool
605 is_c_extern bool
606 is_variadic bool
607 is_anon bool
608 is_weak bool
609 is_noreturn bool // true, when @[noreturn] is used on a fn
610 is_manualfree bool // true, when @[manualfree] is used on a fn
611 is_main bool // true for `fn main()`
612 is_test bool // true for `fn test_abcde() {}`, false for `fn test_abc(x int) {}`, or for fns that do not start with test_
613 is_conditional bool // true for `@[if abc] fn abc(){}`
614 is_exported bool // true for `@[export: 'exact_C_name']`
615 is_keep_alive bool // passed memory must not be freed (by GC) before function returns
616 is_unsafe bool // true, when @[unsafe] is used on a fn
617 is_must_use bool // true, when @[must_use] is used on a fn. Calls to such functions, that ignore the return value, will cause warnings.
618 is_markused bool // true, when an explicit `@[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
619 is_ignore_overflow bool // true, when an explicit `@[ignore_overflow]` tag was put on a fn. `-check-overflow` will not generate checks for arithmetic done in that fn.
620 is_file_translated bool // true, when the file it resides in is `@[translated]`
621 is_closure bool // true, for actual closures like `fn [inherited] () {}` . It is false for normal anonymous functions, and for named functions/methods too.
622 receiver StructField // TODO: this is not a struct field
623 receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position
624 is_method bool
625 is_static_type_method bool // true for `fn Foo.bar() {}`
626 static_type_pos token.Pos // `Foo` in `fn Foo.bar() {}`
627 method_type_pos token.Pos // `User` in ` fn (u User)` position
628 method_idx int
629 rec_mut bool // is receiver mutable
630 has_prev_newline bool
631 has_break_line bool
632 rec_share ShareType
633 language Language // V, C, JS
634 file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc.
635 no_body bool // just a definition `fn C.malloc()`
636 is_builtin bool // this function is defined in builtin/strconv
637 name_pos token.Pos
638 body_pos token.Pos // function bodys position
639 file string
640 generic_names []string
641 is_direct_arr bool // @[direct_array_access] was used; a[i] inside such a fn, will *not* do array index bounds checks.
642 attrs []Attr
643 ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
644pub mut:
645 idx int // index in an external container; can be used to refer to the function in a more efficient way, just by its integer index
646 params []Param
647 stmts []Stmt
648 defer_stmts []DeferStmt
649 trace_fns map[string]FnTrace
650 return_type Type
651 return_type_pos token.Pos // `string` in `fn (u User) name() string` position
652 has_return bool
653 should_be_skipped bool // true, when -skip-unused could not find any usages of that function, starting from main + other known used functions
654 ninstances int // 0 for generic functions with no concrete instances
655 has_await bool // 'true' if this function uses JS.await
656
657 comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl
658 end_comments []Comment // comments *after* header declarations. E.g.: `fn C.C_func(x int) int // Comment`
659 next_comments []Comment // comments that are one line after the decl; used for InterfaceDecl
660
661 source_file &File = unsafe { nil }
662 scope &Scope = unsafe { nil }
663 label_names []string
664 pos token.Pos // function declaration position
665 end_pos token.Pos // end position
666 //
667 is_expand_simple_interpolation bool // true, when @[expand_simple_interpolation] is used on a fn. It should have a single string argument.
668}
669
670pub fn (f &FnDecl) new_method_with_receiver_type(new_type_ Type) FnDecl {
671 new_type := if f.params[0].typ.is_ptr() && !new_type_.is_ptr() {
672 new_type_.ref()
673 } else {
674 new_type_
675 }
676 unsafe {
677 mut new_method := f
678 new_method.params = f.params.clone()
679 for i in 1 .. new_method.params.len {
680 if new_method.params[i].typ == new_method.params[0].typ {
681 new_method.params[i].typ = new_type
682 }
683 }
684 new_method.params[0].typ = new_type
685 return *new_method
686 }
687}
688
689@[minify]
690pub struct FnTrace {
691pub mut:
692 name string
693pub:
694 file string
695 line i64
696 return_type Type
697 func &Fn = unsafe { nil }
698 is_fn_var bool
699}
700
701@[minify]
702pub struct Fn {
703pub:
704 is_variadic bool
705 is_c_variadic bool
706 language Language
707 is_pub bool
708 is_ctor_new bool // `@[use_new] fn JS.Array.prototype.constructor()`
709 is_deprecated bool // `@[deprecated] fn abc(){}`
710 is_noreturn bool // `@[noreturn] fn abc(){}`
711 is_unsafe bool // `@[unsafe] fn abc(){}`
712 is_must_use bool // `@[must_use] fn abc(){}`
713 is_placeholder bool
714 is_main bool // `fn main(){}`
715 is_test bool // `fn test_abc(){}`
716 is_keep_alive bool // passed memory must not be freed (by GC) before function returns
717 is_method bool // true for `fn (x T) name()`, and for interface declarations (which are also for methods)
718 is_static_type_method bool // true for `fn Foo.bar() {}`
719 no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns.
720 is_file_translated bool // true, when the file it resides in is `@[translated]`
721 mod string
722 file string
723 file_mode Language
724 pos token.Pos
725 name_pos token.Pos
726 return_type_pos token.Pos
727pub mut:
728 return_type Type
729 receiver_type Type // != 0, when .is_method == true
730 name string
731 params []Param
732 source_fn voidptr // set in the checker, while processing fn declarations // TODO: get rid of voidptr
733 usages int
734 generic_names []string
735 dep_names []string // globals or consts dependent names
736 attrs []Attr // all fn attributes
737 is_conditional bool // true for `[if abc]fn(){}`
738 ctdefine_idx int // the index of the attribute, containing the compile time define [if mytag]
739 from_embedded_type Type // for interface only, fn from the embedded interface
740 //
741 is_expand_simple_interpolation bool // for tagging b.f(s string), which is then called with `b.f('some ${x} ${y}')`,
742 // when that call, should be expanded to `b.f('some '); b.f(x); b.f(' '); b.f(y);`
743 // Note: the same type, has to support also a .write_decimal(n i64) method.
744}
745
746fn (f &Fn) method_equals(o &Fn) bool {
747 return f.params[1..].equals(o.params[1..]) && f.return_type == o.return_type
748 && f.is_variadic == o.is_variadic && f.is_c_variadic == o.is_c_variadic
749 && f.language == o.language && f.generic_names == o.generic_names && f.is_pub == o.is_pub
750 && f.mod == o.mod && f.name == o.name
751}
752
753@[minify]
754pub struct Param {
755pub:
756 pos token.Pos
757 name string
758 is_mut bool
759 is_shared bool
760 is_atomic bool
761 type_pos token.Pos
762 is_hidden bool // interface first arg
763 on_newline bool // whether the argument starts on a new line
764pub mut:
765 typ Type
766 orig_typ Type // source type before mut lowering
767}
768
769pub fn (p &Param) specifier() string {
770 return match true {
771 p.is_shared { 'shared' }
772 p.is_atomic { 'atomic' }
773 p.is_mut { 'mut' }
774 else { '' }
775 }
776}
777
778pub fn (f &Fn) new_method_with_receiver_type(new_type_ Type) Fn {
779 new_type := if f.params[0].typ.is_ptr() && !new_type_.is_ptr() {
780 new_type_.ref()
781 } else {
782 new_type_
783 }
784 unsafe {
785 mut new_method := f
786 new_method.params = f.params.clone()
787 for i in 1 .. new_method.params.len {
788 if new_method.params[i].typ == new_method.params[0].typ {
789 new_method.params[i].typ = new_type
790 }
791 }
792 new_method.from_embedded_type = if f.from_embedded_type != 0 {
793 f.from_embedded_type
794 } else {
795 f.params[0].typ
796 }
797 new_method.params[0].typ = new_type
798
799 return *new_method
800 }
801}
802
803fn (p &Param) equals(o &Param) bool {
804 return p.name == o.name && p.is_mut == o.is_mut && p.typ == o.typ && p.is_hidden == o.is_hidden
805}
806
807fn (p []Param) equals(o []Param) bool {
808 if p.len != o.len {
809 return false
810 }
811 for i in 0 .. p.len {
812 if !p[i].equals(o[i]) {
813 return false
814 }
815 }
816 return true
817}
818
819// break, continue
820@[minify]
821pub struct BranchStmt {
822pub:
823 kind token.Kind
824 label string
825 scope &Scope
826 pos token.Pos
827}
828
829pub enum CallKind {
830 unknown
831 str
832 wait
833 free
834 try_push
835 try_pop
836 keys
837 values
838 slice
839 map
840 insert
841 prepend
842 sort_with_compare
843 sorted_with_compare
844 sort
845 sorted
846 filter
847 any
848 all
849 count
850 clone
851 clone_to_depth
852 trim
853 contains
854 index
855 last_index
856 first
857 last
858 pop_left
859 pop
860 delete
861 delete_many
862 delete_last
863 drop
864 reverse
865 reverse_in_place
866 panic
867 json_decode
868 json_encode
869 json_encode_pretty
870 repeat
871 type_name
872 type_idx
873 clear
874 reserve
875 move
876 main_main
877 va_arg
878 addr
879 main
880 jsawait
881 error
882 grow_cap
883 grow_len
884 eprint
885 eprintln
886 print
887 println
888 close
889 pointers
890 push_many
891 malloc
892 writeln
893}
894
895// function or method call expr
896@[minify]
897pub struct CallExpr {
898pub:
899 pos token.Pos
900 name_pos token.Pos
901 mod string
902 kind CallKind
903pub mut:
904 name string // left.name()
905 is_method bool
906 is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
907 is_fn_var bool // fn variable, `a := fn() {}`, then: `a()`
908 is_fn_a_const bool // fn const, `const c = abc`, where `abc` is a function, then: `c()`
909 is_keep_alive bool // GC must not free arguments before fn returns
910 is_noreturn bool // whether the function/method is marked as [noreturn]
911 is_ctor_new bool // if JS ctor calls requires `new` before call, marked as `[use_new]` in V
912 is_file_translated bool // true, when the file it resides in is `@[translated]`
913 is_static_method bool // it is a static method call
914 is_variadic bool
915 is_c_variadic bool // it is a C variadic
916 is_c_type_cast bool // unresolved `C.Type(x)` reclassified by checker after imports are parsed
917 args []CallArg
918 expected_arg_types []Type
919 comptime_ret_val bool
920 language Language
921 or_block OrExpr
922 left Expr // `user` in `user.register()`
923 left_type Type // type of `user`
924 receiver_type Type // User / T, if receiver is generic, then cgen requires receiver_type to be T
925 receiver_concrete_type Type // if receiver_type is T, then receiver_concrete_type is concrete type, otherwise it is the same as receiver_type
926 return_type Type
927 return_type_generic Type // the original generic return type from fn def
928 nr_ret_values int = -1 // amount of return values
929 fn_var_type Type // the fn type, when `is_fn_a_const` or `is_fn_var` is true
930 const_name string // the fully qualified name of the const, i.e. `main.c`, given `const c = abc`, and callexpr: `c()`
931 should_be_skipped bool // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
932 concrete_types []Type // concrete types, e.g. [int, string]
933 concrete_list_pos token.Pos
934 raw_concrete_types []Type
935 free_receiver bool // true if the receiver expression needs to be freed
936 scope &Scope = unsafe { nil }
937 from_embed_types []Type // holds the type of the embed that the method is called from
938 comments []Comment
939 is_return_used bool // return value is used for another expr
940 //
941 is_expand_simple_interpolation bool // true, when the function/method is marked as @[expand_simple_interpolation]
942 is_unwrapped_fn_selector bool // true, when the call is from an unwrapped selector (e.g. if t.foo != none { t.foo() })
943 is_paren_wrapped_call bool // true, when the callee was wrapped in parentheses: `(f)(x)` — used by vfmt to preserve the parens
944 // Calls to it with an interpolation argument like `b.f('x ${y}')`, will be converted to `b.f('x ')` followed by `b.f(y)`.
945 // The same type, has to support also a .write_decimal(n i64) method.
946}
947
948/*
949pub struct AutofreeArgVar {
950 name string
951 idx int
952}
953*/
954
955// function call argument: `f(callarg)`
956@[minify]
957pub struct CallArg {
958pub:
959 is_mut bool
960 share ShareType
961 comments []Comment
962pub mut:
963 expr Expr
964 typ Type
965 is_tmp_autofree bool // this tells cgen that a tmp variable has to be used for the arg expression in order to free it after the call
966 pos token.Pos
967 should_be_ptr bool // fn expects a ptr for this arg
968 // tmp_name string // for autofree
969 ct_expr bool // true, when the expression is a comptime/generic expression
970}
971
972// function return statement
973pub struct Return {
974pub:
975 scope &Scope
976 pos token.Pos
977 comments []Comment
978pub mut:
979 exprs []Expr
980 types []Type
981}
982
983pub enum ComptimeVarKind {
984 no_comptime // it is not a comptime var
985 key_var // map key from `for k,v in t.$(field.name)`
986 value_var // map value from `for k,v in t.$(field.name)`
987 field_var // comptime field var `a := t.$(field.name)`
988 generic_param // generic fn parameter
989 generic_var // generic var
990 smartcast // smart cast when used in `is v` (when `v` is from $for .variants)
991 aggregate // aggregate var
992}
993
994@[minify]
995pub struct Var {
996pub:
997 name string
998 share ShareType
999 is_mut bool
1000 is_static bool
1001 is_volatile bool
1002 is_autofree_tmp bool
1003 is_inherited bool
1004 has_inherited bool
1005pub mut:
1006 is_arg bool // fn args should not be autofreed
1007 is_auto_deref bool
1008 is_unwrapped bool // ct type smartcast unwrapped
1009 is_assignment_smartcast bool // smartcast introduced by assigning a non-option value to an option variable
1010 is_index_var bool // index loop var
1011 expr Expr
1012 typ Type
1013 generic_typ Type // original generic declaration type; reused for later concrete instantiations
1014 orig_type Type // original sumtype type; 0 if it's not a sumtype
1015 smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
1016 // TODO: move this to a real docs site later
1017 // 10 <- original type (orig_type)
1018 // [11, 12, 13] <- cast order (smartcasts)
1019 // 12 <- the current casted type (typ)
1020 pos token.Pos
1021 is_used bool // whether the local variable was used in other expressions
1022 is_changed bool // to detect mutable vars that are never changed
1023 ct_type_var ComptimeVarKind // comptime variable type
1024 ct_type_unwrapped bool // true when the comptime variable gets unwrapped
1025 // (for setting the position after the or block for autofree)
1026 is_or bool // `x := foo() or { ... }`
1027 is_tmp bool // for tmp for loop vars, so that autofree can skip them
1028 is_auto_heap bool // value whose address goes out of scope
1029 is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not @[heap] struct)
1030 is_special bool // err, it, a, b vars (ignore not useds)
1031}
1032
1033// used for smartcasting only
1034// struct fields change type in scopes
1035@[minify]
1036pub struct ScopeStructField {
1037pub:
1038 struct_type Type // type of struct
1039 name string
1040 is_mut bool
1041 pos token.Pos
1042 typ Type
1043 orig_type Type // original sumtype type; 0 if it's not a sumtype
1044 smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
1045 // TODO: move this to a real docs site later
1046 // 10 <- original type (orig_type)
1047 // [11, 12, 13] <- cast order (smartcasts)
1048 // 12 <- the current casted type (typ)
1049}
1050
1051@[minify]
1052pub struct GlobalField {
1053pub:
1054 name string
1055 has_expr bool
1056 pos token.Pos
1057 typ_pos token.Pos
1058 is_markused bool // an explicit `@[markused]` tag; the global will NOT be removed by `-skip-unused`
1059 is_volatile bool
1060 is_const bool
1061 is_exported bool // an explicit `@[export]` tag; the global will NOT be removed by `-skip-unused`
1062 is_weak bool
1063 is_hidden bool
1064 // The following fields, are relevant for non V globals, for example `__global C.stdout &C.FILE`:
1065 language Language // for C.stdout, it will be .c .
1066 is_extern bool // true, if an explicit `@[c_extern]` tag was used. It is suitable for globals, that are not initialised by V,
1067 // but come from the external linked objects/libs, like C.stdout etc, and that *are not* declared in included .h files .
1068 // Without an explicit `@[c_extern]` tag, V will avoid emiting `extern CType CName;` lines.
1069 // V will still know, that the type of C.stdout, is not the default `int`, but &C.FILE, and thus will do more checks on it.
1070pub mut:
1071 expr Expr
1072 typ Type
1073 comments []Comment
1074}
1075
1076pub struct GlobalDecl {
1077pub:
1078 mod string
1079 pos token.Pos
1080 is_block bool // __global() block
1081 attrs []Attr // tags like `@[markused]`, valid for all the globals in the list
1082pub mut:
1083 fields []GlobalField
1084 end_comments []Comment
1085}
1086
1087@[minify]
1088pub struct EmbeddedFile {
1089pub:
1090 compression_type string
1091pub mut:
1092 rpath string // used in the source code, as an ID/key to the embed
1093 apath string // absolute path during compilation to the resource
1094 // these are set by gen_embed_file_init in v/gen/c/embed
1095 is_compressed bool
1096 bytes []u8
1097 len int
1098}
1099
1100// TemplateLineInfo maps a generated code line to the original template location
1101pub struct TemplateLineInfo {
1102pub:
1103 tmpl_path string // path to the template file (for @include support)
1104 tmpl_line int // 0-based line number in the template
1105}
1106
1107// Each V source file is represented by one File structure.
1108// When the V compiler runs, the parser will fill an []File.
1109// That array is then passed to V's checker.
1110@[heap]
1111pub struct File {
1112pub:
1113 nr_lines int // number of source code lines in the file (including newlines and comments)
1114 nr_bytes int // number of processed source code bytes
1115 nr_tokens int // number of processed tokens in the source code of the file
1116 mod Module // the module of the source file (from `module xyz` at the top)
1117 global_scope &Scope = unsafe { nil }
1118 is_test bool // true for _test.v files
1119 is_generated bool // true for `@[generated] module xyz` files; turn off notices
1120 is_translated bool // true for `@[translated] module xyz` files; turn off some checks
1121 language Language
1122pub mut:
1123 idx int // index in an external container; can be used to refer to the file in a more efficient way, just by its integer index
1124 path string // absolute path of the source file - '/projects/v/file.v'
1125 path_base string // file name - 'file.v' (useful for tracing)
1126 scope &Scope = unsafe { nil }
1127 stmts []Stmt // all the statements in the source file
1128 imports []Import // all the imports
1129 auto_imports []string // imports that were implicitly added
1130 used_imports []string
1131 implied_imports []string // ​imports that the user's code uses but omitted to import explicitly, used by `vfmt`
1132 embedded_files []EmbeddedFile // list of files to embed in the binary
1133 imported_symbols map[string]string // used for `import {symbol}`, it maps symbol => module.symbol
1134 imported_symbols_trie token.KeywordsMatcherTrie // constructed from imported_symbols, to accelerate presense checks
1135 imported_symbols_used map[string]bool
1136 errors []errors.Error // all the checker errors in the file
1137 warnings []errors.Warning // all the checker warnings in the file
1138 notices []errors.Notice // all the checker notices in the file
1139 call_stack []errors.CallStackItem // call stack for this file (used for template errors)
1140 generic_fns []&FnDecl
1141 global_labels []string // from `asm { .globl labelname }`
1142 template_paths []string // all the .html/.md files that were processed with $tmpl
1143 template_line_map []TemplateLineInfo // maps generated line -> original template location
1144 unique_prefix string // a hash of the `.path` field, used for making anon fn generation unique
1145 //
1146 is_parse_text bool // true for files, produced by parse_text
1147 is_template_text bool // true for files, produced by parse_comptime
1148}
1149
1150@[unsafe]
1151pub fn (f &File) free() {
1152 unsafe {
1153 f.path.free()
1154 f.path_base.free()
1155 f.scope.free()
1156 f.stmts.free()
1157 f.imports.free()
1158 f.auto_imports.free()
1159 f.embedded_files.free()
1160 f.imported_symbols.free()
1161 f.errors.free()
1162 f.warnings.free()
1163 f.notices.free()
1164 f.global_labels.free()
1165 }
1166}
1167
1168pub struct IdentFn {
1169pub mut:
1170 typ Type
1171}
1172
1173// TODO: (joe) remove completely, use ident.obj
1174// instead which points to the scope object
1175@[minify]
1176pub struct IdentVar {
1177pub mut:
1178 typ Type
1179 is_mut bool
1180 is_static bool
1181 is_volatile bool
1182 is_option bool
1183 share ShareType
1184}
1185
1186pub type IdentInfo = IdentFn | IdentVar
1187
1188pub enum IdentKind {
1189 unresolved
1190 blank_ident // discard identifier, `_` in `_ := 1`
1191 variable
1192 constant
1193 global
1194 function
1195}
1196
1197// A single identifier
1198@[minify]
1199pub struct Ident {
1200pub:
1201 language Language
1202 tok_kind token.Kind
1203 pos token.Pos
1204 mut_pos token.Pos
1205 comptime bool
1206pub mut:
1207 scope &Scope = unsafe { nil }
1208 obj ScopeObject = empty_scope_object
1209 mod string
1210 name string
1211 full_name string
1212 cached_name string
1213 kind IdentKind
1214 info IdentInfo
1215 is_mut bool // if mut *token* is before name. Use `is_mut()` to lookup mut variable
1216 or_expr OrExpr
1217 concrete_types []Type
1218 ct_expr bool // is it a comptime expr?
1219}
1220
1221// full_name returns the name of the ident, prefixed with the module name
1222pub fn (mut i Ident) full_name() string {
1223 if i.full_name != '' {
1224 return i.full_name
1225 }
1226 if i.name.contains('.') {
1227 i.full_name = i.name
1228 } else {
1229 i.full_name = i.mod + '.' + i.name
1230 }
1231 return i.full_name
1232}
1233
1234@[inline]
1235pub fn (i &Ident) is_auto_heap() bool {
1236 return match i.obj {
1237 Var { i.obj.is_auto_heap }
1238 else { false }
1239 }
1240}
1241
1242@[inline]
1243pub fn (i &Ident) is_stack_obj() bool {
1244 return match i.obj {
1245 Var { i.obj.is_stack_obj }
1246 else { false }
1247 }
1248}
1249
1250@[inline]
1251pub fn (i &Ident) is_mut() bool {
1252 match i.obj {
1253 Var { return i.obj.is_mut }
1254 ConstField, EmptyScopeObject { return false }
1255 AsmRegister { return true }
1256 GlobalField { return !i.obj.is_const }
1257 }
1258}
1259
1260pub fn (i &Ident) var_info() IdentVar {
1261 match i.info {
1262 IdentVar { return i.info }
1263 else { panic('Ident.var_info(): info is not IdentVar variant') }
1264 }
1265}
1266
1267// left op right
1268// See: token.Kind.is_infix
1269@[minify]
1270pub struct InfixExpr {
1271pub:
1272 op token.Kind
1273 pos token.Pos
1274 is_stmt bool
1275pub mut:
1276 left Expr
1277 right Expr
1278 left_type Type
1279 right_type Type
1280 promoted_type Type = void_type
1281 auto_locked string
1282 or_block OrExpr
1283
1284 ct_left_value_evaled bool
1285 ct_left_value ComptTimeConstValue = empty_comptime_const_value
1286 left_ct_expr bool // true when left is comptime/generic expr
1287 ct_right_value_evaled bool
1288 ct_right_value ComptTimeConstValue = empty_comptime_const_value
1289 right_ct_expr bool // true when right is comptime/generic expr
1290
1291 before_op_comments []Comment
1292 after_op_comments []Comment
1293}
1294
1295// ++, --
1296pub struct PostfixExpr {
1297pub:
1298 op token.Kind
1299 pos token.Pos
1300 is_c2v_prefix bool // for `--x` (`x--$`), only for translated code until c2v can handle it
1301pub mut:
1302 expr Expr
1303 typ Type
1304 auto_locked string
1305}
1306
1307// See: token.Kind.is_prefix
1308@[minify]
1309pub struct PrefixExpr {
1310pub:
1311 op token.Kind
1312 pos token.Pos
1313pub mut:
1314 right_type Type
1315 right Expr
1316 or_block OrExpr
1317 is_option bool // IfGuard
1318}
1319
1320@[minify]
1321pub struct IndexExpr {
1322pub:
1323 pos token.Pos
1324pub mut:
1325 index Expr // [0], RangeExpr [start..end] or map[key]
1326 indices []Expr // parsed index parts, e.g. [i], [i, j], [1..3, ..]
1327 or_expr OrExpr
1328 left Expr
1329 left_type Type // array, map, fixed array, or overloaded index receiver
1330 index_type Type
1331 setter_arg_type Type
1332 is_setter bool
1333 is_map bool
1334 is_array bool
1335 is_farray bool // fixed array
1336 is_index_operator bool // lowered as `[]` / `[]=` method calls
1337 is_option bool // IfGuard
1338 is_direct bool // Set if the underlying memory can be safely accessed
1339 is_gated bool // #[] gated array
1340 typ Type
1341}
1342
1343@[minify]
1344pub struct IfExpr {
1345pub:
1346 is_comptime bool
1347 tok_kind token.Kind
1348 pos token.Pos
1349 post_comments []Comment
1350pub mut:
1351 left Expr // `a` in `a := if ...`
1352 branches []IfBranch // includes all `else if` branches
1353 is_expr bool
1354 force_expr bool
1355 typ Type
1356 has_else bool
1357 // implements bool // comptime $if implements interface
1358}
1359
1360pub struct IfBranch {
1361pub:
1362 pos token.Pos
1363 body_pos token.Pos
1364 comments []Comment
1365pub mut:
1366 cond Expr
1367 stmts []Stmt
1368 scope &Scope = unsafe { nil }
1369 id int
1370}
1371
1372pub struct UnsafeExpr {
1373pub:
1374 pos token.Pos
1375pub mut:
1376 expr Expr
1377}
1378
1379pub struct LockExpr {
1380pub:
1381 is_rlock []bool
1382 pos token.Pos
1383pub mut:
1384 stmts []Stmt
1385 lockeds []Expr // `x`, `y.z` in `lock x, y.z {`
1386 comments []Comment
1387 is_expr bool
1388 typ Type
1389 scope &Scope = unsafe { nil }
1390}
1391
1392@[minify]
1393pub struct MatchExpr {
1394pub:
1395 is_comptime bool
1396 tok_kind token.Kind
1397 pos token.Pos
1398 comments []Comment // comments before the first branch
1399pub mut:
1400 cond Expr
1401 branches []MatchBranch
1402 is_expr bool // returns a value
1403 return_type Type
1404 cond_type Type // type of `x` in `match x {`
1405 expected_type Type // for debugging only
1406 is_sum_type bool
1407}
1408
1409pub struct MatchBranch {
1410pub:
1411 ecmnts [][]Comment // inline comments for each left side expr
1412 pos token.Pos
1413 is_else bool
1414 post_comments []Comment // comments below ´... }´
1415 branch_pos token.Pos // for checker errors about invalid branches
1416pub mut:
1417 stmts []Stmt // right side
1418 exprs []Expr // left side
1419 scope &Scope = unsafe { nil }
1420 id int
1421 is_comptime_err bool // $compile_warn(), $compile_error()
1422}
1423
1424pub struct SelectExpr {
1425pub:
1426 branches []SelectBranch
1427 pos token.Pos
1428 has_exception bool
1429pub mut:
1430 is_expr bool // returns a value
1431 expected_type Type // for debugging only
1432}
1433
1434@[minify]
1435pub struct SelectBranch {
1436pub:
1437 pos token.Pos
1438 comment Comment // comment above `select {`
1439 is_else bool
1440 is_timeout bool
1441 post_comments []Comment
1442 scope &Scope
1443pub mut:
1444 stmt Stmt // `a := <-ch` or `ch <- a`
1445 stmts []Stmt // right side
1446}
1447
1448pub enum ComptimeForKind {
1449 methods
1450 fields
1451 attributes
1452 values
1453 variants
1454 params
1455}
1456
1457pub struct ComptimeFor {
1458pub:
1459 val_var string
1460 kind ComptimeForKind
1461 pos token.Pos
1462 typ_pos token.Pos
1463 scope &Scope = unsafe { nil }
1464pub mut:
1465 stmts []Stmt
1466 typ Type
1467 expr Expr
1468}
1469
1470pub struct ForStmt {
1471pub:
1472 is_inf bool // `for {}`
1473 pos token.Pos
1474 comments []Comment
1475pub mut:
1476 cond Expr
1477 stmts []Stmt
1478 label string // `label: for {`
1479 scope &Scope = unsafe { nil }
1480}
1481
1482@[minify]
1483pub struct ForInStmt {
1484pub:
1485 key_var string
1486 val_var string
1487 is_range bool
1488 pos token.Pos
1489 kv_pos token.Pos
1490 vv_pos token.Pos
1491 comments []Comment
1492 val_is_mut bool // `for mut val in vals {` means that modifying `val` will modify the array
1493 // and the array cannot be indexed inside the loop
1494pub mut:
1495 val_is_ref bool // `for val in &arr {` means that value of `val` will be the reference of the value in `arr`
1496 cond Expr
1497 key_type Type
1498 val_type Type
1499 cond_type Type
1500 high Expr // `10` in `for i in 0..10 {`
1501 high_type Type
1502 kind Kind // array/map/string
1503 label string // `label: for {`
1504 scope &Scope = unsafe { nil }
1505 stmts []Stmt
1506}
1507
1508pub struct ForCStmt {
1509pub:
1510 has_init bool
1511 has_cond bool
1512 has_inc bool
1513 is_multi bool // for a,b := 0,1; a < 10; a,b = a+b, a {...}
1514 pos token.Pos
1515 comments []Comment
1516pub mut:
1517 init Stmt // i := 0;
1518 cond Expr // i < 10;
1519 inc Stmt // i++; i += 2
1520 stmts []Stmt
1521 label string // `label: for {`
1522 scope &Scope = unsafe { nil }
1523}
1524
1525// #include, #define etc
1526pub struct HashStmt {
1527pub:
1528 mod string
1529 pos token.Pos
1530 source_file string
1531 is_use_once bool // true for @[use_once]
1532pub mut:
1533 val string // example: 'include <openssl/rand.h> # please install openssl // comment'
1534 kind string // : 'include'
1535 main string // : '<openssl/rand.h>'
1536 msg string // : 'please install openssl'
1537 ct_conds []Expr // *all* comptime conditions, that must be true, for the hash to be processed
1538 // ct_conds is filled by the checker, based on the current nesting of `$if cond1 {}` blocks
1539 ct_low_level_cond string // optional low-level comptime condition e.g. 'linux', 'darwin' for `#include linux <pty.h>`
1540 attrs []Attr
1541}
1542
1543// variable assign statement
1544@[minify]
1545pub struct AssignStmt {
1546pub:
1547 op token.Kind // include: =,:=,+=,-=,*=,/= and so on; for a list of all the assign operators, see vlib/token/token.v
1548 pos token.Pos
1549 end_comments []Comment
1550pub mut:
1551 right []Expr
1552 left []Expr
1553 left_types []Type
1554 right_types []Type
1555 is_static bool // for translated code only
1556 is_volatile bool // for disabling variable access optimisations (needed for hardware drivers)
1557 is_simple bool // `x+=2` in `for x:=1; ; x+=2`
1558 has_cross_var bool
1559 attr Attr
1560}
1561
1562// `expr as Ident`
1563pub struct AsCast {
1564pub:
1565 typ Type // to type
1566 pos token.Pos
1567pub mut:
1568 expr Expr // from expr: `expr` in `expr as Ident`
1569 expr_type Type // from type
1570}
1571
1572// An enum value, like OS.macos or .macos
1573pub struct EnumVal {
1574pub:
1575 enum_name string
1576 val string
1577 mod string // for full path `mod_Enum_val`
1578 pos token.Pos
1579pub mut:
1580 typ Type
1581}
1582
1583// enum field in enum declaration
1584pub struct EnumField {
1585pub:
1586 name string // just `lock`, or `abc`, etc, no matter if the name is a keyword or not.
1587 source_name string // The name in the source, for example `lock`, and `abc`. Note that `lock` is a keyword in V.
1588 pos token.Pos
1589 pre_comments []Comment // comment before Enumfield
1590 comments []Comment // comment after Enumfield in the same line
1591 next_comments []Comment // comments between current EnumField and next EnumField
1592 has_expr bool // true, when .expr has a value
1593 has_prev_newline bool // empty newline before Enumfield
1594 has_break_line bool
1595 attrs []Attr
1596pub mut:
1597 expr Expr // the value of current EnumField; 123 in `ename = 123`
1598}
1599
1600// enum declaration
1601@[minify]
1602pub struct EnumDecl {
1603pub:
1604 name string
1605 is_pub bool
1606 is_flag bool // true when the enum has @[flag] tag,for bit field enum
1607 is_multi_allowed bool // true when the enum has [_allow_multiple_values] tag
1608 comments []Comment // comments before the first EnumField
1609 fields []EnumField // all the enum fields
1610 attrs []Attr // attributes of enum declaration
1611 typ Type // the default is `int`; can be changed by `enum Big as u64 { a = 5 }`
1612 typ_pos token.Pos
1613 pos token.Pos
1614pub mut:
1615 enum_typ Type
1616}
1617
1618pub struct AliasTypeDecl {
1619pub:
1620 name string
1621 mod string
1622 is_pub bool
1623 typ Type
1624 pos token.Pos
1625 type_pos token.Pos
1626 comments []Comment
1627 attrs []Attr // attributes like @[deprecated] etc
1628pub mut:
1629 parent_type Type
1630 is_markused bool
1631}
1632
1633// SumTypeDecl is the ast node for `type MySumType = string | int`
1634pub struct SumTypeDecl {
1635pub:
1636 name string
1637 mod string
1638 is_pub bool
1639 pos token.Pos
1640 name_pos token.Pos
1641 typ Type
1642 generic_types []Type
1643 attrs []Attr // attributes of type declaration
1644pub mut:
1645 variants []TypeNode
1646 is_markused bool
1647}
1648
1649pub struct FnTypeDecl {
1650pub:
1651 name string
1652 mod string
1653 is_pub bool
1654 typ Type
1655 pos token.Pos
1656 type_pos token.Pos
1657 comments []Comment
1658 generic_types []Type
1659 attrs []Attr // attributes of type declaration
1660 is_markused bool
1661}
1662
1663pub enum DeferMode {
1664 scoped // default
1665 function
1666}
1667
1668// TODO: handle this differently
1669// v1 excludes non current os ifdefs so
1670// the defer's never get added in the first place
1671@[minify]
1672pub struct DeferStmt {
1673pub:
1674 pos token.Pos
1675 scope &Scope
1676 mode DeferMode
1677pub mut:
1678 stmts []Stmt
1679 defer_vars []Ident
1680 ifdef string
1681 idx_in_fn int = -1 // index in FnDecl.defer_stmts
1682}
1683
1684// `(3+4)`
1685pub struct ParExpr {
1686pub:
1687 pos token.Pos
1688pub mut:
1689 expr Expr
1690 comments []Comment
1691}
1692
1693@[minify]
1694pub struct GoExpr {
1695pub:
1696 pos token.Pos
1697pub mut:
1698 call_expr CallExpr
1699 is_expr bool
1700}
1701
1702@[minify]
1703pub struct SpawnExpr {
1704pub:
1705 pos token.Pos
1706pub mut:
1707 call_expr CallExpr
1708 is_expr bool
1709}
1710
1711pub struct GotoLabel {
1712pub:
1713 name string
1714 pos token.Pos
1715pub mut:
1716 is_used bool
1717}
1718
1719pub struct GotoStmt {
1720pub:
1721 name string
1722 pos token.Pos
1723}
1724
1725@[minify]
1726pub struct ArrayInit {
1727pub:
1728 pos token.Pos // `[]` in []Type{} position
1729 elem_type_pos token.Pos // `Type` in []Type{} position
1730 ecmnts [][]Comment // optional iembed comments after each expr
1731 pre_cmnts []Comment
1732 is_fixed bool
1733 is_option bool // true if it was declared as ?[2]Type or ?[]Type
1734 has_val bool // fixed size literal `[expr, expr]!`
1735 from_to_fixed_size bool // lowered from `[expr, expr].to_fixed_size()`
1736 mod string
1737 has_len bool
1738 has_cap bool
1739 has_init bool
1740 has_index bool // true if temp variable index is used
1741pub mut:
1742 exprs []Expr // `[expr, expr]` or `[expr]Type{}` for fixed array
1743 len_expr Expr // len: expr
1744 cap_expr Expr // cap: expr
1745 init_expr Expr // init: expr
1746 elem_type_expr Expr = empty_expr // `typeof(expr).idx` in `[]typeof(expr).idx{}`
1747 expr_types []Type // [Dog, Cat] // also used for interface_types
1748 elem_type Type // element type
1749 generic_elem_type Type // original generic element type; reused for later concrete instantiations
1750 init_type Type // init: value type
1751 typ Type // array type
1752 literal_typ Type // array type as written, preserved for fmt
1753 generic_typ Type // original generic array type; reused for later concrete instantiations
1754 alias_type Type // alias type
1755 has_callexpr bool // has expr which needs tmp var to initialize it
1756}
1757
1758pub struct ArrayDecompose {
1759pub:
1760 pos token.Pos
1761pub mut:
1762 expr Expr
1763 expr_type Type
1764 arg_type Type
1765}
1766
1767pub struct ChanInit {
1768pub:
1769 pos token.Pos
1770 elem_type_pos token.Pos
1771 has_cap bool
1772pub mut:
1773 cap_expr Expr
1774 typ Type
1775 elem_type Type
1776}
1777
1778@[minify]
1779pub struct MapInit {
1780pub:
1781 pos token.Pos
1782 comments [][]Comment // comments after key-value pairs
1783 pre_cmnts []Comment // comments before the first key-value pair
1784pub mut:
1785 keys []Expr
1786 vals []Expr
1787 val_types []Type
1788 typ Type
1789 key_type Type
1790 value_type Type
1791 has_update_expr bool // has `...a`
1792 update_expr Expr // `a` in `...a`
1793 update_expr_pos token.Pos
1794 update_expr_comments []Comment
1795}
1796
1797// s[10..20]
1798@[minify]
1799pub struct RangeExpr {
1800pub:
1801 has_high bool
1802 has_low bool
1803 pos token.Pos
1804 is_gated bool // #[] gated array
1805pub mut:
1806 low Expr
1807 high Expr
1808 typ Type // filled in by checker; the type of `0...1` is `int` for example, while `a`...`z` is `rune` etc
1809}
1810
1811@[minify]
1812pub struct CastExpr {
1813pub mut:
1814 arg Expr // `n` in `string(buf, n)`
1815 typ Type // `string`
1816 expr Expr // `buf` in `string(buf, n)` and `&Type(buf)`
1817 typname string // `&Type` in `&Type(buf)`
1818 expr_type Type // `byteptr`, the type of the `buf` expression
1819 has_arg bool // true for `string(buf, n)`, false for `&Type(buf)`
1820 pos token.Pos
1821}
1822
1823@[minify]
1824pub struct AsmStmt {
1825pub:
1826 arch pref.Arch
1827 is_basic bool
1828 is_volatile bool
1829 is_goto bool
1830 clobbered []AsmClobbered
1831 pos token.Pos
1832pub mut:
1833 templates []AsmTemplate
1834 scope &Scope = unsafe { nil }
1835 output []AsmIO
1836 input []AsmIO
1837 global_labels []string // labels defined in assembly block, exported with `.globl`
1838 local_labels []string // local to the assembly block
1839}
1840
1841@[minify]
1842pub struct AsmTemplate {
1843pub mut:
1844 name string
1845 is_label bool // `example_label:`
1846 is_directive bool // .globl assembly_function
1847 args []AsmArg
1848 comments []Comment
1849 pos token.Pos
1850}
1851
1852// [eax+5] | j | displacement literal (e.g. 123 in [rax + 123] ) | eax | true | `a` | 0.594 | 123 | label_name
1853pub type AsmArg = AsmAddressing
1854 | AsmAlias
1855 | AsmDisp
1856 | AsmRegister
1857 | BoolLiteral
1858 | CharLiteral
1859 | FloatLiteral
1860 | IntegerLiteral
1861 | string
1862
1863pub struct AsmRegister {
1864pub mut:
1865 name string // eax or r12d etc.
1866 typ Type
1867 size int
1868}
1869
1870pub struct AsmDisp {
1871pub:
1872 val string
1873 pos token.Pos
1874}
1875
1876pub struct AsmAlias {
1877pub:
1878 pos token.Pos
1879pub mut:
1880 name string // a
1881}
1882
1883pub struct AsmAddressing {
1884pub:
1885 scale int = -1 // 1, 2, 4, or 8 literal
1886 mode AddressingMode
1887 pos token.Pos
1888pub mut:
1889 segment string // fs:
1890 displacement AsmArg // 8, 16 or 32 bit literal value
1891 base AsmArg // gpr
1892 index AsmArg // gpr
1893}
1894
1895// addressing modes:
1896pub enum AddressingMode {
1897 invalid
1898 displacement // displacement
1899 base // base
1900 base_plus_displacement // base + displacement
1901 index_times_scale_plus_displacement // (index ∗ scale) + displacement
1902 base_plus_index_plus_displacement // base + (index ∗ scale) + displacement
1903 base_plus_index_times_scale_plus_displacement // base + index + displacement
1904 rip_plus_displacement // rip + displacement
1905}
1906
1907pub struct AsmClobbered {
1908pub mut:
1909 reg AsmRegister
1910 comments []Comment
1911}
1912
1913// : [alias_a] '=r' (a) // this is a comment
1914pub struct AsmIO {
1915pub:
1916 alias string // [alias_a]
1917 constraint string // '=r' TODO: allow all backends to easily use this with a struct
1918 comments []Comment // // this is a comment
1919 typ Type
1920 pos token.Pos
1921pub mut:
1922 expr Expr // (a)
1923}
1924
1925// reference: https://en.wikipedia.org/wiki/X86#/media/File:Table_of_x86_Registers_svg.svg
1926// map register size -> register name
1927pub const x86_no_number_register_list = {
1928 8: ['al', 'ah', 'bl', 'bh', 'cl', 'ch', 'dl', 'dh', 'bpl', 'sil', 'dil', 'spl']
1929 16: ['ax', 'bx', 'cx', 'dx', 'bp', 'si', 'di', 'sp', // segment registers
1930 'cs', 'ss', 'ds', 'es', 'fs', 'gs', 'flags', 'ip', // task registers
1931 'gdtr', 'idtr', 'tr', 'ldtr', // CSR register 'msw', /* FP core registers */ 'cw', 'sw', 'tw', 'fp_ip', 'fp_dp', 'fp_cs',
1932 'fp_ds', 'fp_opc']
1933 32: [
1934 'eax',
1935 'ebx',
1936 'ecx',
1937 'edx',
1938 'ebp',
1939 'esi',
1940 'edi',
1941 'esp',
1942 'eflags',
1943 'eip', // CSR register
1944 'mxcsr', // 32-bit FP core registers 'fp_dp', 'fp_ip' (TODO: why are there duplicates?)
1945 ]
1946 64: ['rax', 'rbx', 'rcx', 'rdx', 'rbp', 'rsi', 'rdi', 'rsp', 'rflags', 'rip']
1947}
1948// no comments because maps do not support comments
1949// r#*: gp registers added in 64-bit extensions, can only be from 8-15 actually
1950// *mm#: vector/simd registers
1951// st#: floating point numbers
1952// cr#: control/status registers
1953// dr#: debug registers
1954pub const x86_with_number_register_list = {
1955 8: {
1956 'r#b': 16
1957 }
1958 16: {
1959 'r#w': 16
1960 }
1961 32: {
1962 'r#d': 16
1963 }
1964 64: {
1965 'r#': 16
1966 'mm#': 16
1967 'cr#': 16
1968 'dr#': 16
1969 }
1970 80: {
1971 'st#': 16
1972 }
1973 128: {
1974 'xmm#': 32
1975 }
1976 256: {
1977 'ymm#': 32
1978 }
1979 512: {
1980 'zmm#': 32
1981 }
1982}
1983
1984// TODO: saved priviled registers for arm
1985pub const arm_no_number_register_list = ['fp', // aka r11
1986 'ip', // not instruction pointer: aka r12
1987 'sp', // aka r13
1988 'lr', // aka r14
1989 'pc', // this is instruction pointer ('program counter'): aka r15
1990] // 'cpsr' and 'apsr' are special flags registers, but cannot be referred to directly
1991
1992pub const arm_with_number_register_list = {
1993 'r#': 16
1994}
1995
1996pub const riscv_no_number_register_list = ['zero', 'ra', 'sp', 'gp', 'tp']
1997pub const riscv_with_number_register_list = {
1998 'x#': 32
1999 't#': 3
2000 's#': 12
2001 'a#': 8
2002}
2003
2004pub const s390x_no_number_register_list = []string{}
2005pub const s390x_with_number_register_list = {
2006 'f#': 16
2007 'r#': 16
2008 'v#': 32
2009}
2010
2011pub const ppc64le_no_number_register_list = []string{}
2012pub const ppc64le_with_number_register_list = {
2013 'f#': 32
2014 'r#': 32
2015}
2016
2017pub const loongarch64_no_number_register_list = []string{}
2018pub const loongarch64_with_number_register_list = {
2019 'f#': 32
2020 'r#': 32
2021}
2022
2023pub struct DebuggerStmt {
2024pub:
2025 pos token.Pos
2026}
2027
2028// `assert a == 0, 'a is zero'`
2029@[minify]
2030pub struct AssertStmt {
2031pub:
2032 pos token.Pos
2033 extra_pos token.Pos
2034pub mut:
2035 expr Expr // `a == 0`
2036 extra Expr // `'a is zero'`
2037 is_used bool // asserts are used in _test.v files, as well as in non -prod builds of all files
2038}
2039
2040pub struct IfGuardVar {
2041pub mut:
2042 name string
2043 is_mut bool
2044 pos token.Pos
2045}
2046
2047// `if x := opt() {`
2048pub struct IfGuardExpr {
2049pub:
2050 vars []IfGuardVar
2051pub mut:
2052 expr Expr // `opt()`
2053 expr_type Type // type of `opt()`
2054}
2055
2056pub enum OrKind {
2057 absent
2058 block
2059 propagate_option
2060 propagate_result
2061}
2062
2063// `or { ... }`
2064pub struct OrExpr {
2065pub:
2066 kind OrKind
2067 pos token.Pos
2068 scope &Scope = unsafe { nil }
2069pub mut:
2070 err_used bool
2071 stmts []Stmt
2072}
2073
2074/*
2075// `or { ... }`
2076pub struct OrExpr2 {
2077pub:
2078 call_expr CallExpr
2079 stmts []Stmt // inside `or { }`
2080 kind OrKind
2081 pos token.Pos
2082}
2083*/
2084
2085// deprecated
2086@[minify]
2087pub struct Assoc {
2088pub:
2089 var_name string
2090 fields []string
2091 pos token.Pos
2092pub mut:
2093 exprs []Expr
2094 typ Type
2095 scope &Scope = unsafe { nil }
2096}
2097
2098pub struct SizeOf {
2099pub:
2100 guessed_type bool // a legacy `sizeof( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `sizeof[ Type ]()`
2101 is_type bool
2102 pos token.Pos
2103pub mut:
2104 expr Expr // checker uses this to set typ, when !is_type
2105 typ Type
2106}
2107
2108pub struct IsRefType {
2109pub:
2110 guessed_type bool // a legacy `isreftype( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `isreftype[ Type ]()`
2111 is_type bool
2112 pos token.Pos
2113pub mut:
2114 expr Expr // checker uses this to set typ, when !is_type
2115 typ Type
2116}
2117
2118@[minify]
2119pub struct OffsetOf {
2120pub:
2121 struct_type Type
2122 field string
2123 pos token.Pos
2124}
2125
2126pub struct LambdaExpr {
2127pub:
2128 pos token.Pos
2129pub mut:
2130 params []Ident
2131 pos_expr token.Pos
2132 expr Expr
2133 pos_end token.Pos
2134 scope &Scope = unsafe { nil }
2135 func &AnonFn = unsafe { nil }
2136 is_checked bool
2137 typ Type
2138 call_ctx &CallExpr = unsafe { nil }
2139}
2140
2141pub struct Likely {
2142pub:
2143 pos token.Pos
2144 is_likely bool // false for _unlikely_
2145pub mut:
2146 expr Expr
2147}
2148
2149@[minify]
2150pub struct TypeOf {
2151pub:
2152 is_type bool
2153 pos token.Pos
2154pub mut:
2155 expr Expr // checker uses this to set typ, when !is_type
2156 typ Type
2157}
2158
2159@[minify]
2160pub struct DumpExpr {
2161pub:
2162 pos token.Pos
2163pub mut:
2164 expr Expr
2165 expr_type Type
2166 cname string // filled in the checker
2167}
2168
2169pub struct Comment {
2170pub:
2171 text string
2172 is_multi bool // true only for /* comment */, that use many lines
2173 pos token.Pos
2174}
2175
2176pub struct ConcatExpr {
2177pub:
2178 vals []Expr
2179 pos token.Pos
2180pub mut:
2181 return_type Type
2182}
2183
2184// @FN, @STRUCT, @MOD etc. See full list in token.valid_at_tokens
2185pub struct AtExpr {
2186pub:
2187 name string
2188 pos token.Pos
2189 kind token.AtKind
2190pub mut:
2191 val string
2192}
2193
2194@[minify]
2195pub struct ComptimeSelector {
2196pub:
2197 has_parens bool // if $() is used, for vfmt
2198 pos token.Pos
2199 or_block OrExpr
2200pub mut:
2201 left Expr
2202 left_type Type
2203 field_expr Expr
2204 typ Type
2205 is_name bool // true if f.$(field.name)
2206 is_method bool // true if f.$(method)
2207 typ_key string // `f.typ` cached key for type resolver
2208}
2209
2210pub enum ComptimeCallKind {
2211 unknown
2212 d
2213 env
2214 res
2215 html
2216 tmpl
2217 method
2218 pkgconfig
2219 embed_file
2220 zero
2221 new
2222 compile_warn
2223 compile_error
2224}
2225
2226@[minify]
2227pub struct ComptimeCall {
2228pub:
2229 pos token.Pos
2230 has_parens bool // if $() is used, for vfmt
2231 method_name string
2232 kind ComptimeCallKind
2233 method_pos token.Pos
2234 scope &Scope = unsafe { nil }
2235 is_template bool
2236 is_veb bool
2237 env_pos token.Pos
2238mut:
2239 is_d_resolved bool
2240pub mut:
2241 veb_tmpl File
2242 left Expr
2243 left_type Type
2244 result_type Type
2245 env_value string
2246 compile_value string
2247 args_var string
2248 args []CallArg
2249 embed_file EmbeddedFile
2250 or_block OrExpr
2251}
2252
2253// resolve_compile_value resolves the value and return type of `$d()` calls.
2254// The result is stored in fields `compile_value` and `result_type`.
2255// The argument `compile_values` is expected to be the `Preferences.compile_values` field.
2256pub fn (mut cc ComptimeCall) resolve_compile_value(compile_values map[string]string) ! {
2257 if cc.is_d_resolved {
2258 return
2259 }
2260 if cc.kind != .d {
2261 return error('ComptimeCall is not \$d()')
2262 }
2263 arg := cc.args[0] or {
2264 return error('\$d() takes two arguments, a string and a primitive literal')
2265 }
2266 if !arg.expr.is_pure_literal() {
2267 return error('\$d() values can only be pure literals')
2268 }
2269 typ := arg.expr.get_pure_type()
2270 arg_as_string := arg.str().trim('`"\'')
2271 value := compile_values[cc.args_var] or { arg_as_string }
2272 validate_type_string_is_pure_literal(typ, value) or { return error(err.msg()) }
2273 cc.compile_value = value
2274 cc.result_type = typ
2275 cc.is_d_resolved = true
2276}
2277
2278// expr_str returns the string representation of `ComptimeCall` for use with
2279// `ast.Expr`'s `str()' method (used by e.g. vfmt).
2280pub fn (cc ComptimeCall) expr_str() string {
2281 mut str := 'ast.ComptimeCall'
2282 if cc.kind == .d {
2283 arg := cc.args[0] or { return str }
2284 if arg.expr.is_pure_literal() {
2285 str = "\$${cc.method_name}('${cc.args_var}', ${arg})"
2286 }
2287 } else if cc.kind == .pkgconfig {
2288 str = "\$${cc.method_name}('${cc.args_var}')"
2289 } else if cc.kind in [.zero, .new] {
2290 arg := cc.args[0] or { return str }
2291 str = '\$${cc.method_name}(${arg})'
2292 }
2293 return str
2294}
2295
2296pub struct None {
2297pub:
2298 pos token.Pos
2299}
2300
2301pub enum SqlStmtKind {
2302 insert
2303 upsert
2304 update
2305 delete
2306 create
2307 drop
2308}
2309
2310pub enum SqlExprKind {
2311 insert
2312 select_
2313}
2314
2315pub type SqlQueryDataItem = SqlQueryDataIf | SqlQueryDataLeaf
2316
2317pub struct SqlQueryDataLeaf {
2318pub:
2319 pos token.Pos
2320pub mut:
2321 expr Expr
2322 pre_comments []Comment
2323 end_comments []Comment
2324}
2325
2326pub struct SqlQueryDataBranch {
2327pub:
2328 pos token.Pos
2329pub mut:
2330 cond Expr
2331 items []SqlQueryDataItem
2332 end_comments []Comment
2333}
2334
2335pub struct SqlQueryDataIf {
2336pub:
2337 pos token.Pos
2338pub mut:
2339 branches []SqlQueryDataBranch
2340 has_else bool
2341 pre_comments []Comment
2342 end_comments []Comment
2343}
2344
2345pub struct SqlQueryDataExpr {
2346pub:
2347 pos token.Pos
2348pub mut:
2349 items []SqlQueryDataItem
2350 typ Type
2351 end_comments []Comment
2352}
2353
2354pub struct SqlStmt {
2355pub:
2356 pos token.Pos
2357pub mut:
2358 lines []SqlStmtLine
2359 db_expr Expr // `db` in `sql db {`
2360 or_expr OrExpr
2361 db_expr_type Type // the type of the `db` in `sql db {`
2362}
2363
2364pub struct SqlStmtLine {
2365pub:
2366 kind SqlStmtKind
2367 pos token.Pos
2368 // is_generated indicates a statement is generated by ORM for complex queries with related tables.
2369 is_generated bool
2370 is_dynamic bool
2371 scope &Scope = unsafe { nil }
2372pub mut:
2373 object_var string // `user`
2374 updated_columns []string // for `update set x=y`
2375 is_array_insert bool
2376 is_array_update bool
2377 array_update_var string
2378 array_update_key string
2379 table_expr TypeNode
2380 fields []StructField
2381 sub_structs map[string]SqlStmtLine
2382 where_expr Expr
2383 update_exprs []Expr // for `update`
2384 update_data_expr Expr
2385 pre_comments []Comment
2386 end_comments []Comment
2387}
2388
2389// JoinKind represents the type of SQL JOIN operation
2390pub enum JoinKind {
2391 inner // INNER JOIN - returns only matching rows
2392 left // LEFT JOIN - returns all left rows, NULL for non-matching right
2393 right // RIGHT JOIN - returns all right rows, NULL for non-matching left
2394 full_outer // FULL OUTER JOIN - returns all rows from both tables
2395}
2396
2397// JoinClause represents a JOIN clause in an SQL SELECT query
2398pub struct JoinClause {
2399pub:
2400 kind JoinKind
2401 pos token.Pos
2402pub mut:
2403 table_expr TypeNode // The table being joined (e.g., Department in `join Department`)
2404 on_expr Expr // The ON condition (e.g., `User.dept_id == Department.id`)
2405}
2406
2407pub enum SqlAggregateKind {
2408 none
2409 count
2410 sum
2411 avg
2412 min
2413 max
2414}
2415
2416pub struct SqlSelectField {
2417pub:
2418 name string
2419 pos token.Pos
2420}
2421
2422pub struct SqlExpr {
2423pub:
2424 aggregate_kind SqlAggregateKind
2425 aggregate_field string
2426 is_insert bool // for insert expressions
2427 is_dynamic bool
2428 inserted_var string
2429
2430 has_where bool
2431 has_order bool
2432 has_limit bool
2433 has_offset bool
2434 has_desc bool
2435 has_distinct bool
2436 is_array bool
2437 // is_generated indicates a statement is generated by ORM for complex queries with related tables.
2438 is_generated bool
2439 pos token.Pos
2440pub mut:
2441 typ Type
2442 scope &Scope = unsafe { nil }
2443 db_expr Expr // `db` in `sql db {`
2444 where_expr Expr
2445 order_expr Expr
2446 limit_expr Expr
2447 offset_expr Expr
2448 table_expr TypeNode
2449 requested_fields []SqlSelectField
2450 fields []StructField
2451 sub_structs map[string]SqlExpr
2452 or_expr OrExpr
2453 joins []JoinClause // JOIN clauses for this query
2454 aggregate_field_type Type
2455}
2456
2457pub struct NodeError {
2458pub:
2459 idx int // index for referencing the related File error
2460 pos token.Pos
2461}
2462
2463pub fn (e Expr) type() Type {
2464 return match e {
2465 AnonFn { e.typ }
2466 ArrayDecompose { e.expr_type }
2467 ArrayInit { e.typ }
2468 AsCast { e.typ }
2469 AtExpr { string_type }
2470 BoolLiteral { bool_type }
2471 CTempVar { e.typ }
2472 CallExpr { e.return_type }
2473 CastExpr { e.typ }
2474 ChanInit { e.typ }
2475 CharLiteral { char_type }
2476 ComptimeCall { e.result_type }
2477 ComptimeSelector { e.typ }
2478 ConcatExpr { e.return_type }
2479 DumpExpr { e.expr_type }
2480 EnumVal { e.typ }
2481 FloatLiteral { float_literal_type }
2482 Ident { e.info.typ }
2483 IfExpr { e.typ }
2484 IfGuardExpr { e.expr_type }
2485 IndexExpr { e.typ }
2486 InfixExpr { e.promoted_type }
2487 IntegerLiteral { int_literal_type }
2488 IsRefType { e.typ }
2489 LambdaExpr { e.typ }
2490 Likely { e.expr.type() }
2491 LockExpr { e.typ }
2492 MapInit { e.typ }
2493 MatchExpr { e.return_type }
2494 Nil { voidptr_type }
2495 ParExpr { e.expr.type() }
2496 PostfixExpr { e.typ }
2497 PrefixExpr { e.right_type }
2498 RangeExpr { e.typ }
2499 SelectorExpr { e.typ }
2500 SizeOf { e.typ }
2501 SqlExpr { e.typ }
2502 SqlQueryDataExpr { e.typ }
2503 StringInterLiteral { string_type }
2504 StringLiteral { string_type }
2505 StructInit { e.typ }
2506 TypeNode { e.typ }
2507 TypeOf { e.typ }
2508 UnsafeExpr { e.expr.type() }
2509 else { void_type }
2510 }
2511}
2512
2513@[inline]
2514pub fn (expr Expr) is_blank_ident() bool {
2515 if expr is Ident {
2516 return expr.kind == .blank_ident
2517 }
2518 return false
2519}
2520
2521@[inline]
2522pub fn (expr Expr) is_as_cast() bool {
2523 if expr is ParExpr {
2524 return expr.expr.is_as_cast()
2525 } else if expr is SelectorExpr {
2526 return expr.expr.is_as_cast()
2527 } else {
2528 return expr is AsCast
2529 }
2530}
2531
2532__global nested_expr_pos_calls = i64(0)
2533// values above 14000 risk stack overflow by default on macos in Expr.pos() calls
2534const max_nested_expr_pos_calls = 5000
2535
2536pub fn (expr Expr) pos() token.Pos {
2537 pos_calls := stdatomic.add_i64(&nested_expr_pos_calls, 1)
2538 if pos_calls > max_nested_expr_pos_calls {
2539 $if panic_on_deeply_nested_expr_pos_calls ? {
2540 eprintln('${@LOCATION}: too many nested Expr.pos() calls: ${pos_calls}, expr type: ${expr.type_name()}')
2541 exit(1)
2542 }
2543 return token.Pos{}
2544 }
2545 defer {
2546 stdatomic.sub_i64(&nested_expr_pos_calls, 1)
2547 }
2548 // all uncommented have to be implemented
2549 // Note: please do not print here. the language server will hang
2550 // as it uses STDIO primarily to communicate ~Ned
2551 return match expr {
2552 AnonFn {
2553 expr.decl.pos
2554 }
2555 CTempVar, EmptyExpr {
2556 // println('compiler bug, unhandled EmptyExpr pos()')
2557 token.Pos{}
2558 }
2559 NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr,
2560 CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector,
2561 EnumVal, DumpExpr, FloatLiteral, GoExpr, SpawnExpr, Ident, IfExpr, IntegerLiteral,
2562 IsRefType, Likely, LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr,
2563 PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr,
2564 SqlQueryDataExpr, StringInterLiteral, StringLiteral, StructInit, TypeNode, TypeOf,
2565 UnsafeExpr, ComptimeType, LambdaExpr, Nil {
2566 expr.pos
2567 }
2568 IndexExpr {
2569 if expr.or_expr.kind != .absent {
2570 expr.or_expr.pos
2571 } else {
2572 expr.pos
2573 }
2574 }
2575 IfGuardExpr {
2576 expr.expr.pos()
2577 }
2578 InfixExpr {
2579 left_pos := expr.left.pos()
2580 right_pos := expr.right.pos()
2581 token.Pos{
2582 line_nr: expr.pos.line_nr
2583 pos: left_pos.pos
2584 len: right_pos.pos - left_pos.pos + right_pos.len
2585 col: left_pos.col
2586 last_line: right_pos.last_line
2587 }
2588 }
2589 // Please, do NOT use else{} here.
2590 // This match is exhaustive *on purpose*, to help force
2591 // maintaining/implementing proper .pos fields.
2592 }
2593}
2594
2595pub fn (expr Expr) is_constant() bool {
2596 return match expr {
2597 IntegerLiteral, FloatLiteral, BoolLiteral, StringLiteral {
2598 true
2599 }
2600 InfixExpr, CastExpr, ArrayInit {
2601 true
2602 }
2603 UnsafeExpr {
2604 expr.expr.is_constant()
2605 }
2606 else {
2607 return false
2608 }
2609 }
2610}
2611
2612pub fn (expr Expr) is_lvalue() bool {
2613 return match expr {
2614 Ident, CTempVar { true }
2615 IndexExpr { !expr.is_index_operator && expr.left.is_lvalue() }
2616 PostfixExpr { expr.op == .question && expr.expr is ComptimeSelector }
2617 SelectorExpr { expr.expr.is_lvalue() }
2618 ParExpr { expr.expr.is_lvalue() } // for var := &{...(*pointer_var)}
2619 PrefixExpr { expr.right.is_lvalue() }
2620 ComptimeSelector { expr.field_expr.is_lvalue() }
2621 else { false }
2622 }
2623}
2624
2625pub fn (expr Expr) is_expr() bool {
2626 return match expr {
2627 IfExpr, LockExpr, MatchExpr, SelectExpr { expr.is_expr }
2628 else { true }
2629 }
2630}
2631
2632pub fn (expr Expr) get_pure_type() Type {
2633 return match expr {
2634 BoolLiteral { bool_type }
2635 CharLiteral { char_type }
2636 FloatLiteral { f64_type }
2637 StringLiteral { string_type }
2638 IntegerLiteral { i64_type }
2639 else { void_type }
2640 }
2641}
2642
2643pub fn (expr Expr) is_pure_literal() bool {
2644 return match expr {
2645 BoolLiteral, CharLiteral, FloatLiteral, StringLiteral, IntegerLiteral { true }
2646 else { false }
2647 }
2648}
2649
2650pub fn (expr Expr) is_auto_deref_var() bool {
2651 return match expr {
2652 Ident {
2653 obj := expr.obj
2654 match obj {
2655 Var { obj.is_auto_deref }
2656 else { false }
2657 }
2658 }
2659 PrefixExpr {
2660 expr.op == .amp && expr.right.is_auto_deref_var()
2661 }
2662 else {
2663 false
2664 }
2665 }
2666}
2667
2668pub fn (expr Expr) is_auto_deref_arg() bool {
2669 return match expr {
2670 Ident {
2671 obj := expr.obj
2672 match obj {
2673 Var { obj.is_auto_deref && obj.is_arg }
2674 else { false }
2675 }
2676 }
2677 else {
2678 false
2679 }
2680 }
2681}
2682
2683// returns if an expression can be used as an index in `lock arr[i] {`
2684pub fn (e &Expr) is_lockable_index() bool {
2685 return match e {
2686 BoolLiteral, CharLiteral, EnumVal, FloatLiteral, IntegerLiteral, StringLiteral {
2687 true
2688 }
2689 CastExpr {
2690 e.expr.is_lockable_index()
2691 }
2692 ComptimeSelector {
2693 true
2694 }
2695 Ident {
2696 true
2697 }
2698 InfixExpr {
2699 e.left.is_lockable_index() && e.right.is_lockable_index()
2700 }
2701 ParExpr {
2702 e.expr.is_lockable_index()
2703 }
2704 PrefixExpr {
2705 e.right.is_lockable_index()
2706 }
2707 SelectorExpr {
2708 e.expr.is_lockable_index()
2709 }
2710 else {
2711 false
2712 }
2713 }
2714}
2715
2716// returns if an expression can be used in `lock x, y.z, arr[i] {`
2717pub fn (e &Expr) is_lockable() bool {
2718 return match e {
2719 Ident { true }
2720 IndexExpr { e.left.is_lockable() && e.index !is RangeExpr && e.index.is_lockable_index() }
2721 SelectorExpr { e.expr.is_lockable() }
2722 ComptimeSelector { true }
2723 else { false }
2724 }
2725}
2726
2727// returns if an expression has call expr`
2728pub fn (e &Expr) has_fn_call() bool {
2729 return match e {
2730 CallExpr { true }
2731 SelectorExpr { e.expr.has_fn_call() }
2732 else { false }
2733 }
2734}
2735
2736// CTempVar is used in cgen only, to hold nodes for temporary variables
2737pub struct CTempVar {
2738pub:
2739 name string // the name of the C temporary variable; used by g.expr(x)
2740 typ Type // the type of the original expression
2741 is_ptr bool // whether the type is a pointer
2742pub mut:
2743 orig Expr // the original expression, which produced the C temp variable; used by x.str()
2744 is_fixed_ret bool // it is an array fixed returned from call
2745}
2746
2747pub fn (node Node) pos() token.Pos {
2748 match node {
2749 NodeError {
2750 return token.Pos{}
2751 }
2752 EmptyNode {
2753 return token.Pos{}
2754 }
2755 Stmt {
2756 mut pos := node.pos
2757 if node is Import {
2758 for sym in node.syms {
2759 pos = pos.extend(sym.pos)
2760 }
2761 } else if node is TypeDecl {
2762 match node {
2763 FnTypeDecl, AliasTypeDecl {
2764 pos = pos.extend(node.type_pos)
2765 }
2766 SumTypeDecl {
2767 for variant in node.variants {
2768 pos = pos.extend(variant.pos)
2769 }
2770 }
2771 }
2772 }
2773 if node is AssignStmt {
2774 return pos.extend(node.right.last().pos())
2775 }
2776 if node is AssertStmt {
2777 return pos.extend(node.expr.pos())
2778 }
2779 return pos
2780 }
2781 Expr {
2782 return node.pos()
2783 }
2784 StructField {
2785 return node.pos.extend(node.type_pos)
2786 }
2787 MatchBranch, SelectBranch, EnumField, ConstField, StructInitField, GlobalField, CallArg {
2788 return node.pos
2789 }
2790 Param {
2791 return node.pos.extend(node.type_pos)
2792 }
2793 IfBranch {
2794 return node.pos.extend(node.body_pos)
2795 }
2796 ScopeObject {
2797 match node {
2798 ConstField, GlobalField, Var {
2799 return node.pos
2800 }
2801 EmptyScopeObject, AsmRegister {
2802 return token.Pos{
2803 len: -1
2804 line_nr: -1
2805 pos: -1
2806 last_line: -1
2807 col: 0
2808 }
2809 }
2810 }
2811 }
2812 File {
2813 mut pos := token.Pos{}
2814 if node.stmts.len > 0 {
2815 first_pos := node.stmts.first().pos
2816 last_pos := node.stmts.last().pos
2817 pos = first_pos.extend_with_last_line(last_pos, last_pos.line_nr)
2818 }
2819 return pos
2820 }
2821 }
2822}
2823
2824pub fn (node Node) children() []Node {
2825 mut children := []Node{}
2826 if node is Expr {
2827 match node {
2828 Assoc {
2829 assoc := node
2830 return assoc.exprs.map(Node(it))
2831 }
2832 ArrayInit {
2833 array_init := node
2834 return array_init.exprs.map(Node(it))
2835 }
2836 StringInterLiteral {
2837 string_inter_literal := node
2838 children << string_inter_literal.exprs.map(Node(it))
2839 for expr in string_inter_literal.fwidth_exprs {
2840 if expr !is EmptyExpr {
2841 children << expr
2842 }
2843 }
2844 for expr in string_inter_literal.precision_exprs {
2845 if expr !is EmptyExpr {
2846 children << expr
2847 }
2848 }
2849 return children
2850 }
2851 SelectorExpr {
2852 selector_expr := node
2853 children << selector_expr.expr
2854 }
2855 PostfixExpr {
2856 postfix_expr := node
2857 children << postfix_expr.expr
2858 }
2859 UnsafeExpr {
2860 unsafe_expr := node
2861 children << unsafe_expr.expr
2862 }
2863 AsCast {
2864 as_cast := node
2865 children << as_cast.expr
2866 }
2867 ParExpr {
2868 par_expr := node
2869 children << par_expr.expr
2870 }
2871 IfGuardExpr {
2872 if_guard_expr := node
2873 children << if_guard_expr.expr
2874 }
2875 SizeOf {
2876 size_of := node
2877 children << size_of.expr
2878 }
2879 Likely {
2880 likely_expr := node
2881 children << likely_expr.expr
2882 }
2883 TypeOf {
2884 type_of := node
2885 children << type_of.expr
2886 }
2887 ArrayDecompose {
2888 array_decompose := node
2889 children << array_decompose.expr
2890 }
2891 LambdaExpr {
2892 lambda_expr := node
2893 for p in lambda_expr.params {
2894 children << Node(Expr(p))
2895 }
2896 children << lambda_expr.expr
2897 }
2898 LockExpr {
2899 lock_expr := node
2900 return lock_expr.stmts.map(Node(it))
2901 }
2902 OrExpr {
2903 or_expr := node
2904 return or_expr.stmts.map(Node(it))
2905 }
2906 StructInit {
2907 struct_init := node
2908 return struct_init.init_fields.map(Node(it))
2909 }
2910 AnonFn {
2911 anon_fn := node
2912 children << Stmt(anon_fn.decl)
2913 }
2914 CallExpr {
2915 call_expr := node
2916 children << call_expr.left
2917 children << call_expr.args.map(Node(it))
2918 children << Expr(call_expr.or_block)
2919 }
2920 InfixExpr {
2921 infix_expr := node
2922 children << infix_expr.left
2923 children << infix_expr.right
2924 }
2925 PrefixExpr {
2926 prefix_expr := node
2927 children << prefix_expr.right
2928 }
2929 IndexExpr {
2930 index_expr := node
2931 children << index_expr.left
2932 if index_expr.indices.len > 0 {
2933 children << index_expr.indices.map(Node(it))
2934 } else {
2935 children << index_expr.index
2936 }
2937 }
2938 IfExpr {
2939 if_expr := node
2940 children << if_expr.left
2941 children << if_expr.branches.map(Node(it))
2942 }
2943 MatchExpr {
2944 match_expr := node
2945 children << match_expr.cond
2946 children << match_expr.branches.map(Node(it))
2947 }
2948 SelectExpr {
2949 select_expr := node
2950 return select_expr.branches.map(Node(it))
2951 }
2952 ChanInit {
2953 chan_init := node
2954 children << chan_init.cap_expr
2955 }
2956 MapInit {
2957 map_init := node
2958 children << map_init.keys.map(Node(it))
2959 children << map_init.vals.map(Node(it))
2960 }
2961 RangeExpr {
2962 range_expr := node
2963 children << range_expr.low
2964 children << range_expr.high
2965 }
2966 CastExpr {
2967 cast_expr := node
2968 children << cast_expr.expr
2969 children << cast_expr.arg
2970 }
2971 ConcatExpr {
2972 concat_expr := node
2973 return concat_expr.vals.map(Node(it))
2974 }
2975 ComptimeCall {
2976 comptime_call := node
2977 children << comptime_call.left
2978 }
2979 ComptimeSelector {
2980 comptime_selector := node
2981 children << comptime_selector.left
2982 }
2983 else {}
2984 }
2985 } else if node is Stmt {
2986 match node {
2987 Block {
2988 block := node
2989 return block.stmts.map(Node(it))
2990 }
2991 DeferStmt {
2992 defer_stmt := node
2993 return defer_stmt.stmts.map(Node(it))
2994 }
2995 ForCStmt {
2996 for_c_stmt := node
2997 return for_c_stmt.stmts.map(Node(it))
2998 }
2999 ForInStmt {
3000 for_in_stmt := node
3001 return for_in_stmt.stmts.map(Node(it))
3002 }
3003 ForStmt {
3004 for_stmt := node
3005 return for_stmt.stmts.map(Node(it))
3006 }
3007 ComptimeFor {
3008 comptime_for := node
3009 return comptime_for.stmts.map(Node(it))
3010 }
3011 ExprStmt {
3012 expr_stmt := node
3013 children << expr_stmt.expr
3014 }
3015 AssertStmt {
3016 assert_stmt := node
3017 children << assert_stmt.expr
3018 }
3019 InterfaceDecl {
3020 interface_decl := node
3021 children << interface_decl.methods.map(Node(Stmt(it)))
3022 children << interface_decl.fields.map(Node(it))
3023 }
3024 AssignStmt {
3025 assign_stmt := node
3026 children << assign_stmt.left.map(Node(it))
3027 children << assign_stmt.right.map(Node(it))
3028 }
3029 Return {
3030 return_stmt := node
3031 return return_stmt.exprs.map(Node(it))
3032 }
3033 // Note: these four decl nodes cannot be merged as one branch
3034 StructDecl {
3035 struct_decl := node
3036 return struct_decl.fields.map(Node(it))
3037 }
3038 GlobalDecl {
3039 global_decl := node
3040 return global_decl.fields.map(Node(it))
3041 }
3042 ConstDecl {
3043 const_decl := node
3044 return const_decl.fields.map(Node(it))
3045 }
3046 EnumDecl {
3047 enum_decl := node
3048 return enum_decl.fields.map(Node(it))
3049 }
3050 FnDecl {
3051 fn_decl := node
3052 if fn_decl.is_method {
3053 children << Node(fn_decl.receiver)
3054 }
3055 children << fn_decl.params.map(Node(it))
3056 children << fn_decl.stmts.map(Node(it))
3057 }
3058 TypeDecl {
3059 if node is SumTypeDecl {
3060 children << node.variants.map(Node(Expr(it)))
3061 }
3062 }
3063 else {}
3064 }
3065 } else if node is ScopeObject {
3066 match node {
3067 GlobalField {
3068 global_field := node
3069 children << global_field.expr
3070 }
3071 ConstField {
3072 const_field := node
3073 children << const_field.expr
3074 }
3075 Var {
3076 var_ := node
3077 children << var_.expr
3078 }
3079 AsmRegister, EmptyScopeObject {}
3080 }
3081 } else {
3082 match node {
3083 GlobalField {
3084 global_field := node
3085 children << global_field.expr
3086 }
3087 ConstField {
3088 const_field := node
3089 children << const_field.expr
3090 }
3091 EnumField {
3092 enum_field := node
3093 children << enum_field.expr
3094 }
3095 StructInitField {
3096 struct_init_field := node
3097 children << struct_init_field.expr
3098 }
3099 CallArg {
3100 call_arg := node
3101 children << call_arg.expr
3102 }
3103 SelectBranch {
3104 select_branch := node
3105 children << select_branch.stmt
3106 children << select_branch.stmts.map(Node(it))
3107 }
3108 IfBranch {
3109 if_branch := node
3110 return if_branch.stmts.map(Node(it))
3111 }
3112 File {
3113 file := node
3114 return file.stmts.map(Node(it))
3115 }
3116 MatchBranch {
3117 match_branch := node
3118 children << match_branch.stmts.map(Node(it))
3119 children << match_branch.exprs.map(Node(it))
3120 }
3121 else {}
3122 }
3123 }
3124 return children
3125}
3126
3127// helper for dealing with `m[k1][k2][k3][k3] = value`
3128pub fn (mut lx IndexExpr) recursive_mapset_is_setter(val bool) {
3129 lx.is_setter = val
3130 if mut lx.left is IndexExpr && lx.left.is_map {
3131 lx.left.recursive_mapset_is_setter(val)
3132 }
3133}
3134
3135pub fn (mut lx IndexExpr) recursive_arraymap_set_is_setter() {
3136 lx.is_setter = true
3137 if mut lx.left is IndexExpr {
3138 lx.left.recursive_arraymap_set_is_setter()
3139 } else if mut lx.left is SelectorExpr {
3140 if mut lx.left.expr is IndexExpr {
3141 lx.left.expr.recursive_arraymap_set_is_setter()
3142 }
3143 }
3144}
3145
3146// return all the registers for the given architecture
3147pub fn all_registers(mut t Table, arch pref.Arch) map[string]ScopeObject {
3148 mut res := map[string]ScopeObject{}
3149 match arch {
3150 ._auto {
3151 return all_registers(mut t, .amd64)
3152 }
3153 .amd64, .i386 {
3154 for bit_size, array in x86_no_number_register_list {
3155 for name in array {
3156 res[name] = AsmRegister{
3157 name: name
3158 typ: t.bitsize_to_type(bit_size)
3159 size: bit_size
3160 }
3161 }
3162 }
3163 for bit_size, array in x86_with_number_register_list {
3164 for name, max_num in array {
3165 for i in 0 .. max_num {
3166 hash_index := name.index('#') or {
3167 panic('all_registers: no hashtag found')
3168 }
3169 assembled_name := '${name[..hash_index]}${i}${name[hash_index + 1..]}'
3170 res[assembled_name] = AsmRegister{
3171 name: assembled_name
3172 typ: t.bitsize_to_type(bit_size)
3173 size: bit_size
3174 }
3175 }
3176 }
3177 }
3178 }
3179 .arm32 {
3180 arm32 := gen_all_registers(mut t, arm_no_number_register_list,
3181 arm_with_number_register_list, 32)
3182 for k, v in arm32 {
3183 res[k] = v
3184 }
3185 }
3186 .arm64 {
3187 arm64 := gen_all_registers(mut t, arm_no_number_register_list,
3188 arm_with_number_register_list, 64)
3189 for k, v in arm64 {
3190 res[k] = v
3191 }
3192 }
3193 .rv32 {
3194 rv32 := gen_all_registers(mut t, riscv_no_number_register_list,
3195 riscv_with_number_register_list, 32)
3196 for k, v in rv32 {
3197 res[k] = v
3198 }
3199 }
3200 .rv64 {
3201 rv64 := gen_all_registers(mut t, riscv_no_number_register_list,
3202 riscv_with_number_register_list, 64)
3203 for k, v in rv64 {
3204 res[k] = v
3205 }
3206 }
3207 .s390x {
3208 s390x := gen_all_registers(mut t, s390x_no_number_register_list,
3209 s390x_with_number_register_list, 64)
3210 for k, v in s390x {
3211 res[k] = v
3212 }
3213 }
3214 .ppc64le {
3215 ppc64le := gen_all_registers(mut t, ppc64le_no_number_register_list,
3216 ppc64le_with_number_register_list, 64)
3217 for k, v in ppc64le {
3218 res[k] = v
3219 }
3220 }
3221 .loongarch64 {
3222 loongarch64 := gen_all_registers(mut t, loongarch64_no_number_register_list,
3223 loongarch64_with_number_register_list, 64)
3224 for k, v in loongarch64 {
3225 res[k] = v
3226 }
3227 }
3228 .wasm32 {
3229 // no registers
3230 }
3231 else { // TODO
3232 panic('all_registers: unhandled arch: ${arch}')
3233 }
3234 }
3235
3236 return res
3237}
3238
3239// only for arm and riscv because x86 has different sized registers
3240fn gen_all_registers(mut t Table, without_numbers []string, with_numbers map[string]int, bit_size int) map[string]ScopeObject {
3241 mut res := map[string]ScopeObject{}
3242 for name in without_numbers {
3243 res[name] = AsmRegister{
3244 name: name
3245 typ: t.bitsize_to_type(bit_size)
3246 size: bit_size
3247 }
3248 }
3249 for name, max_num in with_numbers {
3250 for i in 0 .. max_num {
3251 hash_index := name.index('#') or { panic('all_registers: no hashtag found') }
3252 assembled_name := '${name[..hash_index]}${i}${name[hash_index + 1..]}'
3253 res[assembled_name] = AsmRegister{
3254 name: assembled_name
3255 typ: t.bitsize_to_type(bit_size)
3256 size: bit_size
3257 }
3258 }
3259 }
3260 return res
3261}
3262
3263pub fn (expr Expr) is_reference() bool {
3264 return match expr {
3265 PrefixExpr {
3266 expr.op == .amp
3267 }
3268 UnsafeExpr {
3269 expr.expr.is_reference()
3270 }
3271 ParExpr {
3272 expr.expr.is_reference()
3273 }
3274 else {
3275 false
3276 }
3277 }
3278}
3279
3280// remove_par removes all parenthesis and gets the innermost Expr
3281pub fn (expr Expr) remove_par() Expr {
3282 mut e := expr
3283 for e is ParExpr {
3284 e = (e as ParExpr).expr
3285 }
3286 return e
3287}
3288
3289// is `expr` a literal, i.e. it does not depend on any other declarations (C compile time constant)
3290pub fn (expr Expr) is_literal() bool {
3291 return match expr {
3292 BoolLiteral, CharLiteral, FloatLiteral, IntegerLiteral, StringLiteral, StringInterLiteral {
3293 true
3294 }
3295 PrefixExpr {
3296 expr.right.is_literal()
3297 }
3298 InfixExpr {
3299 expr.left.is_literal() && expr.right.is_literal()
3300 }
3301 ParExpr {
3302 expr.expr.is_literal()
3303 }
3304 CastExpr {
3305 !expr.has_arg && expr.expr.is_literal() && (expr.typ.is_any_kind_of_pointer()
3306 || expr.typ in [i8_type, i16_type, i32_type, int_type, i64_type, u8_type, u16_type, u32_type, u64_type, f32_type, f64_type, char_type, bool_type, rune_type])
3307 }
3308 SizeOf, IsRefType {
3309 expr.is_type || expr.expr.is_literal()
3310 }
3311 else {
3312 false
3313 }
3314 }
3315}
3316
3317@[inline]
3318pub fn (e Expr) is_nil() bool {
3319 return e is Nil || (e is UnsafeExpr && e.expr is Nil)
3320}
3321
3322@[direct_array_access]
3323pub fn type_can_start_with_token(tok &token.Token) bool {
3324 return match tok.kind {
3325 .name {
3326 (tok.lit.len > 0 && tok.lit[0].is_capital())
3327 || builtin_type_names_matcher.matches(tok.lit)
3328 }
3329 // Note: return type (T1, T2) should be handled elsewhere
3330 .amp, .key_fn, .lsbr, .question {
3331 true
3332 }
3333 else {
3334 false
3335 }
3336 }
3337}
3338
3339// validate_type_string_is_pure_literal returns `Error` if `str` can not be converted
3340// to pure literal `typ` (`i64`, `f64`, `bool`, `char` or `string`).
3341pub fn validate_type_string_is_pure_literal(typ Type, str string) ! {
3342 if typ == bool_type {
3343 if !(str == 'true' || str == 'false') {
3344 return error('bool literal `true` or `false` expected, found "${str}"')
3345 }
3346 } else if typ == char_type {
3347 if str.starts_with('\\') {
3348 if str.len <= 1 {
3349 return error('empty escape sequence found')
3350 }
3351 if !util.is_escape_sequence(str[1]) {
3352 return error('char literal escape sequence expected, found "${str}"')
3353 }
3354 } else if str.len != 1 {
3355 return error('char literal expected, found "${str}"')
3356 }
3357 } else if typ == f64_type {
3358 if str.count('.') != 1 {
3359 return error('f64 literal expected, found "${str}"')
3360 }
3361 } else if typ == string_type {
3362 } else if typ == i64_type {
3363 if !str.is_int() {
3364 return error('i64 literal expected, found "${str}"')
3365 }
3366 } else {
3367 return error('expected pure literal, found "${str}"')
3368 }
3369}
3370