aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/old/vlib/v/ast/ast.v
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/old/vlib/v/ast/ast.v')
-rw-r--r--v_windows/v/old/vlib/v/ast/ast.v2020
1 files changed, 2020 insertions, 0 deletions
diff --git a/v_windows/v/old/vlib/v/ast/ast.v b/v_windows/v/old/vlib/v/ast/ast.v
new file mode 100644
index 0000000..b2e1e3b
--- /dev/null
+++ b/v_windows/v/old/vlib/v/ast/ast.v
@@ -0,0 +1,2020 @@
+// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
+// Use of this source code is governed by an MIT license
+// that can be found in the LICENSE file.
+module ast
+
+import v.token
+import v.errors
+import v.pref
+
+pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl
+
+pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral |
+ CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall |
+ ComptimeSelector | ConcatExpr | DumpExpr | EmptyExpr | EnumVal | FloatLiteral | GoExpr |
+ Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | IsRefType |
+ Likely | LockExpr | MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr |
+ PostfixExpr | PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr |
+ StringInterLiteral | StringLiteral | StructInit | TypeNode | TypeOf | UnsafeExpr
+
+pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl |
+ DeferStmt | EmptyStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt |
+ GlobalDecl | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | NodeError |
+ Return | SqlStmt | StructDecl | TypeDecl
+
+// NB: when you add a new Expr or Stmt type with a .pos field, remember to update
+// the .position() token.Position methods too.
+pub type ScopeObject = AsmRegister | ConstField | GlobalField | Var
+
+// TODO: replace Param
+pub type Node = CallArg | ConstField | EmptyNode | EnumField | Expr | File | GlobalField |
+ IfBranch | MatchBranch | NodeError | Param | ScopeObject | SelectBranch | Stmt | StructField |
+ StructInitField
+
+pub struct TypeNode {
+pub:
+ typ Type
+ pos token.Position
+}
+
+pub struct EmptyExpr {
+ x int
+}
+
+pub fn empty_expr() Expr {
+ return EmptyExpr{}
+}
+
+pub struct EmptyStmt {
+pub:
+ pos token.Position
+}
+
+pub fn empty_stmt() Stmt {
+ return EmptyStmt{}
+}
+
+pub struct EmptyNode {
+ x int
+}
+
+pub fn empty_node() Node {
+ return EmptyNode{}
+}
+
+// `{stmts}` or `unsafe {stmts}`
+pub struct Block {
+pub:
+ stmts []Stmt
+ is_unsafe bool
+ pos token.Position
+}
+
+// | IncDecStmt k
+// Stand-alone expression in a statement list.
+pub struct ExprStmt {
+pub:
+ expr Expr
+ pos token.Position
+ comments []Comment
+pub mut:
+ is_expr bool
+ typ Type
+}
+
+pub struct IntegerLiteral {
+pub:
+ val string
+ pos token.Position
+}
+
+pub struct FloatLiteral {
+pub:
+ val string
+ pos token.Position
+}
+
+pub struct StringLiteral {
+pub:
+ val string
+ is_raw bool
+ language Language
+ pos token.Position
+}
+
+// 'name: $name'
+pub struct StringInterLiteral {
+pub:
+ vals []string
+ exprs []Expr
+ fwidths []int
+ precisions []int
+ pluss []bool
+ fills []bool
+ fmt_poss []token.Position
+ pos token.Position
+pub mut:
+ expr_types []Type
+ fmts []byte
+ need_fmts []bool // an explicit non-default fmt required, e.g. `x`
+}
+
+pub struct CharLiteral {
+pub:
+ val string
+ pos token.Position
+}
+
+pub struct BoolLiteral {
+pub:
+ val bool
+ pos token.Position
+}
+
+// `foo.bar`
+pub struct SelectorExpr {
+pub:
+ pos token.Position
+ field_name string
+ is_mut bool // is used for the case `if mut ident.selector is MyType {`, it indicates if the root ident is mutable
+ mut_pos token.Position
+ next_token token.Kind
+pub mut:
+ expr Expr // expr.field_name
+ expr_type Type // type of `Foo` in `Foo.bar`
+ typ Type // type of the entire thing (`Foo.bar`)
+ name_type Type // T in `T.name` or typeof in `typeof(expr).name`
+ scope &Scope
+ from_embed_type Type // holds the type of the embed that the method is called from
+}
+
+// root_ident returns the origin ident where the selector started.
+pub fn (e &SelectorExpr) root_ident() ?Ident {
+ mut root := e.expr
+ for root is SelectorExpr {
+ // TODO: remove this line
+ selector_expr := root as SelectorExpr
+ root = selector_expr.expr
+ }
+ if root is Ident {
+ return root as Ident
+ }
+
+ return none
+}
+
+// module declaration
+pub struct Module {
+pub:
+ name string // encoding.base64
+ short_name string // base64
+ attrs []Attr
+ pos token.Position
+ name_pos token.Position // `name` in import name
+ is_skipped bool // module main can be skipped in single file programs
+}
+
+pub struct StructField {
+pub:
+ pos token.Position
+ type_pos token.Position
+ comments []Comment
+ has_default_expr bool
+ attrs []Attr
+ is_pub bool
+ default_val string
+ is_mut bool
+ is_global bool
+pub mut:
+ default_expr Expr
+ default_expr_typ Type
+ name string
+ typ Type
+}
+
+/*
+pub struct Field {
+pub:
+ name string
+ pos token.Position
+pub mut:
+ typ Type
+}
+*/
+
+// const field in const declaration group
+pub struct ConstField {
+pub:
+ mod string
+ name string
+ expr Expr // the value expr of field; everything after `=`
+ is_pub bool
+ pos token.Position
+pub mut:
+ typ Type // the type of the const field, it can be any type in V
+ comments []Comment // comments before current const field
+ // the comptime_expr_value field is filled by the checker, when it has enough
+ // info to evaluate the constant at compile time
+ comptime_expr_value ComptTimeConstValue = empty_comptime_const_expr()
+}
+
+// const declaration
+pub struct ConstDecl {
+pub:
+ is_pub bool
+ pos token.Position
+pub mut:
+ fields []ConstField // all the const fields in the `const (...)` block
+ end_comments []Comment // comments that after last const field
+ is_block bool // const() block
+}
+
+pub struct StructDecl {
+pub:
+ pos token.Position
+ name string
+ generic_types []Type
+ is_pub bool
+ // _pos fields for vfmt
+ mut_pos int // mut:
+ pub_pos int // pub:
+ pub_mut_pos int // pub mut:
+ global_pos int // __global:
+ module_pos int // module:
+ language Language
+ is_union bool
+ attrs []Attr
+ end_comments []Comment
+ embeds []Embed
+pub mut:
+ fields []StructField
+}
+
+pub struct Embed {
+pub:
+ typ Type
+ pos token.Position
+ comments []Comment
+}
+
+pub struct InterfaceEmbedding {
+pub:
+ name string
+ typ Type
+ pos token.Position
+ comments []Comment
+}
+
+pub struct InterfaceDecl {
+pub:
+ name string
+ typ Type
+ name_pos token.Position
+ language Language
+ field_names []string
+ is_pub bool
+ mut_pos int // mut:
+ pos token.Position
+ pre_comments []Comment
+ generic_types []Type
+pub mut:
+ methods []FnDecl
+ fields []StructField
+ //
+ ifaces []InterfaceEmbedding
+ are_ifaces_expanded bool
+}
+
+pub struct StructInitField {
+pub:
+ pos token.Position
+ name_pos token.Position
+ comments []Comment
+ next_comments []Comment
+pub mut:
+ expr Expr
+ name string
+ typ Type
+ expected_type Type
+ parent_type Type
+}
+
+pub struct StructInitEmbed {
+pub:
+ expr Expr
+ pos token.Position
+ comments []Comment
+ next_comments []Comment
+pub mut:
+ name string
+ typ Type
+ expected_type Type
+}
+
+pub struct StructInit {
+pub:
+ pos token.Position
+ name_pos token.Position
+ is_short bool
+pub mut:
+ unresolved bool
+ pre_comments []Comment
+ typ Type
+ update_expr Expr
+ update_expr_type Type
+ update_expr_comments []Comment
+ has_update_expr bool
+ fields []StructInitField
+ embeds []StructInitEmbed
+}
+
+// import statement
+pub struct Import {
+pub:
+ mod string // the module name of the import
+ alias string // the `x` in `import xxx as x`
+ pos token.Position
+ mod_pos token.Position
+ alias_pos token.Position
+ syms_pos token.Position
+pub mut:
+ syms []ImportSymbol // the list of symbols in `import {symbol1, symbol2}`
+ comments []Comment
+ next_comments []Comment
+}
+
+// import symbol,for import {symbol} syntax
+pub struct ImportSymbol {
+pub:
+ pos token.Position
+ name string
+}
+
+// anonymous function
+pub struct AnonFn {
+pub mut:
+ decl FnDecl
+ typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
+ has_gen bool // has been generated
+}
+
+// function or method declaration
+pub struct FnDecl {
+pub:
+ name string
+ mod string
+ is_deprecated bool
+ is_pub bool
+ is_variadic bool
+ is_anon bool
+ is_noreturn bool // true, when [noreturn] is used on a fn
+ is_manualfree bool // true, when [manualfree] is used on a fn
+ is_main bool // true for `fn main()`
+ is_test bool // true for `fn test_abcde`
+ is_conditional bool // true for `[if abc] fn abc(){}`
+ is_exported bool // true for `[export: 'exact_C_name']`
+ is_keep_alive bool // passed memory must not be freed (by GC) before function returns
+ is_unsafe bool // true, when [unsafe] is used on a fn
+ receiver StructField // TODO this is not a struct field
+ receiver_pos token.Position // `(u User)` in `fn (u User) name()` position
+ is_method bool
+ method_type_pos token.Position // `User` in ` fn (u User)` position
+ method_idx int
+ rec_mut bool // is receiver mutable
+ rec_share ShareType
+ language Language
+ no_body bool // just a definition `fn C.malloc()`
+ is_builtin bool // this function is defined in builtin/strconv
+ body_pos token.Position // function bodys position
+ file string
+ generic_names []string
+ is_direct_arr bool // direct array access
+ attrs []Attr
+ ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
+pub mut:
+ params []Param
+ stmts []Stmt
+ defer_stmts []DeferStmt
+ return_type Type
+ return_type_pos token.Position // `string` in `fn (u User) name() string` position
+ has_return bool
+ //
+ comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl
+ next_comments []Comment // coments that are one line after the decl; used for InterfaceDecl
+ //
+ source_file &File = 0
+ scope &Scope
+ label_names []string
+ pos token.Position // function declaration position
+}
+
+// break, continue
+pub struct BranchStmt {
+pub:
+ kind token.Kind
+ label string
+ pos token.Position
+}
+
+// function or method call expr
+pub struct CallExpr {
+pub:
+ pos token.Position
+ name_pos token.Position
+ mod string
+pub mut:
+ name string // left.name()
+ is_method bool
+ is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
+ is_keep_alive bool // GC must not free arguments before fn returns
+ is_noreturn bool // whether the function/method is marked as [noreturn]
+ args []CallArg
+ expected_arg_types []Type
+ language Language
+ or_block OrExpr
+ left Expr // `user` in `user.register()`
+ left_type Type // type of `user`
+ receiver_type Type // User
+ return_type Type
+ should_be_skipped bool
+ concrete_types []Type // concrete types, e.g. <int, string>
+ concrete_list_pos token.Position
+ free_receiver bool // true if the receiver expression needs to be freed
+ scope &Scope
+ from_embed_type Type // holds the type of the embed that the method is called from
+ comments []Comment
+}
+
+/*
+pub struct AutofreeArgVar {
+ name string
+ idx int
+}
+*/
+// function call argument: `f(callarg)`
+pub struct CallArg {
+pub:
+ is_mut bool
+ share ShareType
+ comments []Comment
+pub mut:
+ expr Expr
+ typ Type
+ 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
+ pos token.Position
+ // tmp_name string // for autofree
+}
+
+// function return statement
+pub struct Return {
+pub:
+ pos token.Position
+ comments []Comment
+pub mut:
+ exprs []Expr
+ types []Type
+}
+
+/*
+pub enum Expr {
+ Binary(InfixExpr)
+ If(IfExpr)
+ Integer(IntegerExpr)
+}
+*/
+/*
+pub struct Stmt {
+ pos int
+ //end int
+}
+*/
+pub struct Var {
+pub:
+ name string
+ expr Expr
+ share ShareType
+ is_mut bool
+ is_autofree_tmp bool
+ is_arg bool // fn args should not be autofreed
+ is_auto_deref bool
+pub mut:
+ typ Type
+ orig_type Type // original sumtype type; 0 if it's not a sumtype
+ smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
+ // TODO: move this to a real docs site later
+ // 10 <- original type (orig_type)
+ // [11, 12, 13] <- cast order (smartcasts)
+ // 12 <- the current casted type (typ)
+ pos token.Position
+ is_used bool
+ is_changed bool // to detect mutable vars that are never changed
+ //
+ // (for setting the position after the or block for autofree)
+ is_or bool // `x := foo() or { ... }`
+ is_tmp bool // for tmp for loop vars, so that autofree can skip them
+ is_auto_heap bool // value whoes address goes out of scope
+ is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not [heap] struct)
+}
+
+// used for smartcasting only
+// struct fields change type in scopes
+pub struct ScopeStructField {
+pub:
+ struct_type Type // type of struct
+ name string
+ pos token.Position
+ typ Type
+ smartcasts []Type // nested sum types require nested smart casting, for that a list of types is needed
+ orig_type Type // original sumtype type; 0 if it's not a sumtype
+ // TODO: move this to a real docs site later
+ // 10 <- original type (orig_type)
+ // [11, 12, 13] <- cast order (smartcasts)
+ // 12 <- the current casted type (typ)
+}
+
+pub struct GlobalField {
+pub:
+ name string
+ has_expr bool
+ pos token.Position
+ typ_pos token.Position
+pub mut:
+ expr Expr
+ typ Type
+ comments []Comment
+}
+
+pub struct GlobalDecl {
+pub:
+ mod string
+ pos token.Position
+ is_block bool // __global() block
+pub mut:
+ fields []GlobalField
+ end_comments []Comment
+}
+
+pub struct EmbeddedFile {
+pub:
+ rpath string // used in the source code, as an ID/key to the embed
+ apath string // absolute path during compilation to the resource
+}
+
+// Each V source file is represented by one File structure.
+// When the V compiler runs, the parser will fill an []File.
+// That array is then passed to V's checker.
+[heap]
+pub struct File {
+pub:
+ nr_lines int // number of source code lines in the file (including newlines and comments)
+ nr_bytes int // number of processed source code bytes
+ mod Module // the module of the source file (from `module xyz` at the top)
+ global_scope &Scope
+ is_test bool // true for _test.v files
+pub mut:
+ path string // absolute path of the source file - '/projects/v/file.v'
+ path_base string // file name - 'file.v' (useful for tracing)
+ scope &Scope
+ stmts []Stmt // all the statements in the source file
+ imports []Import // all the imports
+ auto_imports []string // imports that were implicitely added
+ embedded_files []EmbeddedFile // list of files to embed in the binary
+ imported_symbols map[string]string // used for `import {symbol}`, it maps symbol => module.symbol
+ errors []errors.Error // all the checker errors in the file
+ warnings []errors.Warning // all the checker warnings in the file
+ notices []errors.Notice // all the checker notices in the file
+ generic_fns []&FnDecl
+ global_labels []string // from `asm { .globl labelname }`
+}
+
+[unsafe]
+pub fn (f &File) free() {
+ unsafe {
+ f.path.free()
+ f.path_base.free()
+ f.scope.free()
+ f.stmts.free()
+ f.imports.free()
+ f.auto_imports.free()
+ f.embedded_files.free()
+ f.imported_symbols.free()
+ f.errors.free()
+ f.warnings.free()
+ f.notices.free()
+ f.global_labels.free()
+ }
+}
+
+pub struct IdentFn {
+pub mut:
+ typ Type
+}
+
+// TODO: (joe) remove completely, use ident.obj
+// instead which points to the scope object
+pub struct IdentVar {
+pub mut:
+ typ Type
+ is_mut bool
+ is_static bool
+ is_optional bool
+ share ShareType
+}
+
+pub type IdentInfo = IdentFn | IdentVar
+
+pub enum IdentKind {
+ unresolved
+ blank_ident
+ variable
+ constant
+ global
+ function
+}
+
+// A single identifier
+pub struct Ident {
+pub:
+ language Language
+ tok_kind token.Kind
+ pos token.Position
+ mut_pos token.Position
+ comptime bool
+pub mut:
+ scope &Scope
+ obj ScopeObject
+ mod string
+ name string
+ kind IdentKind
+ info IdentInfo
+ is_mut bool
+}
+
+pub fn (i &Ident) var_info() IdentVar {
+ match mut i.info {
+ IdentVar {
+ return i.info
+ }
+ else {
+ // return IdentVar{}
+ panic('Ident.var_info(): info is not IdentVar variant')
+ }
+ }
+}
+
+// left op right
+// See: token.Kind.is_infix
+pub struct InfixExpr {
+pub:
+ op token.Kind
+ pos token.Position
+ is_stmt bool
+pub mut:
+ left Expr
+ right Expr
+ left_type Type
+ right_type Type
+ auto_locked string
+ or_block OrExpr
+}
+
+// ++, --
+pub struct PostfixExpr {
+pub:
+ op token.Kind
+ expr Expr
+ pos token.Position
+pub mut:
+ auto_locked string
+}
+
+// See: token.Kind.is_prefix
+pub struct PrefixExpr {
+pub:
+ op token.Kind
+ pos token.Position
+pub mut:
+ right_type Type
+ right Expr
+ or_block OrExpr
+ is_option bool // IfGuard
+}
+
+pub struct IndexExpr {
+pub:
+ pos token.Position
+ index Expr // [0], RangeExpr [start..end] or map[key]
+ or_expr OrExpr
+pub mut:
+ left Expr
+ left_type Type // array, map, fixed array
+ is_setter bool
+ is_map bool
+ is_array bool
+ is_farray bool
+ is_option bool // IfGuard
+}
+
+pub struct IfExpr {
+pub:
+ is_comptime bool
+ tok_kind token.Kind
+ left Expr // `a` in `a := if ...`
+ pos token.Position
+ post_comments []Comment
+pub mut:
+ branches []IfBranch // includes all `else if` branches
+ is_expr bool
+ typ Type
+ has_else bool
+ // implements bool // comptime $if implements interface
+}
+
+pub struct IfBranch {
+pub:
+ cond Expr
+ pos token.Position
+ body_pos token.Position
+ comments []Comment
+pub mut:
+ pkg_exist bool
+ stmts []Stmt
+ scope &Scope
+}
+
+pub struct UnsafeExpr {
+pub:
+ expr Expr
+ pos token.Position
+}
+
+pub struct LockExpr {
+pub:
+ stmts []Stmt
+ is_rlock []bool
+ pos token.Position
+pub mut:
+ lockeds []Expr // `x`, `y.z` in `lock x, y.z {`
+ comments []Comment
+ is_expr bool
+ typ Type
+ scope &Scope
+}
+
+pub struct MatchExpr {
+pub:
+ tok_kind token.Kind
+ cond Expr
+ branches []MatchBranch
+ pos token.Position
+ comments []Comment // comments before the first branch
+pub mut:
+ is_expr bool // returns a value
+ return_type Type
+ cond_type Type // type of `x` in `match x {`
+ expected_type Type // for debugging only
+ is_sum_type bool
+}
+
+pub struct MatchBranch {
+pub:
+ ecmnts [][]Comment // inline comments for each left side expr
+ stmts []Stmt // right side
+ pos token.Position
+ is_else bool
+ post_comments []Comment // comments below ´... }´
+ branch_pos token.Position // for checker errors about invalid branches
+pub mut:
+ exprs []Expr // left side
+ scope &Scope
+}
+
+pub struct SelectExpr {
+pub:
+ branches []SelectBranch
+ pos token.Position
+ has_exception bool
+pub mut:
+ is_expr bool // returns a value
+ expected_type Type // for debugging only
+}
+
+pub struct SelectBranch {
+pub:
+ stmt Stmt // `a := <-ch` or `ch <- a`
+ stmts []Stmt // right side
+ pos token.Position
+ comment Comment // comment above `select {`
+ is_else bool
+ is_timeout bool
+ post_comments []Comment
+}
+
+pub enum CompForKind {
+ methods
+ fields
+ attributes
+}
+
+pub struct CompFor {
+pub:
+ val_var string
+ stmts []Stmt
+ kind CompForKind
+ pos token.Position
+ typ_pos token.Position
+pub mut:
+ // expr Expr
+ typ Type
+}
+
+pub struct ForStmt {
+pub:
+ cond Expr
+ stmts []Stmt
+ is_inf bool // `for {}`
+ pos token.Position
+pub mut:
+ label string // `label: for {`
+ scope &Scope
+}
+
+pub struct ForInStmt {
+pub:
+ key_var string
+ val_var string
+ cond Expr
+ is_range bool
+ high Expr // `10` in `for i in 0..10 {`
+ stmts []Stmt
+ pos token.Position
+ val_is_mut bool // `for mut val in vals {` means that modifying `val` will modify the array
+ // and the array cannot be indexed inside the loop
+pub mut:
+ key_type Type
+ val_type Type
+ cond_type Type
+ kind Kind // array/map/string
+ label string // `label: for {`
+ scope &Scope
+}
+
+pub struct ForCStmt {
+pub:
+ init Stmt // i := 0;
+ has_init bool
+ cond Expr // i < 10;
+ has_cond bool
+ inc Stmt // i++; i += 2
+ has_inc bool
+ is_multi bool // for a,b := 0,1; a < 10; a,b = a+b, a {...}
+ stmts []Stmt
+ pos token.Position
+pub mut:
+ label string // `label: for {`
+ scope &Scope
+}
+
+// #include, #define etc
+pub struct HashStmt {
+pub:
+ mod string
+ pos token.Position
+ source_file string
+pub mut:
+ val string // example: 'include <openssl/rand.h> # please install openssl // comment'
+ kind string // : 'include'
+ main string // : '<openssl/rand.h>'
+ msg string // : 'please install openssl'
+ ct_conds []Expr // *all* comptime conditions, that must be true, for the hash to be processed
+ // ct_conds is filled by the checker, based on the current nesting of `$if cond1 {}` blocks
+}
+
+/*
+// filter(), map(), sort()
+pub struct Lambda {
+pub:
+ name string
+}
+*/
+// variable assign statement
+pub struct AssignStmt {
+pub:
+ op token.Kind // include: =,:=,+=,-=,*=,/= and so on; for a list of all the assign operators, see vlib/token/token.v
+ pos token.Position
+ comments []Comment
+ end_comments []Comment
+pub mut:
+ right []Expr
+ left []Expr
+ left_types []Type
+ right_types []Type
+ is_static bool // for translated code only
+ is_simple bool // `x+=2` in `for x:=1; ; x+=2`
+ has_cross_var bool
+}
+
+// `expr as Ident`
+pub struct AsCast {
+pub:
+ expr Expr // from expr: `expr` in `expr as Ident`
+ typ Type // to type
+ pos token.Position
+pub mut:
+ expr_type Type // from type
+}
+
+// an enum value, like OS.macos or .macos
+pub struct EnumVal {
+pub:
+ enum_name string
+ val string
+ mod string // for full path `mod_Enum_val`
+ pos token.Position
+pub mut:
+ typ Type
+}
+
+// enum field in enum declaration
+pub struct EnumField {
+pub:
+ name string
+ pos token.Position
+ comments []Comment // comment after Enumfield in the same line
+ next_comments []Comment // comments between current EnumField and next EnumField
+ expr Expr // the value of current EnumField; 123 in `ename = 123`
+ has_expr bool // true, when .expr has a value
+}
+
+// enum declaration
+pub struct EnumDecl {
+pub:
+ name string
+ is_pub bool
+ is_flag bool // true when the enum has [flag] tag,for bit field enum
+ is_multi_allowed bool // true when the enum has [_allow_multiple_values] tag
+ comments []Comment // comments before the first EnumField
+ fields []EnumField // all the enum fields
+ attrs []Attr // attributes of enum declaration
+ pos token.Position
+}
+
+pub struct AliasTypeDecl {
+pub:
+ name string
+ is_pub bool
+ parent_type Type
+ pos token.Position
+ type_pos token.Position
+ comments []Comment
+}
+
+// New implementation of sum types
+pub struct SumTypeDecl {
+pub:
+ name string
+ is_pub bool
+ pos token.Position
+ comments []Comment
+ typ Type
+ generic_types []Type
+pub mut:
+ variants []TypeNode
+}
+
+pub struct FnTypeDecl {
+pub:
+ name string
+ is_pub bool
+ typ Type
+ pos token.Position
+ type_pos token.Position
+ comments []Comment
+}
+
+// TODO: handle this differently
+// v1 excludes non current os ifdefs so
+// the defer's never get added in the first place
+pub struct DeferStmt {
+pub:
+ stmts []Stmt
+ pos token.Position
+pub mut:
+ defer_vars []Ident
+ ifdef string
+ idx_in_fn int = -1 // index in FnDecl.defer_stmts
+}
+
+// `(3+4)`
+pub struct ParExpr {
+pub:
+ expr Expr
+ pos token.Position
+}
+
+pub struct GoExpr {
+pub:
+ pos token.Position
+pub mut:
+ call_expr CallExpr
+ is_expr bool
+}
+
+pub struct GotoLabel {
+pub:
+ name string
+ pos token.Position
+}
+
+pub struct GotoStmt {
+pub:
+ name string
+ pos token.Position
+}
+
+pub struct ArrayInit {
+pub:
+ pos token.Position // `[]` in []Type{} position
+ elem_type_pos token.Position // `Type` in []Type{} position
+ exprs []Expr // `[expr, expr]` or `[expr]Type{}` for fixed array
+ ecmnts [][]Comment // optional iembed comments after each expr
+ pre_cmnts []Comment
+ is_fixed bool
+ has_val bool // fixed size literal `[expr, expr]!`
+ mod string
+ len_expr Expr // len: expr
+ cap_expr Expr // cap: expr
+ default_expr Expr // init: expr
+ has_len bool
+ has_cap bool
+ has_default bool
+pub mut:
+ expr_types []Type // [Dog, Cat] // also used for interface_types
+ elem_type Type // element type
+ typ Type // array type
+}
+
+pub struct ArrayDecompose {
+pub:
+ expr Expr
+ pos token.Position
+pub mut:
+ expr_type Type
+ arg_type Type
+}
+
+pub struct ChanInit {
+pub:
+ pos token.Position
+ cap_expr Expr
+ has_cap bool
+pub mut:
+ typ Type
+ elem_type Type
+}
+
+pub struct MapInit {
+pub:
+ pos token.Position
+ keys []Expr
+ vals []Expr
+ comments [][]Comment // comments after key-value pairs
+ pre_cmnts []Comment // comments before the first key-value pair
+pub mut:
+ typ Type
+ key_type Type
+ value_type Type
+}
+
+// s[10..20]
+pub struct RangeExpr {
+pub:
+ low Expr
+ high Expr
+ has_high bool
+ has_low bool
+ pos token.Position
+}
+
+// NB: &string(x) gets parsed as PrefixExpr{ right: CastExpr{...} }
+// TODO: that is very likely a parsing bug. It should get parsed as just
+// CastExpr{...}, where .typname is '&string' instead.
+// The current situation leads to special cases in vfmt and cgen
+// (see prefix_expr_cast_expr in fmt.v, and .is_amp in cgen.v)
+// .in_prexpr is also needed because of that, because the checker needs to
+// show warnings about the deprecated C->V conversions `string(x)` and
+// `string(x,y)`, while skipping the real pointer casts like `&string(x)`.
+// 2021/07/17: TODO: since 6edfb2c, the above is fixed at the parser level,
+// we need to remove the hacks/special cases in vfmt and the checker too.
+pub struct CastExpr {
+pub:
+ arg Expr // `n` in `string(buf, n)`
+pub mut:
+ typ Type // `string`
+ expr Expr // `buf` in `string(buf, n)` and `&Type(buf)`
+ typname string // `&Type` in `&Type(buf)`
+ expr_type Type // `byteptr`, the type of the `buf` expression
+ has_arg bool // true for `string(buf, n)`, false for `&Type(buf)`
+ pos token.Position
+}
+
+pub struct AsmStmt {
+pub:
+ arch pref.Arch
+ is_basic bool
+ is_volatile bool
+ is_goto bool
+ clobbered []AsmClobbered
+ pos token.Position
+pub mut:
+ templates []AsmTemplate
+ scope &Scope
+ output []AsmIO
+ input []AsmIO
+ global_labels []string // labels defined in assembly block, exported with `.globl`
+ local_labels []string // local to the assembly block
+}
+
+pub struct AsmTemplate {
+pub mut:
+ name string
+ is_label bool // `example_label:`
+ is_directive bool // .globl assembly_function
+ args []AsmArg
+ comments []Comment
+ pos token.Position
+}
+
+// [eax+5] | j | displacement literal (e.g. 123 in [rax + 123] ) | eax | true | `a` | 0.594 | 123 | label_name
+pub type AsmArg = AsmAddressing | AsmAlias | AsmDisp | AsmRegister | BoolLiteral | CharLiteral |
+ FloatLiteral | IntegerLiteral | string
+
+pub struct AsmRegister {
+pub mut:
+ name string // eax or r12d etc.
+ typ Type
+ size int
+}
+
+pub struct AsmDisp {
+pub:
+ val string
+ pos token.Position
+}
+
+pub struct AsmAlias {
+pub:
+ pos token.Position
+pub mut:
+ name string // a
+}
+
+pub struct AsmAddressing {
+pub:
+ scale int = -1 // 1, 2, 4, or 8 literal
+ mode AddressingMode
+ pos token.Position
+pub mut:
+ displacement AsmArg // 8, 16 or 32 bit literal value
+ base AsmArg // gpr
+ index AsmArg // gpr
+}
+
+// adressing modes:
+pub enum AddressingMode {
+ invalid
+ displacement // displacement
+ base // base
+ base_plus_displacement // base + displacement
+ index_times_scale_plus_displacement // (index ∗ scale) + displacement
+ base_plus_index_plus_displacement // base + (index ∗ scale) + displacement
+ base_plus_index_times_scale_plus_displacement // base + index + displacement
+ rip_plus_displacement // rip + displacement
+}
+
+pub struct AsmClobbered {
+pub mut:
+ reg AsmRegister
+ comments []Comment
+}
+
+// : [alias_a] '=r' (a) // this is a comment
+pub struct AsmIO {
+pub:
+ alias string // [alias_a]
+ constraint string // '=r' TODO: allow all backends to easily use this with a struct
+ expr Expr // (a)
+ comments []Comment // // this is a comment
+ typ Type
+ pos token.Position
+}
+
+pub const (
+ // reference: https://en.wikipedia.org/wiki/X86#/media/File:Table_of_x86_Registers_svg.svg
+ // map register size -> register name
+ x86_no_number_register_list = map{
+ 8: ['al', 'ah', 'bl', 'bh', 'cl', 'ch', 'dl', 'dh', 'bpl', 'sil', 'dil', 'spl']
+ 16: ['ax', 'bx', 'cx', 'dx', 'bp', 'si', 'di', 'sp', /* segment registers */ 'cs', 'ss',
+ 'ds', 'es', 'fs', 'gs', 'flags', 'ip', /* task registers */ 'gdtr', 'idtr', 'tr', 'ldtr',
+ // CSR register 'msw', /* FP core registers */ 'cw', 'sw', 'tw', 'fp_ip', 'fp_dp',
+ 'fp_cs', 'fp_ds', 'fp_opc']
+ 32: [
+ 'eax',
+ 'ebx',
+ 'ecx',
+ 'edx',
+ 'ebp',
+ 'esi',
+ 'edi',
+ 'esp',
+ 'eflags',
+ 'eip', /* CSR register */
+ 'mxcsr' /* 32-bit FP core registers 'fp_dp', 'fp_ip' (TODO: why are there duplicates?) */,
+ ]
+ 64: ['rax', 'rbx', 'rcx', 'rdx', 'rbp', 'rsi', 'rdi', 'rsp', 'rflags', 'rip']
+ }
+ // no comments because maps do not support comments
+ // r#*: gp registers added in 64-bit extensions, can only be from 8-15 actually
+ // *mm#: vector/simd registors
+ // st#: floating point numbers
+ // cr#: control/status registers
+ // dr#: debug registers
+ x86_with_number_register_list = map{
+ 8: map{
+ 'r#b': 16
+ }
+ 16: map{
+ 'r#w': 16
+ }
+ 32: map{
+ 'r#d': 16
+ }
+ 64: map{
+ 'r#': 16
+ 'mm#': 16
+ 'cr#': 16
+ 'dr#': 16
+ }
+ 80: map{
+ 'st#': 16
+ }
+ 128: map{
+ 'xmm#': 32
+ }
+ 256: map{
+ 'ymm#': 32
+ }
+ 512: map{
+ 'zmm#': 32
+ }
+ }
+)
+
+// TODO: saved priviled registers for arm
+pub const (
+ arm_no_number_register_list = ['fp' /* aka r11 */, /* not instruction pointer: */ 'ip' /* aka r12 */,
+ 'sp' /* aka r13 */, 'lr' /* aka r14 */, /* this is instruction pointer ('program counter'): */
+ 'pc' /* aka r15 */,
+ ] // 'cpsr' and 'apsr' are special flags registers, but cannot be referred to directly
+ arm_with_number_register_list = map{
+ 'r#': 16
+ }
+)
+
+pub const (
+ riscv_no_number_register_list = ['zero', 'ra', 'sp', 'gp', 'tp']
+ riscv_with_number_register_list = map{
+ 'x#': 32
+ 't#': 3
+ 's#': 12
+ 'a#': 8
+ }
+)
+
+pub struct AssertStmt {
+pub:
+ pos token.Position
+pub mut:
+ expr Expr
+ is_used bool // asserts are used in _test.v files, as well as in non -prod builds of all files
+}
+
+// `if [x := opt()] {`
+pub struct IfGuardExpr {
+pub:
+ var_name string
+ pos token.Position
+pub mut:
+ expr Expr
+ expr_type Type
+}
+
+pub enum OrKind {
+ absent
+ block
+ propagate
+}
+
+// `or { ... }`
+pub struct OrExpr {
+pub:
+ stmts []Stmt
+ kind OrKind
+ pos token.Position
+}
+
+/*
+// `or { ... }`
+pub struct OrExpr2 {
+pub:
+ call_expr CallExpr
+ stmts []Stmt // inside `or { }`
+ kind OrKind
+ pos token.Position
+}
+*/
+
+// deprecated
+pub struct Assoc {
+pub:
+ var_name string
+ fields []string
+ exprs []Expr
+ pos token.Position
+pub mut:
+ typ Type
+ scope &Scope
+}
+
+pub struct SizeOf {
+pub:
+ is_type bool
+ expr Expr // checker uses this to set typ
+ pos token.Position
+pub mut:
+ typ Type
+}
+
+pub struct IsRefType {
+pub:
+ is_type bool
+ expr Expr // checker uses this to set typ
+ pos token.Position
+pub mut:
+ typ Type
+}
+
+pub struct OffsetOf {
+pub:
+ struct_type Type
+ field string
+ pos token.Position
+}
+
+pub struct Likely {
+pub:
+ expr Expr
+ pos token.Position
+ is_likely bool // false for _unlikely_
+}
+
+pub struct TypeOf {
+pub:
+ expr Expr
+ pos token.Position
+pub mut:
+ expr_type Type
+}
+
+pub struct DumpExpr {
+pub:
+ expr Expr
+ pos token.Position
+pub mut:
+ expr_type Type
+ cname string // filled in the checker
+}
+
+pub struct Comment {
+pub:
+ text string
+ is_multi bool // true only for /* comment */, that use many lines
+ is_inline bool // true for all /* comment */ comments
+ pos token.Position
+}
+
+pub struct ConcatExpr {
+pub:
+ vals []Expr
+ pos token.Position
+pub mut:
+ return_type Type
+}
+
+// @FN, @STRUCT, @MOD etc. See full list in token.valid_at_tokens
+pub struct AtExpr {
+pub:
+ name string
+ pos token.Position
+ kind token.AtKind
+pub mut:
+ val string
+}
+
+pub struct ComptimeSelector {
+pub:
+ has_parens bool // if $() is used, for vfmt
+ left Expr
+ field_expr Expr
+ pos token.Position
+pub mut:
+ left_type Type
+ typ Type
+}
+
+pub struct ComptimeCall {
+pub:
+ pos token.Position
+ has_parens bool // if $() is used, for vfmt
+ method_name string
+ method_pos token.Position
+ scope &Scope
+ left Expr
+ args_var string
+ //
+ is_vweb bool
+ vweb_tmpl File
+ //
+ is_embed bool
+ embed_file EmbeddedFile
+ //
+ is_env bool
+ env_pos token.Position
+ //
+ is_pkgconfig bool
+pub mut:
+ sym TypeSymbol
+ result_type Type
+ env_value string
+ args []CallArg
+}
+
+pub struct None {
+pub:
+ pos token.Position
+}
+
+pub enum SqlStmtKind {
+ insert
+ update
+ delete
+ create
+ drop
+}
+
+pub struct SqlStmt {
+pub:
+ pos token.Position
+ db_expr Expr // `db` in `sql db {`
+pub mut:
+ lines []SqlStmtLine
+}
+
+pub struct SqlStmtLine {
+pub:
+ kind SqlStmtKind
+ pos token.Position
+ where_expr Expr
+ update_exprs []Expr // for `update`
+pub mut:
+ object_var_name string // `user`
+ updated_columns []string // for `update set x=y`
+ table_expr TypeNode
+ fields []StructField
+ sub_structs map[int]SqlStmtLine
+}
+
+pub struct SqlExpr {
+pub:
+ typ Type
+ is_count bool
+ db_expr Expr // `db` in `sql db {`
+ has_where bool
+ has_offset bool
+ offset_expr Expr
+ has_order bool
+ order_expr Expr
+ has_desc bool
+ is_array bool
+ pos token.Position
+ has_limit bool
+ limit_expr Expr
+pub mut:
+ where_expr Expr
+ table_expr TypeNode
+ fields []StructField
+ sub_structs map[int]SqlExpr
+}
+
+pub struct NodeError {
+pub:
+ idx int // index for referencing the related File error
+ pos token.Position
+}
+
+[inline]
+pub fn (expr Expr) is_blank_ident() bool {
+ match expr {
+ Ident { return expr.kind == .blank_ident }
+ else { return false }
+ }
+}
+
+pub fn (expr Expr) position() token.Position {
+ // all uncommented have to be implemented
+ // NB: please do not print here. the language server will hang
+ // as it uses STDIO primarly to communicate ~Ned
+ match expr {
+ AnonFn {
+ return expr.decl.pos
+ }
+ EmptyExpr {
+ // println('compiler bug, unhandled EmptyExpr position()')
+ return token.Position{}
+ }
+ NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr,
+ CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector,
+ EnumVal, DumpExpr, FloatLiteral, GoExpr, Ident, IfExpr, IntegerLiteral, IsRefType, Likely,
+ LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr,
+ RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral,
+ StructInit, TypeNode, TypeOf, UnsafeExpr {
+ return expr.pos
+ }
+ IndexExpr {
+ if expr.or_expr.kind != .absent {
+ return expr.or_expr.pos
+ }
+ return expr.pos
+ }
+ IfGuardExpr {
+ return expr.expr.position()
+ }
+ InfixExpr {
+ left_pos := expr.left.position()
+ right_pos := expr.right.position()
+ return token.Position{
+ line_nr: expr.pos.line_nr
+ pos: left_pos.pos
+ len: right_pos.pos - left_pos.pos + right_pos.len
+ col: left_pos.col
+ last_line: right_pos.last_line
+ }
+ }
+ CTempVar {
+ return token.Position{}
+ }
+ // Please, do NOT use else{} here.
+ // This match is exhaustive *on purpose*, to help force
+ // maintaining/implementing proper .pos fields.
+ }
+}
+
+pub fn (expr Expr) is_lvalue() bool {
+ match expr {
+ Ident { return true }
+ CTempVar { return true }
+ IndexExpr { return expr.left.is_lvalue() }
+ SelectorExpr { return expr.expr.is_lvalue() }
+ ParExpr { return expr.expr.is_lvalue() } // for var := &{...(*pointer_var)}
+ PrefixExpr { return expr.right.is_lvalue() }
+ else {}
+ }
+ return false
+}
+
+pub fn (expr Expr) is_expr() bool {
+ match expr {
+ IfExpr { return expr.is_expr }
+ LockExpr { return expr.is_expr }
+ MatchExpr { return expr.is_expr }
+ SelectExpr { return expr.is_expr }
+ else {}
+ }
+ return true
+}
+
+pub fn (expr Expr) is_lit() bool {
+ return match expr {
+ BoolLiteral, CharLiteral, StringLiteral, IntegerLiteral { true }
+ else { false }
+ }
+}
+
+pub fn (expr Expr) is_auto_deref_var() bool {
+ match expr {
+ Ident {
+ if expr.obj is Var {
+ if expr.obj.is_auto_deref {
+ return true
+ }
+ }
+ }
+ PrefixExpr {
+ if expr.op == .amp && expr.right.is_auto_deref_var() {
+ return true
+ }
+ }
+ else {}
+ }
+ return false
+}
+
+// returns if an expression can be used in `lock x, y.z {`
+pub fn (e &Expr) is_lockable() bool {
+ match e {
+ Ident {
+ return true
+ }
+ SelectorExpr {
+ return e.expr.is_lockable()
+ }
+ else {
+ return false
+ }
+ }
+}
+
+// check if stmt can be an expression in C
+pub fn (stmt Stmt) check_c_expr() ? {
+ match stmt {
+ AssignStmt {
+ return
+ }
+ ExprStmt {
+ if stmt.expr.is_expr() {
+ return
+ }
+ return error('unsupported statement (`$stmt.expr.type_name()`)')
+ }
+ else {}
+ }
+ return error('unsupported statement (`$stmt.type_name()`)')
+}
+
+// CTempVar is used in cgen only, to hold nodes for temporary variables
+pub struct CTempVar {
+pub:
+ name string // the name of the C temporary variable; used by g.expr(x)
+ orig Expr // the original expression, which produced the C temp variable; used by x.str()
+ typ Type // the type of the original expression
+ is_ptr bool // whether the type is a pointer
+}
+
+pub fn (node Node) position() token.Position {
+ match node {
+ NodeError {
+ return token.Position{}
+ }
+ EmptyNode {
+ return token.Position{}
+ }
+ Stmt {
+ mut pos := node.pos
+ if node is Import {
+ for sym in node.syms {
+ pos = pos.extend(sym.pos)
+ }
+ } else if node is TypeDecl {
+ match node {
+ FnTypeDecl, AliasTypeDecl {
+ pos = pos.extend(node.type_pos)
+ }
+ SumTypeDecl {
+ for variant in node.variants {
+ pos = pos.extend(variant.pos)
+ }
+ }
+ }
+ }
+ if node is AssignStmt {
+ return pos.extend(node.right.last().position())
+ }
+ if node is AssertStmt {
+ return pos.extend(node.expr.position())
+ }
+ return pos
+ }
+ Expr {
+ return node.position()
+ }
+ StructField {
+ return node.pos.extend(node.type_pos)
+ }
+ MatchBranch, SelectBranch, EnumField, ConstField, StructInitField, GlobalField, CallArg {
+ return node.pos
+ }
+ Param {
+ return node.pos.extend(node.type_pos)
+ }
+ IfBranch {
+ return node.pos.extend(node.body_pos)
+ }
+ ScopeObject {
+ match node {
+ ConstField, GlobalField, Var {
+ return node.pos
+ }
+ AsmRegister {
+ return token.Position{
+ len: -1
+ line_nr: -1
+ pos: -1
+ last_line: -1
+ col: -1
+ }
+ }
+ }
+ }
+ File {
+ mut pos := token.Position{}
+ if node.stmts.len > 0 {
+ first_pos := node.stmts.first().pos
+ last_pos := node.stmts.last().pos
+ pos = first_pos.extend_with_last_line(last_pos, last_pos.line_nr)
+ }
+ return pos
+ }
+ }
+}
+
+pub fn (node Node) children() []Node {
+ mut children := []Node{}
+ if node is Expr {
+ match node {
+ StringInterLiteral, Assoc, ArrayInit {
+ return node.exprs.map(Node(it))
+ }
+ SelectorExpr, PostfixExpr, UnsafeExpr, AsCast, ParExpr, IfGuardExpr, SizeOf, Likely,
+ TypeOf, ArrayDecompose {
+ children << node.expr
+ }
+ LockExpr, OrExpr {
+ return node.stmts.map(Node(it))
+ }
+ StructInit {
+ return node.fields.map(Node(it))
+ }
+ AnonFn {
+ children << Stmt(node.decl)
+ }
+ CallExpr {
+ children << node.left
+ children << node.args.map(Node(it))
+ children << Expr(node.or_block)
+ }
+ InfixExpr {
+ children << node.left
+ children << node.right
+ }
+ PrefixExpr {
+ children << node.right
+ }
+ IndexExpr {
+ children << node.left
+ children << node.index
+ }
+ IfExpr {
+ children << node.left
+ children << node.branches.map(Node(it))
+ }
+ MatchExpr {
+ children << node.cond
+ children << node.branches.map(Node(it))
+ }
+ SelectExpr {
+ return node.branches.map(Node(it))
+ }
+ ChanInit {
+ children << node.cap_expr
+ }
+ MapInit {
+ children << node.keys.map(Node(it))
+ children << node.vals.map(Node(it))
+ }
+ RangeExpr {
+ children << node.low
+ children << node.high
+ }
+ CastExpr {
+ children << node.expr
+ children << node.arg
+ }
+ ConcatExpr {
+ return node.vals.map(Node(it))
+ }
+ ComptimeCall, ComptimeSelector {
+ children << node.left
+ }
+ else {}
+ }
+ } else if node is Stmt {
+ match node {
+ Block, DeferStmt, ForCStmt, ForInStmt, ForStmt, CompFor {
+ return node.stmts.map(Node(it))
+ }
+ ExprStmt, AssertStmt {
+ children << node.expr
+ }
+ InterfaceDecl {
+ children << node.methods.map(Node(Stmt(it)))
+ children << node.fields.map(Node(it))
+ }
+ AssignStmt {
+ children << node.left.map(Node(it))
+ children << node.right.map(Node(it))
+ }
+ Return {
+ return node.exprs.map(Node(it))
+ }
+ // NB: these four decl nodes cannot be merged as one branch
+ StructDecl {
+ return node.fields.map(Node(it))
+ }
+ GlobalDecl {
+ return node.fields.map(Node(it))
+ }
+ ConstDecl {
+ return node.fields.map(Node(it))
+ }
+ EnumDecl {
+ return node.fields.map(Node(it))
+ }
+ FnDecl {
+ if node.is_method {
+ children << Node(node.receiver)
+ }
+ children << node.params.map(Node(it))
+ children << node.stmts.map(Node(it))
+ }
+ TypeDecl {
+ if node is SumTypeDecl {
+ children << node.variants.map(Node(Expr(it)))
+ }
+ }
+ else {}
+ }
+ } else if node is ScopeObject {
+ match node {
+ GlobalField, ConstField, Var { children << node.expr }
+ AsmRegister {}
+ }
+ } else {
+ match node {
+ GlobalField, ConstField, EnumField, StructInitField, CallArg {
+ children << node.expr
+ }
+ SelectBranch {
+ children << node.stmt
+ children << node.stmts.map(Node(it))
+ }
+ IfBranch, File {
+ return node.stmts.map(Node(it))
+ }
+ MatchBranch {
+ children << node.stmts.map(Node(it))
+ children << node.exprs.map(Node(it))
+ }
+ else {}
+ }
+ }
+ return children
+}
+
+// helper for dealing with `m[k1][k2][k3][k3] = value`
+pub fn (mut lx IndexExpr) recursive_mapset_is_setter(val bool) {
+ lx.is_setter = val
+ if mut lx.left is IndexExpr {
+ if lx.left.is_map {
+ lx.left.recursive_mapset_is_setter(val)
+ }
+ }
+}
+
+// return all the registers for a give architecture
+pub fn all_registers(mut t Table, arch pref.Arch) map[string]ScopeObject {
+ mut res := map[string]ScopeObject{}
+ match arch {
+ .amd64, .i386 {
+ for bit_size, array in ast.x86_no_number_register_list {
+ for name in array {
+ res[name] = AsmRegister{
+ name: name
+ typ: t.bitsize_to_type(bit_size)
+ size: bit_size
+ }
+ }
+ }
+ for bit_size, array in ast.x86_with_number_register_list {
+ for name, max_num in array {
+ for i in 0 .. max_num {
+ hash_index := name.index('#') or {
+ panic('all_registers: no hashtag found')
+ }
+ assembled_name := '${name[..hash_index]}$i${name[hash_index + 1..]}'
+ res[assembled_name] = AsmRegister{
+ name: assembled_name
+ typ: t.bitsize_to_type(bit_size)
+ size: bit_size
+ }
+ }
+ }
+ }
+ }
+ .arm32 {
+ arm32 := gen_all_registers(mut t, ast.arm_no_number_register_list, ast.arm_with_number_register_list,
+ 32)
+ for k, v in arm32 {
+ res[k] = v
+ }
+ }
+ .arm64 {
+ arm64 := gen_all_registers(mut t, ast.arm_no_number_register_list, ast.arm_with_number_register_list,
+ 64)
+ for k, v in arm64 {
+ res[k] = v
+ }
+ }
+ .rv32 {
+ rv32 := gen_all_registers(mut t, ast.riscv_no_number_register_list, ast.riscv_with_number_register_list,
+ 32)
+ for k, v in rv32 {
+ res[k] = v
+ }
+ }
+ .rv64 {
+ rv64 := gen_all_registers(mut t, ast.riscv_no_number_register_list, ast.riscv_with_number_register_list,
+ 64)
+ for k, v in rv64 {
+ res[k] = v
+ }
+ }
+ else { // TODO
+ panic('all_registers: unhandled arch')
+ }
+ }
+
+ return res
+}
+
+// only for arm and riscv because x86 has different sized registers
+fn gen_all_registers(mut t Table, without_numbers []string, with_numbers map[string]int, bit_size int) map[string]ScopeObject {
+ mut res := map[string]ScopeObject{}
+ for name in without_numbers {
+ res[name] = AsmRegister{
+ name: name
+ typ: t.bitsize_to_type(bit_size)
+ size: bit_size
+ }
+ }
+ for name, max_num in with_numbers {
+ for i in 0 .. max_num {
+ hash_index := name.index('#') or { panic('all_registers: no hashtag found') }
+ assembled_name := '${name[..hash_index]}$i${name[hash_index + 1..]}'
+ res[assembled_name] = AsmRegister{
+ name: assembled_name
+ typ: t.bitsize_to_type(bit_size)
+ size: bit_size
+ }
+ }
+ }
+ return res
+}
+
+// is `expr` a literal, i.e. it does not depend on any other declarations (C compile time constant)
+pub fn (expr Expr) is_literal() bool {
+ match expr {
+ BoolLiteral, CharLiteral, FloatLiteral, IntegerLiteral {
+ return true
+ }
+ PrefixExpr {
+ return expr.right.is_literal()
+ }
+ InfixExpr {
+ return expr.left.is_literal() && expr.right.is_literal()
+ }
+ ParExpr {
+ return expr.expr.is_literal()
+ }
+ CastExpr {
+ return !expr.has_arg && expr.expr.is_literal()
+ && (expr.typ.is_ptr() || expr.typ.is_pointer()
+ || expr.typ in [i8_type, i16_type, int_type, i64_type, byte_type, u8_type, u16_type, u32_type, u64_type, f32_type, f64_type, char_type, bool_type, rune_type])
+ }
+ SizeOf, IsRefType {
+ return expr.is_type || expr.expr.is_literal()
+ }
+ else {
+ return false
+ }
+ }
+}