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