v/vlib/v/ast/ast.v

1583 lines
34 KiB
V
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 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.table
import v.errors
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 | EnumVal | FloatLiteral | GoExpr | Ident |
IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr |
MapInit | MatchExpr | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | PrefixExpr |
RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral |
StructInit | Type | TypeOf | UnsafeExpr
pub type Stmt = AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | DeferStmt |
EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt |
GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | 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 = ConstField | GlobalField | Var
// TOOD: replace table.Param
pub type Node = ConstField | EnumField | Expr | Field | File | GlobalField | IfBranch |
MatchBranch | ScopeObject | SelectBranch | Stmt | StructField | StructInitField |
table.Param
pub struct Type {
pub:
typ table.Type
pos token.Position
}
// `{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
is_expr bool
pub mut:
typ table.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 table.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 []table.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 table.Type // type of `Foo` in `Foo.bar`
typ table.Type // type of the entire thing (`Foo.bar`)
name_type table.Type // T in `T.name` or typeof in `typeof(expr).name`
scope &Scope
from_embed_type table.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
}
return root as Ident
}
// module declaration
pub struct Module {
pub:
name string // encoding.base64
short_name string // base64
attrs []table.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
default_expr Expr
has_default_expr bool
attrs []table.Attr
is_public bool
pub mut:
name string
typ table.Type
}
pub struct Field {
pub:
name string
pos token.Position
pub mut:
typ table.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 table.Type // the type of the const field, it can be any type in V
comments []Comment // comments before current const field
}
// 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
gen_types []table.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 table.Language
is_union bool
attrs []table.Attr
end_comments []Comment
embeds []Embed
pub mut:
fields []StructField
}
pub struct Embed {
pub:
typ table.Type
pos token.Position
}
pub struct StructEmbedding {
pub:
name string
typ table.Type
pos token.Position
}
pub struct InterfaceDecl {
pub:
name string
field_names []string
is_pub bool
methods []FnDecl
mut_pos int // mut:
fields []StructField
pos token.Position
pre_comments []Comment
}
pub struct StructInitField {
pub:
expr Expr
pos token.Position
comments []Comment
next_comments []Comment
pub mut:
name string
typ table.Type
expected_type table.Type
}
pub struct StructInitEmbed {
pub:
expr Expr
pos token.Position
comments []Comment
next_comments []Comment
pub mut:
name string
typ table.Type
expected_type table.Type
}
pub struct StructInit {
pub:
pos token.Position
is_short bool
pub mut:
unresolved bool
pre_comments []Comment
typ table.Type
update_expr Expr
update_expr_type table.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
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 table.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
params []table.Param
is_deprecated bool
is_pub bool
is_variadic bool
is_anon bool
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`
receiver 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 table.ShareType
language table.Language
no_body bool // just a definition `fn C.malloc()`
is_builtin bool // this function is defined in builtin/strconv
pos token.Position // function declaration position
body_pos token.Position // function bodys position
file string
generic_params []GenericParam
is_direct_arr bool // direct array access
attrs []table.Attr
skip_gen bool // this function doesn't need to be generated (for example [if foo])
pub mut:
stmts []Stmt
defer_stmts []DeferStmt
return_type table.Type
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
}
pub struct GenericParam {
pub:
name string
}
// 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
mod string
pub mut:
name string // left.name()
is_method bool
is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
args []CallArg
expected_arg_types []table.Type
language table.Language
or_block OrExpr
left Expr // `user` in `user.register()`
left_type table.Type // type of `user`
receiver_type table.Type // User
return_type table.Type
should_be_skipped bool
generic_types []table.Type
generic_list_pos token.Position
free_receiver bool // true if the receiver expression needs to be freed
scope &Scope
from_embed_type table.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 table.ShareType
expr Expr
comments []Comment
pub mut:
typ table.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
exprs []Expr
comments []Comment
pub mut:
types []table.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 table.ShareType
is_mut bool
is_autofree_tmp bool
is_arg bool // fn args should not be autofreed
is_auto_deref bool
pub mut:
typ table.Type
orig_type table.Type // original sumtype type; 0 if it's not a sumtype
sum_type_casts []table.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 (sum_type_casts)
// 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
}
// used for smartcasting only
// struct fields change type in scopes
pub struct ScopeStructField {
pub:
struct_type table.Type // type of struct
name string
pos token.Position
typ table.Type
sum_type_casts []table.Type // nested sum types require nested smart casting, for that a list of types is needed
orig_type table.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 (sum_type_casts)
// 12 <- the current casted type (typ)
}
pub struct GlobalField {
pub:
name string
expr Expr
has_expr bool
pos token.Position
pub mut:
typ table.Type
comments []Comment
}
pub struct GlobalDecl {
pub:
pos token.Position
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 ast.File structure.
// When the V compiler runs, the parser will fill an []ast.File.
// That array is then passed to V's checker.
pub struct File {
pub:
path string // absolute path of the source file - '/projects/v/file.v'
path_base string // file name - 'file.v' (useful for tracing)
mod Module // the module of the source file (from `module xyz` at the top)
global_scope &Scope
pub mut:
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 warings in the file
generic_fns []&FnDecl
}
pub struct IdentFn {
pub mut:
typ table.Type
}
// TODO: (joe) remove completely, use ident.obj
// instead which points to the scope object
pub struct IdentVar {
pub mut:
typ table.Type
is_mut bool
is_static bool
is_optional bool
share table.ShareType
}
pub type IdentInfo = IdentFn | IdentVar
pub enum IdentKind {
unresolved
blank_ident
variable
constant
global
function
}
// A single identifier
pub struct Ident {
pub:
language table.Language
tok_kind token.Kind
pos token.Position
mut_pos token.Position
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
pub mut:
left Expr
right Expr
left_type table.Type
right_type table.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 table.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 table.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 table.Type
has_else bool
}
pub struct IfBranch {
pub:
cond Expr
pos token.Position
body_pos token.Position
comments []Comment
pub mut:
stmts []Stmt
smartcast bool // true when cond is `x is SumType`, set in checker.if_expr // no longer needed with union sum types TODO: remove
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 []Ident // `x`, `y` in `lock x, y {`
is_expr bool
typ table.Type
}
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 table.Type
cond_type table.Type // type of `x` in `match x {`
expected_type table.Type // for debugging only
is_sum_type bool
}
pub struct MatchBranch {
pub:
exprs []Expr // left side
ecmnts [][]Comment // inline comments for each left side expr
stmts []Stmt // right side
pos token.Position
is_else bool
post_comments []Comment // comments below ´... }´
pub mut:
scope &Scope
}
pub struct SelectExpr {
pub:
branches []SelectBranch
pos token.Position
has_exception bool
pub mut:
is_expr bool // returns a value
expected_type table.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
}
pub struct CompFor {
pub:
val_var string
stmts []Stmt
kind CompForKind
pos token.Position
typ_pos token.Position
pub mut:
// expr Expr
typ table.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 table.Type
val_type table.Type
cond_type table.Type
kind table.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 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'
}
/*
// 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 []table.Type
right_types []table.Type
is_static bool // for translated code only
is_simple bool // `x+=2` in `for x:=1; ; x+=2`
has_cross_var bool
}
pub struct AsCast {
pub:
expr Expr
typ table.Type
pos token.Position
pub mut:
expr_type table.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 table.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 []table.Attr // attributes of enum declaration
pos token.Position
}
pub struct AliasTypeDecl {
pub:
name string
is_pub bool
parent_type table.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
pub mut:
variants []SumTypeVariant
}
pub struct SumTypeVariant {
pub:
typ table.Type
pos token.Position
}
pub struct FnTypeDecl {
pub:
name string
is_pub bool
typ table.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:
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 GoStmt {
pub:
pos token.Position
pub mut:
call_expr CallExpr
}
pub struct GoExpr {
pub:
pos token.Position
pub mut:
go_stmt GoStmt
mut:
return_type table.Type
}
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 []table.Type // [Dog, Cat] // also used for interface_types
elem_type table.Type // element type
typ table.Type // array type
}
pub struct ArrayDecompose {
pub:
expr Expr
pos token.Position
pub mut:
expr_type table.Type
arg_type table.Type
}
pub struct ChanInit {
pub:
pos token.Position
cap_expr Expr
has_cap bool
pub mut:
typ table.Type
elem_type table.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 table.Type
key_type table.Type
value_type table.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 ast.PrefixExpr{ right: ast.CastExpr{...} }
// TODO: that is very likely a parsing bug. It should get parsed as just
// ast.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)`.
pub struct CastExpr {
pub:
expr Expr // `buf` in `string(buf, n)`
arg Expr // `n` in `string(buf, n)`
typ table.Type // `string` TODO rename to `type_to_cast_to`
pos token.Position
pub mut:
typname string // TypeSymbol.name
expr_type table.Type // `byteptr`
has_arg bool
in_prexpr bool // is the parent node an ast.PrefixExpr
}
pub struct AssertStmt {
pub:
pos token.Position
pub mut:
expr Expr
}
// `if [x := opt()] {`
pub struct IfGuardExpr {
pub:
var_name string
pos token.Position
pub mut:
expr Expr
expr_type table.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 table.Type
scope &Scope
}
pub struct SizeOf {
pub:
is_type bool
expr Expr // checker uses this to set typ
pos token.Position
pub mut:
typ table.Type
}
pub struct OffsetOf {
pub:
struct_type table.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 table.Type
}
pub struct DumpExpr {
pub:
expr Expr
pos token.Position
pub mut:
expr_type table.Type
cname string // filled in the checker
}
pub struct Comment {
pub:
text string
is_multi bool
line_nr int
pos token.Position
}
pub struct ConcatExpr {
pub:
vals []Expr
pos token.Position
pub mut:
return_type table.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 table.Type
typ table.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
pub mut:
sym table.TypeSymbol
result_type table.Type
env_value string
}
pub struct None {
pub:
pos token.Position
foo int // todo
}
pub enum SqlStmtKind {
insert
update
delete
}
pub struct SqlStmt {
pub:
kind SqlStmtKind
db_expr Expr // `db` in `sql db {`
object_var_name string // `user`
pos token.Position
where_expr Expr
updated_columns []string // for `update set x=y`
update_exprs []Expr // for `update`
pub mut:
table_expr Type
fields []table.Field
sub_structs map[int]SqlStmt
}
pub struct SqlExpr {
pub:
typ table.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 Type
fields []table.Field
sub_structs map[int]SqlExpr
}
[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
match expr {
// KEKW2
AnonFn {
return expr.decl.pos
}
ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit,
CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr, FloatLiteral,
GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, MatchExpr,
None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr,
SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf, UnsafeExpr
{
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
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, 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
}
// 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 table.Type // the type of the original expression
is_ptr bool // whether the type is a pointer
}
pub fn (stmt Stmt) position() token.Position {
match stmt {
AssertStmt, AssignStmt, Block, BranchStmt, CompFor, ConstDecl, DeferStmt, EnumDecl, ExprStmt,
FnDecl, ForCStmt, ForInStmt, ForStmt, GotoLabel, GotoStmt, Import, Return, StructDecl,
GlobalDecl, HashStmt, InterfaceDecl, Module, SqlStmt, GoStmt {
return stmt.pos
}
TypeDecl {
match stmt {
AliasTypeDecl, FnTypeDecl, SumTypeDecl { return stmt.pos }
}
}
// Please, do NOT use else{} here.
// This match is exhaustive *on purpose*, to help force
// maintaining/implementing proper .pos fields.
}
}
pub fn (node Node) position() token.Position {
match node {
Stmt {
mut pos := node.position()
if node is Import {
for sym in node.syms {
pos = pos.extend(sym.pos)
}
}
return pos
}
Expr {
return node.position()
}
StructField {
return node.pos.extend(node.type_pos)
}
MatchBranch, SelectBranch, Field, EnumField, ConstField, StructInitField, GlobalField,
table.Param {
return node.pos
}
IfBranch {
return node.pos.extend(node.body_pos)
}
ScopeObject {
match node {
ConstField, GlobalField, Var { return node.pos }
}
}
File {
mut pos := token.Position{}
if node.stmts.len > 0 {
first_pos := node.stmts.first().position()
last_pos := node.stmts.last().position()
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 << 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 {
return node.methods.map(Node(Stmt(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))
}
else {}
}
} else if node is ScopeObject {
match node {
GlobalField, ConstField, Var { children << node.expr }
}
} else {
match node {
GlobalField, ConstField, EnumField, StructInitField {
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
}
// TODO: remove this fugly hack :-|
// fe2ex/1 and ex2fe/1 are used to convert back and forth from
// table.FExpr to ast.Expr , which in turn is needed to break
// a dependency cycle between v.ast and v.table, for the single
// field table.Field.default_expr, which should be ast.Expr
pub fn fe2ex(x table.FExpr) Expr {
res := Expr{}
unsafe { C.memcpy(&res, &x, sizeof(Expr)) }
return res
}
pub fn ex2fe(x Expr) table.FExpr {
res := table.FExpr{}
unsafe { C.memcpy(&res, &x, sizeof(table.FExpr)) }
return res
}
// experimental ast.Table
pub struct Table {
// pub mut:
// main_fn_decl_node FnDecl
}
// 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)
}
}
}