v/vlib/v/ast/ast.v

2172 lines
47 KiB
V
Raw Normal View History

2022-01-04 10:21:08 +01:00
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
2019-12-22 02:34:37 +01:00
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module ast
2020-04-19 00:07:57 +02:00
import v.token
import v.errors
import v.pref
2019-12-22 02:34:37 +01:00
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
| ComptimeFor
| ConstDecl
| DeferStmt
| EmptyStmt
| EnumDecl
| ExprStmt
| FnDecl
| ForCStmt
| ForInStmt
| ForStmt
| GlobalDecl
| GotoLabel
| GotoStmt
| HashStmt
| Import
| InterfaceDecl
| Module
| NodeError
| Return
| SqlStmt
| StructDecl
| TypeDecl
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 {
2020-03-02 10:53:38 +01:00
pub:
typ Type
pos token.Pos
2020-03-02 10:53:38 +01:00
}
2021-03-31 11:28:42 +02:00
pub struct EmptyExpr {
x int
}
pub fn empty_expr() Expr {
return EmptyExpr{}
}
pub struct EmptyStmt {
pub:
pos token.Pos
}
pub fn empty_stmt() Stmt {
return EmptyStmt{}
}
pub struct EmptyNode {
x int
}
pub fn empty_node() Node {
return EmptyNode{}
}
// `{stmts}` or `unsafe {stmts}`
2020-03-24 15:44:17 +01:00
pub struct Block {
pub:
stmts []Stmt
is_unsafe bool
pos token.Pos
2020-03-24 15:44:17 +01:00
}
2020-01-06 16:13:12 +01:00
// | IncDecStmt k
2019-12-28 14:11:05 +01:00
// Stand-alone expression in a statement list.
pub struct ExprStmt {
pub:
pos token.Pos
comments []Comment
2020-05-21 22:35:43 +02:00
pub mut:
expr Expr
is_expr bool
typ Type
2019-12-28 14:11:05 +01:00
}
2019-12-22 02:34:37 +01:00
2019-12-26 11:21:41 +01:00
pub struct IntegerLiteral {
pub:
val string
pos token.Pos
}
2019-12-24 18:54:43 +01:00
2019-12-27 10:03:29 +01:00
pub struct FloatLiteral {
pub:
val string
pos token.Pos
2019-12-27 10:03:29 +01:00
}
2019-12-24 18:54:43 +01:00
pub struct StringLiteral {
pub:
val string
is_raw bool
language Language
pos token.Pos
2019-12-24 18:54:43 +01:00
}
2019-12-22 02:34:37 +01:00
2020-03-21 07:01:06 +01:00
// 'name: $name'
pub struct StringInterLiteral {
pub:
vals []string
fwidths []int
precisions []int
pluss []bool
fills []bool
fmt_poss []token.Pos
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
exprs []Expr
expr_types []Type
fmts []byte
need_fmts []bool // an explicit non-default fmt required, e.g. `x`
2020-03-21 07:01:06 +01:00
}
2020-02-04 09:54:15 +01:00
pub struct CharLiteral {
pub:
val string
pos token.Pos
2020-02-04 09:54:15 +01:00
}
pub struct BoolLiteral {
pub:
val bool
pos token.Pos
}
pub enum GenericKindField {
unknown
name
typ
}
// `foo.bar`
pub struct SelectorExpr {
pub:
pos token.Pos
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.Pos
next_token token.Kind
2020-05-09 15:16:48 +02:00
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`
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
scope &Scope
from_embed_types []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
2021-09-13 03:08:58 +02:00
for mut root is SelectorExpr {
root = root.expr
}
if root is Ident {
return root as Ident
}
return none
}
2019-12-28 11:02:06 +01:00
// module declaration
pub struct Module {
pub:
name string // encoding.base64
short_name string // base64
attrs []Attr
pos token.Pos
name_pos token.Pos // `name` in import name
is_skipped bool // module main can be skipped in single file programs
}
2020-04-05 02:08:10 +02:00
pub struct StructField {
pub:
pos token.Pos
type_pos token.Pos
comments []Comment
has_default_expr bool
attrs []Attr
is_pub bool
default_val string
is_mut bool
is_global bool
is_volatile bool
2020-05-09 15:16:48 +02:00
pub mut:
default_expr Expr
default_expr_typ Type
name string
typ Type
2020-04-05 02:08:10 +02:00
}
pub fn (f &StructField) equals(o &StructField) bool {
// TODO: f.is_mut == o.is_mut was removed here to allow read only access
// to (mut/not mut), but otherwise equal fields; some other new checks are needed:
// - if node is declared mut, and we mutate node.stmts, all stmts fields must be mutable
// - same goes for pub and global, if we call the field from another module
return f.name == o.name && f.typ == o.typ && f.is_pub == o.is_pub && f.is_global == o.is_global
}
// const field in const declaration group
pub struct ConstField {
pub:
mod string
name string
is_pub bool
is_markused bool // an explict `[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
expr Expr // the value expr of field; everything after `=`
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.Pos
attrs []Attr // tags like `[markused]`, valid for all the consts in the list
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.Pos
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
2020-10-30 07:09:26 +01:00
pub mut:
fields []StructField
2020-10-30 07:09:26 +01:00
}
pub struct Embed {
pub:
typ Type
pos token.Pos
comments []Comment
}
pub struct InterfaceEmbedding {
pub:
name string
typ Type
pos token.Pos
comments []Comment
}
pub struct InterfaceDecl {
2020-04-05 12:31:39 +02:00
pub:
name string
typ Type
name_pos token.Pos
language Language
field_names []string
is_pub bool
mut_pos int // mut:
pos token.Pos
pre_comments []Comment
generic_types []Type
attrs []Attr
pub mut:
methods []FnDecl
fields []StructField
//
ifaces []InterfaceEmbedding
are_ifaces_expanded bool
}
pub struct StructInitField {
pub:
pos token.Pos
name_pos token.Pos
comments []Comment
next_comments []Comment
2020-05-09 15:16:48 +02:00
pub mut:
expr Expr
name string
typ Type
expected_type Type
2021-04-02 16:26:37 +02:00
parent_type Type
}
pub struct StructInitEmbed {
pub:
pos token.Pos
comments []Comment
next_comments []Comment
pub mut:
expr Expr
name string
typ Type
expected_type Type
}
pub struct StructInit {
pub:
pos token.Pos
name_pos token.Pos
is_short bool
is_short_syntax bool
2020-05-09 15:16:48 +02:00
pub mut:
unresolved bool
pre_comments []Comment
typ_str string
typ Type
update_expr Expr
update_expr_type Type
update_expr_comments []Comment
has_update_expr bool
fields []StructInitField
embeds []StructInitEmbed
generic_types []Type
}
// 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.Pos
mod_pos token.Pos
alias_pos token.Pos
syms_pos token.Pos
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.Pos
name string
}
// anonymous function
2020-04-17 21:59:19 +02:00
pub struct AnonFn {
2020-05-09 15:16:48 +02:00
pub mut:
decl FnDecl
inherited_vars []Param
typ Type // the type of anonymous fn. Both .typ and .decl.name are auto generated
has_gen bool // has been generated
2020-04-17 21:59:19 +02:00
}
// function or method declaration
2019-12-27 13:57:49 +01:00
pub struct FnDecl {
pub:
name string // 'math.bits.normalize'
short_name string // 'normalize'
mod string // 'math.bits'
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
is_markused bool // true, when an explict `[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
receiver StructField // TODO this is not a struct field
receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position
is_method bool
method_type_pos token.Pos // `User` in ` fn (u User)` position
method_idx int
rec_mut bool // is receiver mutable
rec_share ShareType
language Language // V, C, JS
file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc.
no_body bool // just a definition `fn C.malloc()`
is_builtin bool // this function is defined in builtin/strconv
body_pos token.Pos // 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.Pos // `string` in `fn (u User) name() string` position
has_return bool
should_be_skipped bool // true, when -skip-unused could not find any usages of that function, starting from main + other known used functions
ninstances int // 0 for generic functions with no concrete instances
has_await bool // 'true' if this function uses JS.await
//
2021-12-05 12:33:53 +01:00
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.Pos // function declaration position
2019-12-29 07:24:17 +01:00
}
// break, continue
pub struct BranchStmt {
pub:
kind token.Kind
label string
pos token.Pos
}
// function or method call expr
2019-12-29 07:24:17 +01:00
pub struct CallExpr {
pub:
pos token.Pos
name_pos token.Pos
mod string
2020-05-09 15:16:48 +02:00
pub mut:
name string // left.name()
is_method bool
2020-07-13 20:04:16 +02:00
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]
is_ctor_new bool // if JS ctor calls requires `new` before call, marked as `[use_new]` in V
2020-04-09 15:33:46 +02:00
args []CallArg
expected_arg_types []Type
language Language
2020-04-09 15:33:46 +02:00
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 // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
concrete_types []Type // concrete types, e.g. <int, string>
concrete_list_pos token.Pos
2020-10-22 03:51:25 +02:00
free_receiver bool // true if the receiver expression needs to be freed
scope &Scope
from_embed_types []Type // holds the type of the embed that the method is called from
comments []Comment
}
2020-09-05 12:00:35 +02:00
/*
pub struct AutofreeArgVar {
name string
idx int
}
*/
// function call argument: `f(callarg)`
pub struct CallArg {
pub:
is_mut bool
share ShareType
comments []Comment
2020-05-09 15:16:48 +02:00
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.Pos
2020-09-05 12:00:35 +02:00
// tmp_name string // for autofree
2019-12-27 13:57:49 +01:00
}
// function return statement
2019-12-27 13:57:49 +01:00
pub struct Return {
pub:
pos token.Pos
comments []Comment
2020-05-09 15:16:48 +02:00
pub mut:
exprs []Expr
types []Type
2019-12-27 13:57:49 +01:00
}
2019-12-22 02:34:37 +01:00
/*
pub enum Expr {
Binary(InfixExpr)
2019-12-22 02:34:37 +01:00
If(IfExpr)
Integer(IntegerExpr)
}
*/
2019-12-24 18:54:43 +01:00
/*
2019-12-22 02:34:37 +01:00
pub struct Stmt {
pos int
//end int
}
2019-12-24 18:54:43 +01:00
*/
pub struct Var {
2019-12-24 18:54:43 +01:00
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
is_inherited bool
2020-05-09 15:16:48 +02:00
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.Pos
is_used bool // whether the local variable was used in other expressions
is_changed bool // to detect mutable vars that are never changed
2020-12-06 08:38:21 +01:00
//
// (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)
2019-12-24 18:54:43 +01:00
}
// used for smartcasting only
// struct fields change type in scopes
pub struct ScopeStructField {
pub:
struct_type Type // type of struct
name string
pos token.Pos
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.Pos
typ_pos token.Pos
is_markused bool // an explict `[markused]` tag; the global will NOT be removed by `-skip-unused`
2020-05-09 15:16:48 +02:00
pub mut:
expr Expr
typ Type
comments []Comment
}
pub struct GlobalDecl {
pub:
mod string
pos token.Pos
is_block bool // __global() block
attrs []Attr // tags like `[markused]`, valid for all the globals in the list
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
compression_type string
pub mut:
// these are set by gen_embed_file_init in v/gen/c/embed
is_compressed bool
bytes []byte
len int
}
// 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]
2019-12-30 12:10:46 +01:00
pub struct File {
2019-12-24 18:54:43 +01:00
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
is_generated bool // true for `[generated] module xyz` files; turn off notices
is_translated bool // true for `[translated] module xyz` files; turn off some checks
2020-05-09 15:16:48 +02:00
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
2020-03-13 05:57:51 +01:00
is_mut bool
is_static bool
is_volatile bool
2020-03-13 05:57:51 +01:00
is_optional bool
share ShareType
}
pub type IdentInfo = IdentFn | IdentVar
pub enum IdentKind {
unresolved
blank_ident
variable
constant
global
function
2019-12-24 18:54:43 +01:00
}
2019-12-28 14:11:05 +01:00
2019-12-22 02:34:37 +01:00
// A single identifier
2019-12-28 14:11:05 +01:00
pub struct Ident {
pub:
language Language
tok_kind token.Kind
pos token.Pos
mut_pos token.Pos
comptime bool
2020-05-09 15:16:48 +02:00
pub mut:
scope &Scope
obj ScopeObject
mod string
name string
kind IdentKind
info IdentInfo
is_mut bool
2019-12-22 02:34:37 +01:00
}
2020-02-07 14:49:14 +01:00
pub fn (i &Ident) var_info() IdentVar {
match mut i.info {
2020-02-06 17:38:02 +01:00
IdentVar {
return i.info
2020-02-06 17:38:02 +01:00
}
else {
// return IdentVar{}
panic('Ident.var_info(): info is not IdentVar variant')
}
}
}
// left op right
// See: token.Kind.is_infix
pub struct InfixExpr {
2019-12-22 02:34:37 +01:00
pub:
op token.Kind
pos token.Pos
is_stmt bool
pub mut:
2020-07-14 18:52:28 +02:00
left Expr
right Expr
left_type Type
right_type Type
2020-07-14 18:52:28 +02:00
auto_locked string
or_block OrExpr
//
ct_left_value_evaled bool
ct_left_value ComptTimeConstValue = empty_comptime_const_expr()
ct_right_value_evaled bool
ct_right_value ComptTimeConstValue = empty_comptime_const_expr()
2019-12-22 02:34:37 +01:00
}
// ++, --
2020-01-06 16:13:12 +01:00
pub struct PostfixExpr {
pub:
op token.Kind
pos token.Pos
pub mut:
expr Expr
2020-07-14 18:52:28 +02:00
auto_locked string
2020-01-06 16:13:12 +01:00
}
// See: token.Kind.is_prefix
2020-01-06 16:13:12 +01:00
pub struct PrefixExpr {
pub:
op token.Kind
pos token.Pos
pub mut:
right_type Type
right Expr
or_block OrExpr
is_option bool // IfGuard
2020-01-06 16:13:12 +01:00
}
2020-01-07 12:14:10 +01:00
pub struct IndexExpr {
pub:
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
index Expr // [0], RangeExpr [start..end] or map[key]
or_expr OrExpr
left Expr
left_type Type // array, map, fixed array
2020-04-09 15:33:46 +02:00
is_setter bool
is_map bool
is_array bool
is_farray bool
is_option bool // IfGuard
is_direct bool // Set if the underlying memory can be safely accessed
is_gated bool // #[] gated array
2020-01-07 12:14:10 +01:00
}
2019-12-28 19:16:04 +01:00
pub struct IfExpr {
pub:
is_comptime bool
tok_kind token.Kind
pos token.Pos
post_comments []Comment
2020-05-09 15:16:48 +02:00
pub mut:
left Expr // `a` in `a := if ...`
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:
pos token.Pos
body_pos token.Pos
comments []Comment
2020-07-08 15:17:28 +02:00
pub mut:
cond Expr
pkg_exist bool
stmts []Stmt
scope &Scope
}
2020-07-12 12:58:33 +02:00
pub struct UnsafeExpr {
pub:
pos token.Pos
pub mut:
expr Expr
2020-07-12 12:58:33 +02:00
}
pub struct LockExpr {
pub:
is_rlock []bool
pos token.Pos
pub mut:
stmts []Stmt
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
pos token.Pos
comments []Comment // comments before the first branch
2020-05-09 15:16:48 +02:00
pub mut:
cond Expr
branches []MatchBranch
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
}
2020-03-04 11:59:45 +01:00
pub struct MatchBranch {
pub:
ecmnts [][]Comment // inline comments for each left side expr
pos token.Pos
is_else bool
post_comments []Comment // comments below ´... }´
branch_pos token.Pos // for checker errors about invalid branches
pub mut:
stmts []Stmt // right side
exprs []Expr // left side
scope &Scope
2020-03-04 11:59:45 +01:00
}
pub struct SelectExpr {
pub:
branches []SelectBranch
pos token.Pos
has_exception bool
pub mut:
is_expr bool // returns a value
expected_type Type // for debugging only
}
pub struct SelectBranch {
pub:
pos token.Pos
comment Comment // comment above `select {`
is_else bool
is_timeout bool
post_comments []Comment
pub mut:
stmt Stmt // `a := <-ch` or `ch <- a`
stmts []Stmt // right side
}
pub enum ComptimeForKind {
methods
fields
attributes
}
pub struct ComptimeFor {
pub:
val_var string
stmts []Stmt
kind ComptimeForKind
pos token.Pos
typ_pos token.Pos
pub mut:
// expr Expr
typ Type
}
pub struct ForStmt {
pub:
2020-02-19 11:06:36 +01:00
is_inf bool // `for {}`
pos token.Pos
pub mut:
cond Expr
stmts []Stmt
label string // `label: for {`
scope &Scope
2020-01-07 00:14:19 +01:00
}
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.Pos
2020-10-13 16:27:24 +02:00
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
2021-12-08 09:09:10 +01:00
high_type Type
kind Kind // array/map/string
label string // `label: for {`
scope &Scope
2020-01-07 00:14:19 +01:00
}
pub struct ForCStmt {
pub:
has_init bool
has_cond bool
has_inc bool
is_multi bool // for a,b := 0,1; a < 10; a,b = a+b, a {...}
pos token.Pos
pub mut:
init Stmt // i := 0;
cond Expr // i < 10;
inc Stmt // i++; i += 2
stmts []Stmt
label string // `label: for {`
scope &Scope
}
// #include, #define etc
2020-02-04 09:54:15 +01:00
pub struct HashStmt {
pub:
mod string
pos token.Pos
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
2020-02-04 09:54:15 +01:00
}
2020-08-12 05:54:51 +02:00
/*
// filter(), map(), sort()
2020-02-10 14:42:57 +01:00
pub struct Lambda {
pub:
name string
}
2020-08-12 05:54:51 +02:00
*/
// variable assign statement
2019-12-28 19:16:04 +01:00
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.Pos
comments []Comment
end_comments []Comment
pub mut:
2021-01-30 11:55:10 +01:00
right []Expr
left []Expr
left_types []Type
right_types []Type
2020-05-27 03:20:22 +02:00
is_static bool // for translated code only
is_volatile bool // for disabling variable access optimisations (needed for hardware drivers)
is_simple bool // `x+=2` in `for x:=1; ; x+=2`
2020-05-26 18:00:51 +02:00
has_cross_var bool
2019-12-28 19:16:04 +01:00
}
2020-02-06 17:38:02 +01:00
// `expr as Ident`
pub struct AsCast {
pub:
typ Type // to type
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
expr Expr // from expr: `expr` in `expr as Ident`
expr_type Type // from type
}
// an enum value, like OS.macos or .macos
pub struct EnumVal {
pub:
2020-02-25 15:02:34 +01:00
enum_name string
val string
2020-03-15 00:46:08 +01:00
mod string // for full path `mod_Enum_val`
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
typ Type
}
// enum field in enum declaration
2020-04-09 19:23:49 +02:00
pub struct EnumField {
2020-05-18 18:06:09 +02:00
pub:
name string
pos token.Pos
comments []Comment // comment after Enumfield in the same line
next_comments []Comment // comments between current EnumField and next EnumField
has_expr bool // true, when .expr has a value
pub mut:
expr Expr // the value of current EnumField; 123 in `ename = 123`
2020-04-09 19:23:49 +02:00
}
// 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.Pos
}
pub struct AliasTypeDecl {
pub:
2020-03-07 22:37:03 +01:00
name string
is_pub bool
parent_type Type
pos token.Pos
type_pos token.Pos
comments []Comment
}
2021-12-25 16:26:40 +01:00
// SumTypeDecl is the ast node for `type MySumType = string | int`
pub struct SumTypeDecl {
pub:
name string
is_pub bool
pos token.Pos
comments []Comment
typ Type
generic_types []Type
attrs []Attr // attributes of type declaration
pub mut:
variants []TypeNode
}
pub struct FnTypeDecl {
pub:
name string
is_pub bool
typ Type
pos token.Pos
type_pos token.Pos
comments []Comment
}
2020-04-09 15:33:46 +02:00
// TODO: handle this differently
// v1 excludes non current os ifdefs so
// the defer's never get added in the first place
2020-02-17 22:50:04 +01:00
pub struct DeferStmt {
2020-02-11 10:26:46 +01:00
pub:
2020-02-17 22:50:04 +01:00
stmts []Stmt
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
defer_vars []Ident
ifdef string
idx_in_fn int = -1 // index in FnDecl.defer_stmts
2020-02-11 10:26:46 +01:00
}
2020-02-28 14:41:19 +01:00
// `(3+4)`
pub struct ParExpr {
pub:
pos token.Pos
pub mut:
2020-02-28 14:41:19 +01:00
expr Expr
}
pub struct GoExpr {
pub:
pos token.Pos
pub mut:
2021-04-11 23:56:25 +02:00
call_expr CallExpr
is_expr bool
}
2020-02-17 22:50:04 +01:00
pub struct GotoLabel {
2020-02-17 14:15:42 +01:00
pub:
2020-02-17 22:50:04 +01:00
name string
pos token.Pos
2020-02-17 14:15:42 +01:00
}
pub struct GotoStmt {
pub:
2020-02-17 22:50:04 +01:00
name string
pos token.Pos
2020-02-17 14:15:42 +01:00
}
2019-12-30 09:38:12 +01:00
pub struct ArrayInit {
pub:
pos token.Pos // `[]` in []Type{} position
elem_type_pos token.Pos // `Type` in []Type{} position
ecmnts [][]Comment // optional iembed comments after each expr
pre_cmnts []Comment
is_fixed bool
has_val bool // fixed size literal `[expr, expr]!`
mod string
has_len bool
has_cap bool
has_default bool
has_it bool // true if temp variable it is used
2020-12-01 11:20:27 +01:00
pub mut:
exprs []Expr // `[expr, expr]` or `[expr]Type{}` for fixed array
len_expr Expr // len: expr
cap_expr Expr // cap: expr
default_expr Expr // init: expr
expr_types []Type // [Dog, Cat] // also used for interface_types
elem_type Type // element type
default_type Type // default value type
typ Type // array type
2019-12-30 09:38:12 +01:00
}
pub struct ArrayDecompose {
pub:
pos token.Pos
pub mut:
expr Expr
expr_type Type
arg_type Type
}
pub struct ChanInit {
pub:
pos token.Pos
has_cap bool
pub mut:
cap_expr Expr
typ Type
elem_type Type
}
2020-02-22 14:13:19 +01:00
pub struct MapInit {
pub:
pos token.Pos
comments [][]Comment // comments after key-value pairs
pre_cmnts []Comment // comments before the first key-value pair
2020-05-09 15:16:48 +02:00
pub mut:
keys []Expr
vals []Expr
val_types []Type
typ Type
key_type Type
value_type Type
2020-02-22 14:13:19 +01:00
}
2020-02-02 14:31:54 +01:00
// s[10..20]
pub struct RangeExpr {
pub:
2020-03-06 22:24:39 +01:00
has_high bool
has_low bool
pos token.Pos
is_gated bool // #[] gated array
pub mut:
low Expr
high Expr
2020-02-02 14:31:54 +01:00
}
pub struct CastExpr {
2020-05-09 15:16:48 +02:00
pub mut:
arg Expr // `n` in `string(buf, n)`
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.Pos
}
pub struct AsmStmt {
pub:
arch pref.Arch
is_basic bool
is_volatile bool
is_goto bool
clobbered []AsmClobbered
pos token.Pos
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.Pos
}
// [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.Pos
}
pub struct AsmAlias {
pub:
pos token.Pos
pub mut:
name string // a
}
pub struct AsmAddressing {
pub:
2021-04-02 16:26:37 +02:00
scale int = -1 // 1, 2, 4, or 8 literal
mode AddressingMode
pos token.Pos
pub mut:
segment string // fs:
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.Pos
}
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 = {
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 = {
8: {
'r#b': 16
}
16: {
'r#w': 16
}
32: {
'r#d': 16
}
64: {
'r#': 16
'mm#': 16
'cr#': 16
'dr#': 16
}
80: {
'st#': 16
}
128: {
'xmm#': 32
}
256: {
'ymm#': 32
}
512: {
'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 = {
'r#': 16
}
)
pub const (
riscv_no_number_register_list = ['zero', 'ra', 'sp', 'gp', 'tp']
riscv_with_number_register_list = {
'x#': 32
't#': 3
's#': 12
'a#': 8
}
)
pub struct AssertStmt {
pub:
pos token.Pos
pub mut:
expr Expr
is_used bool // asserts are used in _test.v files, as well as in non -prod builds of all files
}
pub struct IfGuardVar {
pub mut:
name string
is_mut bool
pos token.Pos
}
// `if x := opt() {`
pub struct IfGuardExpr {
pub:
vars []IfGuardVar
2020-05-09 15:16:48 +02:00
pub mut:
expr Expr
expr_type Type
}
2020-05-23 08:51:15 +02:00
pub enum OrKind {
absent
block
propagate
}
// `or { ... }`
pub struct OrExpr {
pub:
2020-05-23 08:51:15 +02:00
stmts []Stmt
kind OrKind
pos token.Pos
}
2020-09-13 03:00:20 +02:00
/*
// `or { ... }`
pub struct OrExpr2 {
pub:
call_expr CallExpr
stmts []Stmt // inside `or { }`
kind OrKind
pos token.Pos
}
2020-09-13 03:00:20 +02:00
*/
// deprecated
pub struct Assoc {
pub:
var_name string
fields []string
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
exprs []Expr
typ Type
scope &Scope
}
2020-02-18 18:13:34 +01:00
pub struct SizeOf {
pub:
is_type bool
pos token.Pos
pub mut:
expr Expr // checker uses this to set typ
typ Type
2020-02-18 18:13:34 +01:00
}
pub struct IsRefType {
pub:
is_type bool
pos token.Pos
pub mut:
expr Expr // checker uses this to set typ
typ Type
}
2021-01-30 12:57:09 +01:00
pub struct OffsetOf {
pub:
struct_type Type
2021-01-30 12:57:09 +01:00
field string
pos token.Pos
2021-01-30 12:57:09 +01:00
}
pub struct Likely {
pub:
pos token.Pos
is_likely bool // false for _unlikely_
pub mut:
expr Expr
}
2020-03-19 12:15:39 +01:00
pub struct TypeOf {
pub:
pos token.Pos
2020-05-09 15:16:48 +02:00
pub mut:
expr Expr
expr_type Type
2020-03-19 12:15:39 +01:00
}
2021-03-06 18:09:28 +01:00
pub struct DumpExpr {
pub:
pos token.Pos
2021-03-06 18:09:28 +01:00
pub mut:
expr Expr
expr_type Type
2021-03-06 18:09:28 +01:00
cname string // filled in the checker
}
2020-04-05 02:08:10 +02:00
pub struct Comment {
2020-02-18 20:20:15 +01:00
pub:
text string
is_multi bool // true only for /* comment */, that use many lines
is_inline bool // true for all /* comment */ comments
pos token.Pos
2020-02-18 20:20:15 +01:00
}
2020-03-01 14:57:54 +01:00
pub struct ConcatExpr {
pub:
vals []Expr
pos token.Pos
2020-05-15 23:14:53 +02:00
pub mut:
return_type Type
2020-03-01 14:57:54 +01:00
}
// @FN, @STRUCT, @MOD etc. See full list in token.valid_at_tokens
pub struct AtExpr {
pub:
name string
pos token.Pos
kind token.AtKind
pub mut:
val string
}
pub struct ComptimeSelector {
pub:
has_parens bool // if $() is used, for vfmt
pos token.Pos
pub mut:
left Expr
left_type Type
field_expr Expr
typ Type
}
pub struct ComptimeCall {
pub:
pos token.Pos
has_parens bool // if $() is used, for vfmt
method_name string
method_pos token.Pos
scope &Scope
left Expr
args_var string
//
is_vweb bool
vweb_tmpl File
//
is_embed bool
//
is_env bool
env_pos token.Pos
//
is_pkgconfig bool
pub mut:
left_type Type
result_type Type
env_value string
args []CallArg
embed_file EmbeddedFile
}
2020-02-19 19:54:36 +01:00
pub struct None {
pub:
pos token.Pos
2020-06-16 12:14:22 +02:00
}
2020-06-24 14:32:14 +02:00
pub enum SqlStmtKind {
insert
update
delete
2021-04-07 15:27:02 +02:00
create
drop
2020-06-24 14:32:14 +02:00
}
pub struct SqlStmt {
pub:
pos token.Pos
db_expr Expr // `db` in `sql db {`
pub mut:
lines []SqlStmtLine
}
pub struct SqlStmtLine {
2020-06-19 16:43:32 +02:00
pub:
kind SqlStmtKind
pos token.Pos
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
2020-06-19 16:43:32 +02:00
}
2020-06-16 12:14:22 +02:00
pub struct SqlExpr {
2020-06-17 00:59:33 +02:00
pub:
typ Type
is_count bool
has_where bool
has_order bool
has_limit bool
has_offset bool
has_desc bool
is_array bool
pos token.Pos
pub mut:
2020-06-27 16:19:12 +02:00
db_expr Expr // `db` in `sql db {`
where_expr Expr
2020-07-02 19:29:22 +02:00
order_expr Expr
2020-06-27 16:19:12 +02:00
limit_expr Expr
offset_expr Expr
table_expr TypeNode
fields []StructField
2021-02-04 20:28:33 +01:00
sub_structs map[int]SqlExpr
2020-02-19 19:54:36 +01:00
}
pub struct NodeError {
pub:
idx int // index for referencing the related File error
pos token.Pos
}
2020-03-18 01:19:23 +01:00
[inline]
pub fn (expr Expr) is_blank_ident() bool {
match expr {
2020-06-19 11:46:08 +02:00
Ident { return expr.kind == .blank_ident }
2020-04-19 00:07:57 +02:00
else { return false }
2020-03-18 01:19:23 +01:00
}
}
pub fn (expr Expr) pos() token.Pos {
// all uncommented have to be implemented
2021-04-02 16:26:37 +02:00
// 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
}
CTempVar, EmptyExpr {
// println('compiler bug, unhandled EmptyExpr pos()')
return token.Pos{}
}
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 {
2021-04-06 15:16:19 +02:00
return expr.pos
}
IndexExpr {
if expr.or_expr.kind != .absent {
return expr.or_expr.pos
}
return expr.pos
}
IfGuardExpr {
return expr.expr.pos()
}
InfixExpr {
left_pos := expr.left.pos()
right_pos := expr.right.pos()
return token.Pos{
2020-06-19 11:46:08 +02:00
line_nr: expr.pos.line_nr
pos: left_pos.pos
len: right_pos.pos - left_pos.pos + right_pos.len
col: left_pos.col
2021-01-19 14:49:40 +01:00
last_line: right_pos.last_line
}
}
// Please, do NOT use else{} here.
// This match is exhaustive *on purpose*, to help force
// maintaining/implementing proper .pos fields.
}
}
2020-04-29 12:31:18 +02:00
pub fn (expr Expr) is_lvalue() bool {
match expr {
2020-09-05 12:00:35 +02:00
Ident { return true }
CTempVar { return true }
2020-09-05 12:00:35 +02:00
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 {
2021-02-20 19:50:43 +01:00
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() {
2021-02-20 19:50:43 +01:00
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)
typ Type // the type of the original expression
is_ptr bool // whether the type is a pointer
pub mut:
orig Expr // the original expression, which produced the C temp variable; used by x.str()
}
pub fn (node Node) pos() token.Pos {
match node {
NodeError {
return token.Pos{}
}
EmptyNode {
return token.Pos{}
}
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)
}
}
}
}
2021-04-06 15:16:19 +02:00
if node is AssignStmt {
return pos.extend(node.right.last().pos())
2021-04-06 15:16:19 +02:00
}
if node is AssertStmt {
return pos.extend(node.expr.pos())
2021-04-06 15:16:19 +02:00
}
return pos
}
Expr {
return node.pos()
}
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.Pos{
len: -1
line_nr: -1
pos: -1
last_line: -1
col: -1
}
}
}
}
File {
mut pos := token.Pos{}
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, ComptimeFor {
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 {
2021-04-02 16:26:37 +02:00
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 the given 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
}
}
}
pub fn type_can_start_with_token(tok &token.Token) bool {
match tok.kind {
.name {
return (tok.lit.len > 0 && tok.lit[0].is_capital())
|| builtin_type_names_matcher.find(tok.lit) > 0
}
// Note: return type (T1, T2) should be handled elsewhere
.amp, .key_fn, .lsbr, .question {
return true
}
else {}
}
return false
}
fn build_builtin_type_names_matcher() token.KeywordsMatcher {
mut m := map[string]int{}
for i, name in builtin_type_names {
m[name] = i
}
return token.new_keywords_matcher<int>(m)
}