transformer: refactor + apply transform to (hopefully) all nodes (#13216)
parent
d67be6302b
commit
14b33baa3b
147
vlib/v/ast/ast.v
147
vlib/v/ast/ast.v
|
@ -151,10 +151,10 @@ pub:
|
||||||
// Stand-alone expression in a statement list.
|
// Stand-alone expression in a statement list.
|
||||||
pub struct ExprStmt {
|
pub struct ExprStmt {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
is_expr bool
|
is_expr bool
|
||||||
typ Type
|
typ Type
|
||||||
}
|
}
|
||||||
|
@ -290,11 +290,11 @@ pub struct ConstField {
|
||||||
pub:
|
pub:
|
||||||
mod string
|
mod string
|
||||||
name string
|
name string
|
||||||
expr Expr // the value expr of field; everything after `=`
|
|
||||||
is_pub bool
|
is_pub bool
|
||||||
is_markused bool // an explict `[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
|
is_markused bool // an explict `[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
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
|
typ Type // the type of the const field, it can be any type in V
|
||||||
comments []Comment // comments before current const field
|
comments []Comment // comments before current const field
|
||||||
// the comptime_expr_value field is filled by the checker, when it has enough
|
// the comptime_expr_value field is filled by the checker, when it has enough
|
||||||
|
@ -387,11 +387,11 @@ pub mut:
|
||||||
|
|
||||||
pub struct StructInitEmbed {
|
pub struct StructInitEmbed {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
comments []Comment
|
comments []Comment
|
||||||
next_comments []Comment
|
next_comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
name string
|
name string
|
||||||
typ Type
|
typ Type
|
||||||
expected_type Type
|
expected_type Type
|
||||||
|
@ -791,10 +791,10 @@ pub mut:
|
||||||
// ++, --
|
// ++, --
|
||||||
pub struct PostfixExpr {
|
pub struct PostfixExpr {
|
||||||
pub:
|
pub:
|
||||||
op token.Kind
|
op token.Kind
|
||||||
expr Expr
|
pos token.Position
|
||||||
pos token.Position
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
auto_locked string
|
auto_locked string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,10 +812,10 @@ pub mut:
|
||||||
|
|
||||||
pub struct IndexExpr {
|
pub struct IndexExpr {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
index Expr // [0], RangeExpr [start..end] or map[key]
|
|
||||||
or_expr OrExpr
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
index Expr // [0], RangeExpr [start..end] or map[key]
|
||||||
|
or_expr OrExpr
|
||||||
left Expr
|
left Expr
|
||||||
left_type Type // array, map, fixed array
|
left_type Type // array, map, fixed array
|
||||||
is_setter bool
|
is_setter bool
|
||||||
|
@ -831,10 +831,10 @@ pub struct IfExpr {
|
||||||
pub:
|
pub:
|
||||||
is_comptime bool
|
is_comptime bool
|
||||||
tok_kind token.Kind
|
tok_kind token.Kind
|
||||||
left Expr // `a` in `a := if ...`
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
post_comments []Comment
|
post_comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
left Expr // `a` in `a := if ...`
|
||||||
branches []IfBranch // includes all `else if` branches
|
branches []IfBranch // includes all `else if` branches
|
||||||
is_expr bool
|
is_expr bool
|
||||||
typ Type
|
typ Type
|
||||||
|
@ -844,11 +844,11 @@ pub mut:
|
||||||
|
|
||||||
pub struct IfBranch {
|
pub struct IfBranch {
|
||||||
pub:
|
pub:
|
||||||
cond Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
body_pos token.Position
|
body_pos token.Position
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
cond Expr
|
||||||
pkg_exist bool
|
pkg_exist bool
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
scope &Scope
|
scope &Scope
|
||||||
|
@ -856,16 +856,17 @@ pub mut:
|
||||||
|
|
||||||
pub struct UnsafeExpr {
|
pub struct UnsafeExpr {
|
||||||
pub:
|
pub:
|
||||||
|
pos token.Position
|
||||||
|
pub mut:
|
||||||
expr Expr
|
expr Expr
|
||||||
pos token.Position
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LockExpr {
|
pub struct LockExpr {
|
||||||
pub:
|
pub:
|
||||||
stmts []Stmt
|
|
||||||
is_rlock []bool
|
is_rlock []bool
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
|
stmts []Stmt
|
||||||
lockeds []Expr // `x`, `y.z` in `lock x, y.z {`
|
lockeds []Expr // `x`, `y.z` in `lock x, y.z {`
|
||||||
comments []Comment
|
comments []Comment
|
||||||
is_expr bool
|
is_expr bool
|
||||||
|
@ -876,11 +877,11 @@ pub mut:
|
||||||
pub struct MatchExpr {
|
pub struct MatchExpr {
|
||||||
pub:
|
pub:
|
||||||
tok_kind token.Kind
|
tok_kind token.Kind
|
||||||
cond Expr
|
|
||||||
branches []MatchBranch
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
comments []Comment // comments before the first branch
|
comments []Comment // comments before the first branch
|
||||||
pub mut:
|
pub mut:
|
||||||
|
cond Expr
|
||||||
|
branches []MatchBranch
|
||||||
is_expr bool // returns a value
|
is_expr bool // returns a value
|
||||||
return_type Type
|
return_type Type
|
||||||
cond_type Type // type of `x` in `match x {`
|
cond_type Type // type of `x` in `match x {`
|
||||||
|
@ -913,13 +914,14 @@ pub mut:
|
||||||
|
|
||||||
pub struct SelectBranch {
|
pub struct SelectBranch {
|
||||||
pub:
|
pub:
|
||||||
stmt Stmt // `a := <-ch` or `ch <- a`
|
|
||||||
stmts []Stmt // right side
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
comment Comment // comment above `select {`
|
comment Comment // comment above `select {`
|
||||||
is_else bool
|
is_else bool
|
||||||
is_timeout bool
|
is_timeout bool
|
||||||
post_comments []Comment
|
post_comments []Comment
|
||||||
|
pub mut:
|
||||||
|
stmt Stmt // `a := <-ch` or `ch <- a`
|
||||||
|
stmts []Stmt // right side
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ComptimeForKind {
|
pub enum ComptimeForKind {
|
||||||
|
@ -942,11 +944,11 @@ pub mut:
|
||||||
|
|
||||||
pub struct ForStmt {
|
pub struct ForStmt {
|
||||||
pub:
|
pub:
|
||||||
cond Expr
|
|
||||||
stmts []Stmt
|
|
||||||
is_inf bool // `for {}`
|
is_inf bool // `for {}`
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
|
cond Expr
|
||||||
|
stmts []Stmt
|
||||||
label string // `label: for {`
|
label string // `label: for {`
|
||||||
scope &Scope
|
scope &Scope
|
||||||
}
|
}
|
||||||
|
@ -974,16 +976,16 @@ pub mut:
|
||||||
|
|
||||||
pub struct ForCStmt {
|
pub struct ForCStmt {
|
||||||
pub:
|
pub:
|
||||||
init Stmt // i := 0;
|
|
||||||
has_init bool
|
has_init bool
|
||||||
cond Expr // i < 10;
|
|
||||||
has_cond bool
|
has_cond bool
|
||||||
inc Stmt // i++; i += 2
|
|
||||||
has_inc bool
|
has_inc bool
|
||||||
is_multi bool // for a,b := 0,1; a < 10; a,b = a+b, a {...}
|
is_multi bool // for a,b := 0,1; a < 10; a,b = a+b, a {...}
|
||||||
stmts []Stmt
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
|
init Stmt // i := 0;
|
||||||
|
cond Expr // i < 10;
|
||||||
|
inc Stmt // i++; i += 2
|
||||||
|
stmts []Stmt
|
||||||
label string // `label: for {`
|
label string // `label: for {`
|
||||||
scope &Scope
|
scope &Scope
|
||||||
}
|
}
|
||||||
|
@ -1031,10 +1033,10 @@ pub mut:
|
||||||
// `expr as Ident`
|
// `expr as Ident`
|
||||||
pub struct AsCast {
|
pub struct AsCast {
|
||||||
pub:
|
pub:
|
||||||
expr Expr // from expr: `expr` in `expr as Ident`
|
typ Type // to type
|
||||||
typ Type // to type
|
pos token.Position
|
||||||
pos token.Position
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr // from expr: `expr` in `expr as Ident`
|
||||||
expr_type Type // from type
|
expr_type Type // from type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,8 +1126,9 @@ pub mut:
|
||||||
// `(3+4)`
|
// `(3+4)`
|
||||||
pub struct ParExpr {
|
pub struct ParExpr {
|
||||||
pub:
|
pub:
|
||||||
|
pos token.Position
|
||||||
|
pub mut:
|
||||||
expr Expr
|
expr Expr
|
||||||
pos token.Position
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GoExpr {
|
pub struct GoExpr {
|
||||||
|
@ -1152,20 +1155,20 @@ pub struct ArrayInit {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position // `[]` in []Type{} position
|
pos token.Position // `[]` in []Type{} position
|
||||||
elem_type_pos token.Position // `Type` 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
|
||||||
ecmnts [][]Comment // optional iembed comments after each expr
|
|
||||||
pre_cmnts []Comment
|
pre_cmnts []Comment
|
||||||
is_fixed bool
|
is_fixed bool
|
||||||
has_val bool // fixed size literal `[expr, expr]!`
|
has_val bool // fixed size literal `[expr, expr]!`
|
||||||
mod string
|
mod string
|
||||||
len_expr Expr // len: expr
|
|
||||||
cap_expr Expr // cap: expr
|
|
||||||
default_expr Expr // init: expr
|
|
||||||
has_len bool
|
has_len bool
|
||||||
has_cap bool
|
has_cap bool
|
||||||
has_default bool
|
has_default bool
|
||||||
has_it bool // true if temp variable it is used
|
has_it bool // true if temp variable it is used
|
||||||
pub mut:
|
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
|
expr_types []Type // [Dog, Cat] // also used for interface_types
|
||||||
elem_type Type // element type
|
elem_type Type // element type
|
||||||
default_type Type // default value type
|
default_type Type // default value type
|
||||||
|
@ -1174,19 +1177,19 @@ pub mut:
|
||||||
|
|
||||||
pub struct ArrayDecompose {
|
pub struct ArrayDecompose {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
pos token.Position
|
||||||
pos token.Position
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
expr_type Type
|
expr_type Type
|
||||||
arg_type Type
|
arg_type Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChanInit {
|
pub struct ChanInit {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
cap_expr Expr
|
has_cap bool
|
||||||
has_cap bool
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
cap_expr Expr
|
||||||
typ Type
|
typ Type
|
||||||
elem_type Type
|
elem_type Type
|
||||||
}
|
}
|
||||||
|
@ -1194,11 +1197,11 @@ pub mut:
|
||||||
pub struct MapInit {
|
pub struct MapInit {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
keys []Expr
|
|
||||||
vals []Expr
|
|
||||||
comments [][]Comment // comments after key-value pairs
|
comments [][]Comment // comments after key-value pairs
|
||||||
pre_cmnts []Comment // comments before the first key-value pair
|
pre_cmnts []Comment // comments before the first key-value pair
|
||||||
pub mut:
|
pub mut:
|
||||||
|
keys []Expr
|
||||||
|
vals []Expr
|
||||||
typ Type
|
typ Type
|
||||||
key_type Type
|
key_type Type
|
||||||
value_type Type
|
value_type Type
|
||||||
|
@ -1207,18 +1210,18 @@ pub mut:
|
||||||
// s[10..20]
|
// s[10..20]
|
||||||
pub struct RangeExpr {
|
pub struct RangeExpr {
|
||||||
pub:
|
pub:
|
||||||
low Expr
|
|
||||||
high Expr
|
|
||||||
has_high bool
|
has_high bool
|
||||||
has_low bool
|
has_low bool
|
||||||
pos token.Position
|
pos token.Position
|
||||||
is_gated bool // #[] gated array
|
is_gated bool // #[] gated array
|
||||||
|
pub mut:
|
||||||
|
low Expr
|
||||||
|
high Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CastExpr {
|
pub struct CastExpr {
|
||||||
pub:
|
|
||||||
arg Expr // `n` in `string(buf, n)`
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
arg Expr // `n` in `string(buf, n)`
|
||||||
typ Type // `string`
|
typ Type // `string`
|
||||||
expr Expr // `buf` in `string(buf, n)` and `&Type(buf)`
|
expr Expr // `buf` in `string(buf, n)` and `&Type(buf)`
|
||||||
typname string // `&Type` in `&Type(buf)`
|
typname string // `&Type` in `&Type(buf)`
|
||||||
|
@ -1457,9 +1460,9 @@ pub struct Assoc {
|
||||||
pub:
|
pub:
|
||||||
var_name string
|
var_name string
|
||||||
fields []string
|
fields []string
|
||||||
exprs []Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
|
exprs []Expr
|
||||||
typ Type
|
typ Type
|
||||||
scope &Scope
|
scope &Scope
|
||||||
}
|
}
|
||||||
|
@ -1467,19 +1470,19 @@ pub mut:
|
||||||
pub struct SizeOf {
|
pub struct SizeOf {
|
||||||
pub:
|
pub:
|
||||||
is_type bool
|
is_type bool
|
||||||
expr Expr // checker uses this to set typ
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
typ Type
|
expr Expr // checker uses this to set typ
|
||||||
|
typ Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IsRefType {
|
pub struct IsRefType {
|
||||||
pub:
|
pub:
|
||||||
is_type bool
|
is_type bool
|
||||||
expr Expr // checker uses this to set typ
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
typ Type
|
expr Expr // checker uses this to set typ
|
||||||
|
typ Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OffsetOf {
|
pub struct OffsetOf {
|
||||||
|
@ -1491,24 +1494,25 @@ pub:
|
||||||
|
|
||||||
pub struct Likely {
|
pub struct Likely {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
is_likely bool // false for _unlikely_
|
is_likely bool // false for _unlikely_
|
||||||
|
pub mut:
|
||||||
|
expr Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TypeOf {
|
pub struct TypeOf {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
pos token.Position
|
||||||
pos token.Position
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
expr_type Type
|
expr_type Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DumpExpr {
|
pub struct DumpExpr {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
pos token.Position
|
||||||
pos token.Position
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
expr_type Type
|
expr_type Type
|
||||||
cname string // filled in the checker
|
cname string // filled in the checker
|
||||||
}
|
}
|
||||||
|
@ -1542,12 +1546,12 @@ pub mut:
|
||||||
pub struct ComptimeSelector {
|
pub struct ComptimeSelector {
|
||||||
pub:
|
pub:
|
||||||
has_parens bool // if $() is used, for vfmt
|
has_parens bool // if $() is used, for vfmt
|
||||||
left Expr
|
|
||||||
field_expr Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
left_type Type
|
left Expr
|
||||||
typ Type
|
left_type Type
|
||||||
|
field_expr Expr
|
||||||
|
typ Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ComptimeCall {
|
pub struct ComptimeCall {
|
||||||
|
@ -1614,21 +1618,21 @@ pub mut:
|
||||||
|
|
||||||
pub struct SqlExpr {
|
pub struct SqlExpr {
|
||||||
pub:
|
pub:
|
||||||
typ Type
|
typ Type
|
||||||
is_count bool
|
is_count bool
|
||||||
db_expr Expr // `db` in `sql db {`
|
has_where bool
|
||||||
has_where bool
|
has_order bool
|
||||||
has_offset bool
|
has_limit bool
|
||||||
offset_expr Expr
|
has_offset bool
|
||||||
has_order bool
|
has_desc bool
|
||||||
order_expr Expr
|
is_array bool
|
||||||
has_desc bool
|
pos token.Position
|
||||||
is_array bool
|
|
||||||
pos token.Position
|
|
||||||
has_limit bool
|
|
||||||
limit_expr Expr
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
db_expr Expr // `db` in `sql db {`
|
||||||
where_expr Expr
|
where_expr Expr
|
||||||
|
order_expr Expr
|
||||||
|
limit_expr Expr
|
||||||
|
offset_expr Expr
|
||||||
table_expr TypeNode
|
table_expr TypeNode
|
||||||
fields []StructField
|
fields []StructField
|
||||||
sub_structs map[int]SqlExpr
|
sub_structs map[int]SqlExpr
|
||||||
|
@ -1780,9 +1784,10 @@ pub fn (stmt Stmt) check_c_expr() ? {
|
||||||
pub struct CTempVar {
|
pub struct CTempVar {
|
||||||
pub:
|
pub:
|
||||||
name string // the name of the C temporary variable; used by g.expr(x)
|
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
|
typ Type // the type of the original expression
|
||||||
is_ptr bool // whether the type is a pointer
|
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) position() token.Position {
|
pub fn (node Node) position() token.Position {
|
||||||
|
|
|
@ -1821,7 +1821,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
node.typ = c.expr(node.expr)
|
node.typ = c.expr(node.expr)
|
||||||
c.expected_type = ast.void_type
|
c.expected_type = ast.void_type
|
||||||
mut or_typ := ast.void_type
|
mut or_typ := ast.void_type
|
||||||
match node.expr {
|
match mut node.expr {
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
if node.expr.or_expr.kind != .absent {
|
if node.expr.or_expr.kind != .absent {
|
||||||
node.is_expr = true
|
node.is_expr = true
|
||||||
|
@ -1837,7 +1837,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
if !c.pref.is_repl && (c.stmt_level == 1 || (c.stmt_level > 1 && !c.is_last_stmt)) {
|
if !c.pref.is_repl && (c.stmt_level == 1 || (c.stmt_level > 1 && !c.is_last_stmt)) {
|
||||||
if node.expr is ast.InfixExpr {
|
if mut node.expr is ast.InfixExpr {
|
||||||
if node.expr.op == .left_shift {
|
if node.expr.op == .left_shift {
|
||||||
left_sym := c.table.final_sym(node.expr.left_type)
|
left_sym := c.table.final_sym(node.expr.left_type)
|
||||||
if left_sym.kind != .array {
|
if left_sym.kind != .array {
|
||||||
|
@ -2422,7 +2422,7 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
|
||||||
c.error('expected `string` instead of `$expr_sym.name` (e.g. `field.name`)',
|
c.error('expected `string` instead of `$expr_sym.name` (e.g. `field.name`)',
|
||||||
node.field_expr.position())
|
node.field_expr.position())
|
||||||
}
|
}
|
||||||
if node.field_expr is ast.SelectorExpr {
|
if mut node.field_expr is ast.SelectorExpr {
|
||||||
left_pos := node.field_expr.expr.position()
|
left_pos := node.field_expr.expr.position()
|
||||||
if c.comptime_fields_type.len == 0 {
|
if c.comptime_fields_type.len == 0 {
|
||||||
c.error('compile time field access can only be used when iterating over `T.fields`',
|
c.error('compile time field access can only be used when iterating over `T.fields`',
|
||||||
|
@ -3025,7 +3025,7 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
|
||||||
c.inside_const = false
|
c.inside_const = false
|
||||||
c.mod = old_c_mod
|
c.mod = old_c_mod
|
||||||
|
|
||||||
if obj.expr is ast.CallExpr {
|
if mut obj.expr is ast.CallExpr {
|
||||||
if obj.expr.or_block.kind != .absent {
|
if obj.expr.or_block.kind != .absent {
|
||||||
typ = typ.clear_flag(.optional)
|
typ = typ.clear_flag(.optional)
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,10 +147,10 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
||||||
if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated {
|
if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated {
|
||||||
c.error('non-bool used as for condition', node.pos)
|
c.error('non-bool used as for condition', node.pos)
|
||||||
}
|
}
|
||||||
if node.cond is ast.InfixExpr {
|
if mut node.cond is ast.InfixExpr {
|
||||||
infix := node.cond
|
infix := node.cond
|
||||||
if infix.op == .key_is {
|
if infix.op == .key_is {
|
||||||
if infix.left in [ast.Ident, ast.SelectorExpr] && infix.right is ast.TypeNode {
|
if infix.right is ast.TypeNode && infix.left in [ast.Ident, ast.SelectorExpr] {
|
||||||
is_variable := if mut infix.left is ast.Ident {
|
is_variable := if mut infix.left is ast.Ident {
|
||||||
infix.left.kind == .variable
|
infix.left.kind == .variable
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
if node.is_comptime { // Skip checking if needed
|
if node.is_comptime { // Skip checking if needed
|
||||||
// smartcast field type on comptime if
|
// smartcast field type on comptime if
|
||||||
mut comptime_field_name := ''
|
mut comptime_field_name := ''
|
||||||
if branch.cond is ast.InfixExpr {
|
if mut branch.cond is ast.InfixExpr {
|
||||||
if branch.cond.op == .key_is {
|
if branch.cond.op == .key_is {
|
||||||
if branch.cond.right !is ast.TypeNode {
|
if branch.cond.right !is ast.TypeNode {
|
||||||
c.error('invalid `\$if` condition: expected a type', branch.cond.right.position())
|
c.error('invalid `\$if` condition: expected a type', branch.cond.right.position())
|
||||||
|
@ -106,7 +106,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
}
|
}
|
||||||
} else if c.pref.output_cross_c {
|
} else if c.pref.output_cross_c {
|
||||||
mut is_freestanding_block := false
|
mut is_freestanding_block := false
|
||||||
if branch.cond is ast.Ident {
|
if mut branch.cond is ast.Ident {
|
||||||
if branch.cond.name == 'freestanding' {
|
if branch.cond.name == 'freestanding' {
|
||||||
is_freestanding_block = true
|
is_freestanding_block = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import strings
|
||||||
pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
||||||
node.is_expr = c.expected_type != ast.void_type
|
node.is_expr = c.expected_type != ast.void_type
|
||||||
node.expected_type = c.expected_type
|
node.expected_type = c.expected_type
|
||||||
if node.cond is ast.ParExpr && !c.pref.translated {
|
if mut node.cond is ast.ParExpr && !c.pref.translated {
|
||||||
c.error('unnecessary `()` in `match` condition, use `match expr {` instead of `match (expr) {`.',
|
c.error('unnecessary `()` in `match` condition, use `match expr {` instead of `match (expr) {`.',
|
||||||
node.cond.pos)
|
node.cond.pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,13 @@ pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
mut show_non_const_error := false
|
mut show_non_const_error := false
|
||||||
if const_field := p.table.global_scope.find_const('${p.mod}.$size_expr.name') {
|
if mut const_field := p.table.global_scope.find_const('${p.mod}.$size_expr.name') {
|
||||||
if const_field.expr is ast.IntegerLiteral {
|
if mut const_field.expr is ast.IntegerLiteral {
|
||||||
fixed_size = const_field.expr.val.int()
|
fixed_size = const_field.expr.val.int()
|
||||||
} else {
|
} else {
|
||||||
if const_field.expr is ast.InfixExpr {
|
if mut const_field.expr is ast.InfixExpr {
|
||||||
mut t := transformer.new_transformer(p.pref)
|
mut t := transformer.new_transformer(p.pref)
|
||||||
folded_expr := t.infix_expr(const_field.expr)
|
folded_expr := t.infix_expr(mut const_field.expr)
|
||||||
|
|
||||||
if folded_expr is ast.IntegerLiteral {
|
if folded_expr is ast.IntegerLiteral {
|
||||||
fixed_size = folded_expr.val.int()
|
fixed_size = folded_expr.val.int()
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
module transformer
|
||||||
|
|
||||||
|
struct KeyVal {
|
||||||
|
key string
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
|
||||||
|
[if debug_bounds_checking ?]
|
||||||
|
fn debug_bounds_checking(str string) {
|
||||||
|
println(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexState is used to track the index analysis performed when parsing the code
|
||||||
|
// `IndexExpr` nodes are annotated with `is_direct`, indicating that the array index can be safely directly accessed.
|
||||||
|
|
||||||
|
// The c_gen code check will handle this annotation and perform this direct memory access. The following cases are considered valid for this optimisation:
|
||||||
|
// 1. the array size is known and has a `len` larger than the index requested
|
||||||
|
// 2. the array was previously accessed with a higher value which would have reported the issue already
|
||||||
|
// 3. the array was created from a range expression a := range[10..13] and the offset'ed indexes are safe
|
||||||
|
|
||||||
|
// Current limitations:
|
||||||
|
// * any function using break/continue or goto/label stopped from being optimised as soon as the relevant AST nodes are found as the code can not be ensured to be sequential
|
||||||
|
// * `enum` and `const` indexes are not optimised (they could probably be looked up)
|
||||||
|
// * for loops with multiple var in their init and/or inc are not analysed
|
||||||
|
// * mut array are not analysed as their size can be reduced, but self-assignment in a single line
|
||||||
|
|
||||||
|
pub struct IndexState {
|
||||||
|
mut:
|
||||||
|
// max_index has the biggest array index accessed for then named array
|
||||||
|
// so if a[2] was set or read, it will be 2
|
||||||
|
// A new array with no .len will recorded as -1 (accessing a[0] would be invalid)
|
||||||
|
// the value -2 is used to indicate that the array should not be analysed
|
||||||
|
// this is used for a mut array
|
||||||
|
max_index map[string]int
|
||||||
|
// We need to snapshot when entering `if` and `for` blocks and restore on exit
|
||||||
|
// as the statements may not be run. This is managed by indent() & unindent().
|
||||||
|
saved_disabled []bool
|
||||||
|
saved_key_vals [][]KeyVal
|
||||||
|
pub mut:
|
||||||
|
// on encountering goto/break/continue statements we stop any analysis
|
||||||
|
// for the current function (as the code is not linear anymore)
|
||||||
|
disabled bool
|
||||||
|
level int
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are remembering the last array accessed and checking if the value is safe
|
||||||
|
// the node is updated with this information which can then be used by the code generators
|
||||||
|
fn (mut i IndexState) safe_access(key string, new int) bool {
|
||||||
|
$if no_bounds_checking {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if i.disabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
old := i.max_index[key] or {
|
||||||
|
debug_bounds_checking('$i.level ${key}.len = $new')
|
||||||
|
i.max_index[key] = new
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if new > old {
|
||||||
|
if old < -1 {
|
||||||
|
debug_bounds_checking('$i.level $key[$new] unsafe (mut array)')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
debug_bounds_checking('$i.level $key[$new] unsafe (index was $old)')
|
||||||
|
i.max_index[key] = new
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
debug_bounds_checking('$i.level $key[$new] safe (index is $old)')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// safe_offset returns for a previvous array what was the highest
|
||||||
|
// offset we ever accessed for that identifier
|
||||||
|
fn (mut i IndexState) safe_offset(key string) int {
|
||||||
|
$if no_bounds_checking {
|
||||||
|
return -2
|
||||||
|
}
|
||||||
|
if i.disabled {
|
||||||
|
return -2
|
||||||
|
}
|
||||||
|
return i.max_index[key] or { -1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// indent is used for when encountering new code blocks (if, for and functions)
|
||||||
|
// The code analysis needs to take into consideration blocks of code which
|
||||||
|
// may not run at runtime (if/for) and therefore even if a new maximum for an
|
||||||
|
// index access is found on an if branch it can not be used within the parent
|
||||||
|
// code. The same is true with for blocks. indent() snapshot the current state,
|
||||||
|
// to allow restoration with unindent()
|
||||||
|
// Also within a function, analysis must be `disabled` when goto or break are
|
||||||
|
// encountered as the code flow is then not lineear, and only restart when a
|
||||||
|
// new function analysis is started.
|
||||||
|
[if !no_bounds_checking]
|
||||||
|
fn (mut i IndexState) indent(is_function bool) {
|
||||||
|
mut kvs := []KeyVal{cap: i.max_index.len}
|
||||||
|
for k, v in i.max_index {
|
||||||
|
kvs << KeyVal{k, v}
|
||||||
|
}
|
||||||
|
i.saved_disabled << i.disabled
|
||||||
|
i.saved_key_vals << kvs
|
||||||
|
if is_function {
|
||||||
|
i.disabled = false
|
||||||
|
}
|
||||||
|
i.level += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoring the data as it was before the if/for/unsafe block
|
||||||
|
[if !no_bounds_checking]
|
||||||
|
fn (mut i IndexState) unindent() {
|
||||||
|
i.level -= 1
|
||||||
|
mut keys := []string{cap: i.max_index.len}
|
||||||
|
for k, _ in i.max_index {
|
||||||
|
keys << k
|
||||||
|
}
|
||||||
|
for k in keys {
|
||||||
|
i.max_index.delete(k)
|
||||||
|
}
|
||||||
|
for saved in i.saved_key_vals.pop() {
|
||||||
|
i.max_index[saved.key] = saved.value
|
||||||
|
}
|
||||||
|
i.disabled = i.saved_disabled.pop()
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue