all: refactor ast.Expr to use the new sum type implementation (#6792)
parent
ff1752dfff
commit
838ad16296
|
@ -9,7 +9,7 @@ import v.errors
|
|||
|
||||
pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl | UnionSumTypeDecl
|
||||
|
||||
pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar |
|
||||
pub __type Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar |
|
||||
CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal |
|
||||
FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral |
|
||||
Likely | LockExpr | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr |
|
||||
|
@ -559,18 +559,19 @@ pub mut:
|
|||
|
||||
pub struct MatchExpr {
|
||||
pub:
|
||||
tok_kind token.Kind
|
||||
cond Expr
|
||||
branches []MatchBranch
|
||||
pos token.Position
|
||||
is_mut bool // `match mut ast_node {`
|
||||
var_name string // `match cond as var_name {`
|
||||
tok_kind token.Kind
|
||||
cond Expr
|
||||
branches []MatchBranch
|
||||
pos token.Position
|
||||
is_mut bool // `match mut ast_node {`
|
||||
var_name string // `match cond as var_name {`
|
||||
is_union_match bool // temporary union key after match
|
||||
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
|
||||
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 {
|
||||
|
@ -1057,7 +1058,7 @@ pub mut:
|
|||
|
||||
[inline]
|
||||
pub fn (expr Expr) is_blank_ident() bool {
|
||||
match expr {
|
||||
match union expr {
|
||||
Ident { return expr.kind == .blank_ident }
|
||||
else { return false }
|
||||
}
|
||||
|
@ -1065,7 +1066,7 @@ pub fn (expr Expr) is_blank_ident() bool {
|
|||
|
||||
pub fn (expr Expr) position() token.Position {
|
||||
// all uncommented have to be implemented
|
||||
match expr {
|
||||
match union expr {
|
||||
// KEKW2
|
||||
AnonFn {
|
||||
return expr.decl.pos
|
||||
|
@ -1101,7 +1102,7 @@ pub fn (expr Expr) position() token.Position {
|
|||
}
|
||||
|
||||
pub fn (expr Expr) is_lvalue() bool {
|
||||
match expr {
|
||||
match union expr {
|
||||
Ident { return true }
|
||||
CTempVar { return true }
|
||||
IndexExpr { return expr.left.is_lvalue() }
|
||||
|
@ -1112,7 +1113,7 @@ pub fn (expr Expr) is_lvalue() bool {
|
|||
}
|
||||
|
||||
pub fn (expr Expr) is_expr() bool {
|
||||
match expr {
|
||||
match union expr {
|
||||
IfExpr { return expr.is_expr }
|
||||
MatchExpr { return expr.is_expr }
|
||||
else {}
|
||||
|
|
|
@ -210,10 +210,10 @@ pub fn (sc &Scope) str() string {
|
|||
// ```
|
||||
// Since x is mutable, it returns true.
|
||||
pub fn (s &Scope) is_selector_root_mutable(t &table.Table, selector_expr SelectorExpr) bool {
|
||||
if selector_expr.expr is SelectorExpr as left_expr {
|
||||
return s.is_selector_root_mutable(t, left_expr)
|
||||
} else if selector_expr.expr is Ident as left_expr {
|
||||
if v := s.find_var(left_expr.name) {
|
||||
if mut selector_expr.expr is SelectorExpr {
|
||||
return s.is_selector_root_mutable(t, selector_expr.expr)
|
||||
} else if mut selector_expr.expr is Ident {
|
||||
if v := s.find_var(selector_expr.expr.name) {
|
||||
return v.is_mut
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,21 +129,21 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) {
|
|||
if !needs_braces {
|
||||
mut sub_expr := lit.exprs[i]
|
||||
for {
|
||||
match sub_expr as sx {
|
||||
match union mut sub_expr {
|
||||
Ident {
|
||||
if sx.name[0] == `@` {
|
||||
if sub_expr.name[0] == `@` {
|
||||
needs_braces = true
|
||||
}
|
||||
break
|
||||
}
|
||||
CallExpr {
|
||||
if sx.args.len != 0 {
|
||||
if sub_expr.args.len != 0 {
|
||||
needs_braces = true
|
||||
}
|
||||
break
|
||||
}
|
||||
SelectorExpr {
|
||||
sub_expr = sx.expr
|
||||
sub_expr = sub_expr.expr
|
||||
continue
|
||||
}
|
||||
else {
|
||||
|
@ -176,7 +176,7 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) {
|
|||
|
||||
// string representation of expr
|
||||
pub fn (x Expr) str() string {
|
||||
match x {
|
||||
match union x {
|
||||
CTempVar {
|
||||
return x.orig.str()
|
||||
}
|
||||
|
|
|
@ -414,20 +414,20 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
|||
if field.typ.is_ptr() {
|
||||
continue
|
||||
}
|
||||
if field.default_expr is ast.IntegerLiteral as lit {
|
||||
if lit.val == '0' {
|
||||
if field.default_expr is ast.IntegerLiteral {
|
||||
if field.default_expr.val == '0' {
|
||||
c.warn('unnecessary default value of `0`: struct fields are zeroed by default',
|
||||
lit.pos)
|
||||
field.default_expr.pos)
|
||||
}
|
||||
} else if field.default_expr is ast.StringLiteral as lit {
|
||||
if lit.val == '' {
|
||||
} else if field.default_expr is ast.StringLiteral {
|
||||
if field.default_expr.val == '' {
|
||||
c.warn("unnecessary default value of '': struct fields are zeroed by default",
|
||||
lit.pos)
|
||||
field.default_expr.pos)
|
||||
}
|
||||
} else if field.default_expr is ast.BoolLiteral as lit {
|
||||
if lit.val == false {
|
||||
} else if field.default_expr is ast.BoolLiteral {
|
||||
if field.default_expr.val == false {
|
||||
c.warn('unnecessary default value `false`: struct fields are zeroed by default',
|
||||
lit.pos)
|
||||
field.default_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -732,17 +732,17 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
}
|
||||
}
|
||||
if infix_expr.op in [.div, .mod] {
|
||||
match infix_expr.right as infix_right {
|
||||
match union mut infix_expr.right {
|
||||
ast.FloatLiteral {
|
||||
if infix_right.val.f64() == 0.0 {
|
||||
if infix_expr.right.val.f64() == 0.0 {
|
||||
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||
c.error('$oper by zero', infix_right.pos)
|
||||
c.error('$oper by zero', infix_expr.right.pos)
|
||||
}
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
if infix_right.val.int() == 0 {
|
||||
if infix_expr.right.val.int() == 0 {
|
||||
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||
c.error('$oper by zero', infix_right.pos)
|
||||
c.error('$oper by zero', infix_expr.right.pos)
|
||||
}
|
||||
}
|
||||
else {}
|
||||
|
@ -843,9 +843,9 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
// use `()` to make the boolean expression clear error
|
||||
// for example: `(a && b) || c` instead of `a && b || c`
|
||||
if infix_expr.op in [.logical_or, .and] {
|
||||
if infix_expr.left is ast.InfixExpr {
|
||||
e := infix_expr.left as ast.InfixExpr
|
||||
if e.op in [.logical_or, .and] && e.op != infix_expr.op {
|
||||
if mut infix_expr.left is ast.InfixExpr {
|
||||
if infix_expr.left.op in [.logical_or, .and] &&
|
||||
infix_expr.left.op != infix_expr.op {
|
||||
c.error('use `()` to make the boolean expression clear', infix_expr.pos)
|
||||
}
|
||||
}
|
||||
|
@ -897,7 +897,7 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
|
|||
mut to_lock := '' // name of variable that needs lock
|
||||
mut pos := token.Position{} // and its position
|
||||
mut explicit_lock_needed := false
|
||||
match mut expr {
|
||||
match union mut expr {
|
||||
ast.CastExpr {
|
||||
// TODO
|
||||
return '', pos
|
||||
|
@ -1053,7 +1053,8 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type {
|
|||
|
||||
fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_expr ast.CallExpr) {
|
||||
elem_sym := c.table.get_type_symbol(elem_typ)
|
||||
match call_expr.args[0].expr as arg_expr {
|
||||
arg_expr := call_expr.args[0].expr
|
||||
match union arg_expr {
|
||||
ast.AnonFn {
|
||||
if arg_expr.decl.params.len > 1 {
|
||||
c.error('function needs exactly 1 argument', call_expr.pos)
|
||||
|
@ -1385,12 +1386,11 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
|||
mut found := false
|
||||
mut found_in_args := false
|
||||
// anon fn direct call
|
||||
if call_expr.left is ast.AnonFn {
|
||||
if mut call_expr.left is ast.AnonFn {
|
||||
// it was set to anon for checker errors, clear for gen
|
||||
call_expr.name = ''
|
||||
c.expr(call_expr.left)
|
||||
anon_fn := call_expr.left as ast.AnonFn
|
||||
anon_fn_sym := c.table.get_type_symbol(anon_fn.typ)
|
||||
anon_fn_sym := c.table.get_type_symbol(call_expr.left.typ)
|
||||
f = (anon_fn_sym.info as table.FnType).func
|
||||
found = true
|
||||
}
|
||||
|
@ -1741,7 +1741,7 @@ pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type, ex
|
|||
}
|
||||
|
||||
fn is_expr_panic_or_exit(expr ast.Expr) bool {
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.CallExpr { return expr.name in ['panic', 'exit'] }
|
||||
else { return false }
|
||||
}
|
||||
|
@ -1752,16 +1752,16 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T
|
|||
c.prevent_sum_type_unwrapping_once = false
|
||||
// T.name, typeof(expr).name
|
||||
mut name_type := 0
|
||||
match selector_expr.expr as left {
|
||||
match union mut selector_expr.expr {
|
||||
ast.Ident {
|
||||
if left.name == 'T' {
|
||||
if selector_expr.expr.name == 'T' {
|
||||
name_type = table.Type(c.table.find_type_idx('T')).set_flag(.generic)
|
||||
}
|
||||
}
|
||||
// Note: in future typeof() should be a type known at compile-time
|
||||
// sum types should not be handled dynamically
|
||||
ast.TypeOf {
|
||||
name_type = c.expr(left.expr)
|
||||
name_type = c.expr(selector_expr.expr.expr)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
|
@ -1911,21 +1911,20 @@ pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
|
|||
}
|
||||
}
|
||||
if field.has_expr {
|
||||
match field.expr as field_expr {
|
||||
match union field.expr {
|
||||
ast.IntegerLiteral {
|
||||
val := field_expr.val.i64()
|
||||
val := field.expr.val.i64()
|
||||
if val < int_min || val > int_max {
|
||||
c.error('enum value `$val` overflows int', field_expr.pos)
|
||||
c.error('enum value `$val` overflows int', field.expr.pos)
|
||||
} else if !decl.is_multi_allowed && int(val) in seen {
|
||||
c.error('enum value `$val` already exists', field_expr.pos)
|
||||
c.error('enum value `$val` already exists', field.expr.pos)
|
||||
}
|
||||
seen << int(val)
|
||||
}
|
||||
ast.PrefixExpr {}
|
||||
else {
|
||||
if field.expr is ast.Ident {
|
||||
expr := field.expr as ast.Ident
|
||||
if expr.language == .c {
|
||||
if field.expr.language == .c {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -1988,13 +1987,12 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
if left_first is ast.Ident {
|
||||
assigned_var := left_first
|
||||
if node.right is ast.Ident {
|
||||
ident := node.right as ast.Ident
|
||||
scope := c.file.scope.innermost(node.pos.pos)
|
||||
if v := scope.find_var(ident.name) {
|
||||
if v := scope.find_var(node.right.name) {
|
||||
right_type0 = v.typ
|
||||
if node.op == .amp {
|
||||
if !v.is_mut && assigned_var.is_mut && !c.inside_unsafe {
|
||||
c.error('`$ident.name` is immutable, cannot have a mutable reference to it',
|
||||
c.error('`$node.right.name` is immutable, cannot have a mutable reference to it',
|
||||
node.pos)
|
||||
}
|
||||
}
|
||||
|
@ -2049,7 +2047,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
negative = true
|
||||
}
|
||||
}
|
||||
if expr is ast.IntegerLiteral {
|
||||
if mut expr is ast.IntegerLiteral {
|
||||
mut is_large := false
|
||||
if expr.val.len > 8 {
|
||||
val := expr.val.i64()
|
||||
|
@ -2073,7 +2071,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||
// left_type = c.expr(left)
|
||||
}
|
||||
assign_stmt.left_types << left_type
|
||||
match mut left {
|
||||
match union mut left {
|
||||
ast.Ident {
|
||||
if left.kind == .blank_ident {
|
||||
left_type = right_type
|
||||
|
@ -2327,7 +2325,8 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
|||
} else if array_init.is_fixed && array_init.exprs.len == 1 && array_init.elem_type != table.void_type {
|
||||
// [50]byte
|
||||
mut fixed_size := 1
|
||||
match array_init.exprs[0] as init_expr {
|
||||
init_expr := array_init.exprs[0]
|
||||
match union init_expr {
|
||||
ast.IntegerLiteral {
|
||||
fixed_size = init_expr.val.int()
|
||||
}
|
||||
|
@ -2369,8 +2368,8 @@ fn const_int_value(cfield ast.ConstField) ?int {
|
|||
}
|
||||
|
||||
fn is_const_integer(cfield ast.ConstField) ?ast.IntegerLiteral {
|
||||
match cfield.expr {
|
||||
ast.IntegerLiteral { return *it }
|
||||
match union cfield.expr {
|
||||
ast.IntegerLiteral { return cfield.expr }
|
||||
else {}
|
||||
}
|
||||
return none
|
||||
|
@ -2562,18 +2561,17 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
c.error('expression in `go` must be a function call', node.call_expr.position())
|
||||
}
|
||||
c.expr(node.call_expr)
|
||||
if node.call_expr is ast.CallExpr {
|
||||
call_expr := node.call_expr as ast.CallExpr
|
||||
if mut node.call_expr is ast.CallExpr {
|
||||
// Make sure there are no mutable arguments
|
||||
for arg in call_expr.args {
|
||||
for arg in node.call_expr.args {
|
||||
if arg.is_mut && !arg.typ.is_ptr() {
|
||||
c.error('function in `go` statement cannot contain mutable non-reference arguments',
|
||||
arg.expr.position())
|
||||
}
|
||||
}
|
||||
if call_expr.is_method && call_expr.receiver_type.is_ptr() && !call_expr.left_type.is_ptr() {
|
||||
if node.call_expr.is_method && node.call_expr.receiver_type.is_ptr() && !node.call_expr.left_type.is_ptr() {
|
||||
c.error('method in `go` statement cannot have non-reference mutable receiver',
|
||||
call_expr.left.position())
|
||||
node.call_expr.left.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2743,7 +2741,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
c.error('checker: too many expr levels: $c.expr_level ', node.position())
|
||||
return table.void_type
|
||||
}
|
||||
match mut node {
|
||||
match union mut node {
|
||||
ast.CTempVar {
|
||||
return node.typ
|
||||
}
|
||||
|
@ -2894,10 +2892,11 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
if node.right is ast.StringLiteral || node.right is ast.StringInterLiteral {
|
||||
c.error('cannot take the address of a string', node.pos)
|
||||
}
|
||||
if node.right is ast.IndexExpr as index {
|
||||
typ_sym := c.table.get_type_symbol(index.left_type)
|
||||
if mut node.right is ast.IndexExpr {
|
||||
typ_sym := c.table.get_type_symbol(node.right.left_type)
|
||||
mut is_mut := false
|
||||
if index.left is ast.Ident as ident {
|
||||
if mut node.right.left is ast.Ident {
|
||||
ident := node.right.left
|
||||
if ident.obj is ast.Var {
|
||||
v := ident.obj as ast.Var
|
||||
is_mut = v.is_mut
|
||||
|
@ -2906,11 +2905,11 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
if !c.inside_unsafe && is_mut {
|
||||
if typ_sym.kind == .map {
|
||||
c.error('cannot take the address of mutable map values outside unsafe blocks',
|
||||
index.pos)
|
||||
node.right.pos)
|
||||
}
|
||||
if typ_sym.kind == .array {
|
||||
c.error('cannot take the address of mutable array elements outside unsafe blocks',
|
||||
index.pos)
|
||||
node.right.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3049,10 +3048,9 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) table.Type {
|
|||
} else if node.expr_type == table.string_type {
|
||||
if to_type_sym.kind != .alias {
|
||||
mut error_msg := 'cannot cast a string'
|
||||
if node.expr is ast.StringLiteral {
|
||||
str_lit := node.expr as ast.StringLiteral
|
||||
if str_lit.val.len == 1 {
|
||||
error_msg += ", for denoting characters use `$str_lit.val` instead of '$str_lit.val'"
|
||||
if mut node.expr is ast.StringLiteral {
|
||||
if node.expr.val.len == 1 {
|
||||
error_msg += ", for denoting characters use `$node.expr.val` instead of '$node.expr.val'"
|
||||
}
|
||||
}
|
||||
c.error(error_msg, node.pos)
|
||||
|
@ -3203,9 +3201,8 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
|||
c.prevent_sum_type_unwrapping_once = false
|
||||
mut typ := if is_sum_type_cast { obj.sum_type_cast } else { obj.typ }
|
||||
if typ == 0 {
|
||||
if obj.expr is ast.Ident {
|
||||
inner_ident := obj.expr as ast.Ident
|
||||
if inner_ident.kind == .unresolved {
|
||||
if mut obj.expr is ast.Ident {
|
||||
if obj.expr.kind == .unresolved {
|
||||
c.error('unresolved variable: `$ident.name`', ident.pos)
|
||||
return table.void_type
|
||||
}
|
||||
|
@ -3446,7 +3443,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
|
|||
}
|
||||
continue
|
||||
}
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.Type {
|
||||
key = c.table.type_to_str(expr.typ)
|
||||
expr_types << expr
|
||||
|
@ -3518,28 +3515,28 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
|
|||
expr_type = expr_types[0].typ
|
||||
}
|
||||
mut scope := c.file.scope.innermost(branch.pos.pos)
|
||||
match node.cond as node_cond {
|
||||
match mut node.cond {
|
||||
ast.SelectorExpr {
|
||||
expr_sym := c.table.get_type_symbol(node_cond.expr_type)
|
||||
field := c.table.struct_find_field(expr_sym, node_cond.field_name) or {
|
||||
expr_sym := c.table.get_type_symbol(node.cond.expr_type)
|
||||
field := c.table.struct_find_field(expr_sym, node.cond.field_name) or {
|
||||
table.Field{}
|
||||
}
|
||||
is_mut := field.is_mut
|
||||
is_root_mut := scope.is_selector_root_mutable(c.table, node_cond)
|
||||
is_root_mut := scope.is_selector_root_mutable(c.table, node.cond)
|
||||
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
||||
if (!is_root_mut && !is_mut) || node.is_mut {
|
||||
scope.register_struct_field(ast.ScopeStructField{
|
||||
struct_type: node_cond.expr_type
|
||||
name: node_cond.field_name
|
||||
struct_type: node.cond.expr_type
|
||||
name: node.cond.field_name
|
||||
typ: node.cond_type
|
||||
sum_type_cast: expr_type
|
||||
pos: node_cond.pos
|
||||
pos: node.cond.pos
|
||||
})
|
||||
}
|
||||
}
|
||||
ast.Ident {
|
||||
mut is_mut := false
|
||||
if v := scope.find_var(node_cond.name) {
|
||||
if v := scope.find_var(node.cond.name) {
|
||||
is_mut = v.is_mut
|
||||
}
|
||||
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
||||
|
@ -3547,7 +3544,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
|
|||
scope.register(node.var_name, ast.Var{
|
||||
name: node.var_name
|
||||
typ: node.cond_type
|
||||
pos: node_cond.pos
|
||||
pos: node.cond.pos
|
||||
is_used: true
|
||||
is_mut: node.is_mut
|
||||
sum_type_cast: expr_type
|
||||
|
@ -3648,10 +3645,10 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
|
|||
stmt.pos)
|
||||
}
|
||||
} else {
|
||||
if stmt.expr is ast.InfixExpr as expr {
|
||||
if expr.left !is ast.Ident &&
|
||||
expr.left !is ast.SelectorExpr && expr.left !is ast.IndexExpr {
|
||||
c.error('channel in `select` key must be predefined', expr.left.position())
|
||||
if stmt.expr is ast.InfixExpr {
|
||||
if stmt.expr.left !is ast.Ident &&
|
||||
stmt.expr.left !is ast.SelectorExpr && stmt.expr.left !is ast.IndexExpr {
|
||||
c.error('channel in `select` key must be predefined', stmt.expr.left.position())
|
||||
}
|
||||
} else {
|
||||
c.error('invalid expression for `select` key', stmt.expr.position())
|
||||
|
@ -3659,7 +3656,8 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
|
|||
}
|
||||
}
|
||||
ast.AssignStmt {
|
||||
match stmt.right[0] as expr {
|
||||
expr := stmt.right[0]
|
||||
match union expr {
|
||||
ast.PrefixExpr {
|
||||
if expr.right !is ast.Ident &&
|
||||
expr.right !is ast.SelectorExpr && expr.right !is ast.IndexExpr {
|
||||
|
@ -3774,15 +3772,14 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
|||
if (infix.left is ast.Ident ||
|
||||
infix.left is ast.SelectorExpr) &&
|
||||
infix.right is ast.Type {
|
||||
is_variable := if infix.left is ast.Ident { (infix.left as ast.Ident).kind ==
|
||||
.variable } else { true }
|
||||
is_variable := if mut infix.left is ast.Ident { infix.left.kind == .variable } else { true }
|
||||
// Register shadow variable or `as` variable with actual type
|
||||
if is_variable {
|
||||
if left_sym.kind in [.sum_type, .interface_, .union_sum_type] {
|
||||
mut is_mut := false
|
||||
mut scope := c.file.scope.innermost(branch.body_pos.pos)
|
||||
if infix.left is ast.Ident as infix_left {
|
||||
if v := scope.find_var(infix_left.name) {
|
||||
if mut infix.left is ast.Ident {
|
||||
if v := scope.find_var(infix.left.name) {
|
||||
is_mut = v.is_mut
|
||||
}
|
||||
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
||||
|
@ -3792,29 +3789,29 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
|||
name: branch.left_as_name
|
||||
typ: infix.left_type
|
||||
sum_type_cast: right_expr.typ
|
||||
pos: infix.left.position()
|
||||
pos: infix.left.pos
|
||||
is_used: true
|
||||
is_mut: is_mut
|
||||
})
|
||||
}
|
||||
} else if infix.left is ast.SelectorExpr as selector {
|
||||
expr_sym := c.table.get_type_symbol(selector.expr_type)
|
||||
field := c.table.struct_find_field(expr_sym, selector.field_name) or {
|
||||
} else if mut infix.left is ast.SelectorExpr {
|
||||
expr_sym := c.table.get_type_symbol(infix.left.expr_type)
|
||||
field := c.table.struct_find_field(expr_sym, infix.left.field_name) or {
|
||||
table.Field{}
|
||||
}
|
||||
is_mut = field.is_mut
|
||||
is_root_mut := scope.is_selector_root_mutable(c.table,
|
||||
selector)
|
||||
infix.left)
|
||||
// smartcast either if the value is immutable or if the mut argument is explicitly given
|
||||
if ((!is_root_mut && !is_mut) ||
|
||||
branch.is_mut_name) &&
|
||||
left_sym.kind == .union_sum_type {
|
||||
scope.register_struct_field(ast.ScopeStructField{
|
||||
struct_type: selector.expr_type
|
||||
name: selector.field_name
|
||||
struct_type: infix.left.expr_type
|
||||
name: infix.left.field_name
|
||||
typ: infix.left_type
|
||||
sum_type_cast: right_expr.typ
|
||||
pos: infix.left.position()
|
||||
pos: infix.left.pos
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3946,7 +3943,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
|||
// saying whether that branch's contents should be skipped (targets a different os for example)
|
||||
fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
|
||||
// TODO: better error messages here
|
||||
match cond {
|
||||
match union cond {
|
||||
ast.ParExpr {
|
||||
return c.comp_if_branch(cond.expr, pos)
|
||||
}
|
||||
|
@ -3959,8 +3956,8 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
|
|||
ast.PostfixExpr {
|
||||
if cond.op != .question {
|
||||
c.error('invalid \$if postfix operator', cond.pos)
|
||||
} else if cond.expr is ast.Ident as ident {
|
||||
return ident.name !in c.pref.compile_defines_all
|
||||
} else if cond.expr is ast.Ident {
|
||||
return cond.expr.name !in c.pref.compile_defines_all
|
||||
} else {
|
||||
c.error('invalid `\$if` condition', cond.pos)
|
||||
}
|
||||
|
@ -4093,10 +4090,9 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
|
|||
}
|
||||
if !c.inside_unsafe && (typ.is_ptr() || typ.is_pointer()) {
|
||||
mut is_ok := false
|
||||
if node.left is ast.Ident {
|
||||
ident := node.left as ast.Ident
|
||||
scope := c.file.scope.innermost(ident.pos.pos)
|
||||
if v := scope.find_var(ident.name) {
|
||||
if mut node.left is ast.Ident {
|
||||
scope := c.file.scope.innermost(node.left.pos.pos)
|
||||
if v := scope.find_var(node.left.name) {
|
||||
// `mut param []T` function parameter
|
||||
is_ok = v.is_mut && v.is_arg && !typ.deref().is_ptr()
|
||||
}
|
||||
|
@ -4105,13 +4101,13 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) table.Type {
|
|||
c.warn('pointer indexing is only allowed in `unsafe` blocks', node.pos)
|
||||
}
|
||||
}
|
||||
if node.index is ast.RangeExpr as range { // [1..2]
|
||||
if range.has_low {
|
||||
index_type := c.expr(range.low)
|
||||
if mut node.index is ast.RangeExpr { // [1..2]
|
||||
if node.index.has_low {
|
||||
index_type := c.expr(node.index.low)
|
||||
c.check_index_type(typ_sym, index_type, node.pos)
|
||||
}
|
||||
if range.has_high {
|
||||
index_type := c.expr(range.high)
|
||||
if node.index.has_high {
|
||||
index_type := c.expr(node.index.high)
|
||||
c.check_index_type(typ_sym, index_type, node.pos)
|
||||
}
|
||||
// array[1..2] => array
|
||||
|
@ -4559,8 +4555,8 @@ fn has_top_return(stmts []ast.Stmt) bool {
|
|||
return true
|
||||
}
|
||||
} else if stmt is ast.ExprStmt {
|
||||
if stmt.expr is ast.CallExpr as ce {
|
||||
if ce.name in ['panic', 'exit'] {
|
||||
if stmt.expr is ast.CallExpr {
|
||||
if stmt.expr.name in ['panic', 'exit'] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,8 +222,8 @@ pub fn (mut d Doc) file_ast(file_ast ast.File) map[string]DocNode {
|
|||
for sidx, stmt in stmts {
|
||||
// eprintln('stmt typeof: ' + typeof(stmt))
|
||||
if stmt is ast.ExprStmt {
|
||||
if stmt.expr is ast.Comment as cmt {
|
||||
prev_comments << cmt
|
||||
if stmt.expr is ast.Comment {
|
||||
prev_comments << stmt.expr
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
|
@ -771,7 +771,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||
if f.is_debug {
|
||||
eprintln('expr: ${node.position():-42} | node: ${typeof(node):-20} | $node.str()')
|
||||
}
|
||||
match mut node {
|
||||
match union mut node {
|
||||
ast.CTempVar {
|
||||
eprintln('ast.CTempVar of $node.orig.str() should be generated/used only in cgen')
|
||||
}
|
||||
|
@ -1366,9 +1366,9 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
|
|||
}
|
||||
f.expr_bufs << f.out.str()
|
||||
mut penalty := 3
|
||||
match node.left as left {
|
||||
match union mut node.left {
|
||||
ast.InfixExpr {
|
||||
if int(token.precedences[left.op]) > int(token.precedences[node.op]) {
|
||||
if int(token.precedences[node.left.op]) > int(token.precedences[node.op]) {
|
||||
penalty--
|
||||
}
|
||||
}
|
||||
|
@ -1377,7 +1377,7 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
|
|||
}
|
||||
else {}
|
||||
}
|
||||
match node.right as right {
|
||||
match union node.right {
|
||||
ast.InfixExpr { penalty-- }
|
||||
ast.ParExpr { penalty = 1 }
|
||||
else {}
|
||||
|
@ -1418,11 +1418,11 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
|
|||
for i, branch in it.branches {
|
||||
// Check `sum is T` smartcast
|
||||
mut smartcast_as := false
|
||||
if branch.cond is ast.InfixExpr as infix {
|
||||
if infix.op == .key_is {
|
||||
// left_as_name is either empty, infix.left.str() or the `as` name
|
||||
if branch.cond is ast.InfixExpr {
|
||||
if branch.cond.op == .key_is {
|
||||
// left_as_name is either empty, branch.cond.left.str() or the `as` name
|
||||
smartcast_as = branch.left_as_name.len > 0 &&
|
||||
infix.left.str() != branch.left_as_name
|
||||
branch.cond.left.str() != branch.left_as_name
|
||||
}
|
||||
}
|
||||
if i == 0 {
|
||||
|
@ -1513,16 +1513,15 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||
}
|
||||
}
|
||||
if node.left is ast.Ident {
|
||||
left := node.left as ast.Ident
|
||||
// `time.now()` without `time imported` is processed as a method call with `time` being
|
||||
// a `node.left` expression. Import `time` automatically.
|
||||
// TODO fetch all available modules
|
||||
if left.name in ['time', 'os', 'strings', 'math', 'json', 'base64'] {
|
||||
if left.name !in f.auto_imports {
|
||||
f.auto_imports << left.name
|
||||
if node.left.name in ['time', 'os', 'strings', 'math', 'json', 'base64'] {
|
||||
if node.left.name !in f.auto_imports {
|
||||
f.auto_imports << node.left.name
|
||||
f.file.imports << ast.Import{
|
||||
mod: left.name
|
||||
alias: left.name
|
||||
mod: node.left.name
|
||||
alias: node.left.name
|
||||
}
|
||||
}
|
||||
// for imp in f.file.imports {
|
||||
|
@ -1540,8 +1539,8 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||
f.or_expr(node.or_block)
|
||||
} else {
|
||||
f.write_language_prefix(node.language)
|
||||
if node.left is ast.AnonFn as anon_fn {
|
||||
f.fn_decl(anon_fn.decl)
|
||||
if node.left is ast.AnonFn {
|
||||
f.fn_decl(node.left.decl)
|
||||
} else {
|
||||
mut name := f.short_module(node.name)
|
||||
f.mark_module_as_used(name)
|
||||
|
@ -1565,13 +1564,16 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||
|
||||
pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
|
||||
f.write('match ')
|
||||
// TODO: temporary, remove again
|
||||
if it.is_union_match {
|
||||
f.write('union ')
|
||||
}
|
||||
if it.is_mut {
|
||||
f.write('mut ')
|
||||
}
|
||||
f.expr(it.cond)
|
||||
if it.cond is ast.Ident {
|
||||
ident := it.cond as ast.Ident
|
||||
f.it_name = ident.name
|
||||
f.it_name = it.cond.name
|
||||
} else if it.cond is ast.SelectorExpr {
|
||||
// `x.y as z`
|
||||
// if ident.name != it.var_name && it.var_name != '' {
|
||||
|
@ -1702,7 +1704,7 @@ fn stmt_is_single_line(stmt ast.Stmt) bool {
|
|||
}
|
||||
|
||||
fn expr_is_single_line(expr ast.Expr) bool {
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.IfExpr { return false }
|
||||
ast.Comment { return false }
|
||||
else {}
|
||||
|
|
|
@ -1418,13 +1418,12 @@ fn (mut g Gen) gen_attrs(attrs []table.Attr) {
|
|||
fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
|
||||
mut a := original_assert_statement
|
||||
g.writeln('// assert')
|
||||
if a.expr is ast.InfixExpr {
|
||||
mut aie := a.expr as ast.InfixExpr
|
||||
if aie.left is ast.CallExpr {
|
||||
aie.left = g.new_ctemp_var_then_gen(aie.left, aie.left_type)
|
||||
if mut a.expr is ast.InfixExpr {
|
||||
if mut a.expr.left is ast.CallExpr {
|
||||
a.expr.left = g.new_ctemp_var_then_gen(a.expr.left, a.expr.left_type)
|
||||
}
|
||||
if aie.right is ast.CallExpr {
|
||||
aie.right = g.new_ctemp_var_then_gen(aie.right, aie.right_type)
|
||||
if mut a.expr.right is ast.CallExpr {
|
||||
a.expr.right = g.new_ctemp_var_then_gen(a.expr.right, a.expr.right_type)
|
||||
}
|
||||
}
|
||||
g.inside_ternary++
|
||||
|
@ -1471,17 +1470,17 @@ fn (mut g Gen) gen_assert_metainfo(a ast.AssertStmt) string {
|
|||
g.writeln('\t${metaname}.line_nr = $line_nr;')
|
||||
g.writeln('\t${metaname}.fn_name = ${ctoslit(fn_name)};')
|
||||
g.writeln('\t${metaname}.src = ${cnewlines(ctoslit(src))};')
|
||||
match a.expr {
|
||||
match union mut a.expr {
|
||||
ast.InfixExpr {
|
||||
g.writeln('\t${metaname}.op = ${ctoslit(it.op.str())};')
|
||||
g.writeln('\t${metaname}.llabel = ${cnewlines(ctoslit(it.left.str()))};')
|
||||
g.writeln('\t${metaname}.rlabel = ${cnewlines(ctoslit(it.right.str()))};')
|
||||
g.writeln('\t${metaname}.op = ${ctoslit(a.expr.op.str())};')
|
||||
g.writeln('\t${metaname}.llabel = ${cnewlines(ctoslit(a.expr.left.str()))};')
|
||||
g.writeln('\t${metaname}.rlabel = ${cnewlines(ctoslit(a.expr.right.str()))};')
|
||||
g.write('\t${metaname}.lvalue = ')
|
||||
g.gen_assert_single_expr(it.left, it.left_type)
|
||||
g.gen_assert_single_expr(a.expr.left, a.expr.left_type)
|
||||
g.writeln(';')
|
||||
//
|
||||
g.write('\t${metaname}.rvalue = ')
|
||||
g.gen_assert_single_expr(it.right, it.right_type)
|
||||
g.gen_assert_single_expr(a.expr.right, a.expr.right_type)
|
||||
g.writeln(';')
|
||||
}
|
||||
ast.CallExpr {
|
||||
|
@ -1494,7 +1493,7 @@ fn (mut g Gen) gen_assert_metainfo(a ast.AssertStmt) string {
|
|||
|
||||
fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) {
|
||||
unknown_value := '*unknown value*'
|
||||
match e {
|
||||
match union e {
|
||||
ast.CastExpr, ast.IndexExpr, ast.MatchExpr {
|
||||
g.write(ctoslit(unknown_value))
|
||||
}
|
||||
|
@ -1544,9 +1543,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
mut return_type := table.void_type
|
||||
op := if assign_stmt.op == .decl_assign { token.Kind.assign } else { assign_stmt.op }
|
||||
is_decl := assign_stmt.op == .decl_assign
|
||||
match assign_stmt.right[0] {
|
||||
ast.CallExpr, ast.MatchExpr { return_type = it.return_type }
|
||||
ast.IfExpr { return_type = it.typ }
|
||||
right_expr := assign_stmt.right[0]
|
||||
match union right_expr {
|
||||
ast.CallExpr { return_type = right_expr.return_type }
|
||||
ast.MatchExpr { return_type = right_expr.return_type }
|
||||
ast.IfExpr { return_type = right_expr.typ }
|
||||
else {}
|
||||
}
|
||||
// Free the old value assigned to this string var (only if it's `str = [new value]`)
|
||||
|
@ -1630,13 +1631,10 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.is_assign_rhs = false
|
||||
g.writeln(';')
|
||||
for i, lx in assign_stmt.left {
|
||||
match lx {
|
||||
ast.Ident {
|
||||
if lx.kind == .blank_ident {
|
||||
continue
|
||||
}
|
||||
if lx is ast.Ident {
|
||||
if lx.kind == .blank_ident {
|
||||
continue
|
||||
}
|
||||
else {}
|
||||
}
|
||||
styp := g.typ(assign_stmt.left_types[i])
|
||||
if assign_stmt.op == .decl_assign {
|
||||
|
@ -1656,7 +1654,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
// TODO: non idents on left (exprs)
|
||||
if assign_stmt.has_cross_var {
|
||||
for i, left in assign_stmt.left {
|
||||
match left {
|
||||
match union left {
|
||||
ast.Ident {
|
||||
left_typ := assign_stmt.left_types[i]
|
||||
left_sym := g.table.get_type_symbol(left_typ)
|
||||
|
@ -1720,6 +1718,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.write('$styp _var_$left.pos.pos = ')
|
||||
g.expr(left.expr)
|
||||
if left.expr_type.is_ptr() {
|
||||
g.write('/* left.expr_type */')
|
||||
g.writeln('->$left.field_name;')
|
||||
} else {
|
||||
g.writeln('.$left.field_name;')
|
||||
|
@ -1738,7 +1737,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
mut blank_assign := false
|
||||
mut ident := ast.Ident{}
|
||||
if left is ast.Ident {
|
||||
ident = *left
|
||||
ident = left
|
||||
// id_info := ident.var_info()
|
||||
// var_type = id_info.typ
|
||||
blank_assign = left.kind == .blank_ident
|
||||
|
@ -1755,7 +1754,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
styp := g.typ(var_type)
|
||||
mut is_fixed_array_init := false
|
||||
mut has_val := false
|
||||
match val {
|
||||
match union val {
|
||||
ast.ArrayInit {
|
||||
is_fixed_array_init = val.is_fixed
|
||||
has_val = val.has_val
|
||||
|
@ -1775,7 +1774,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.fn_args(val.decl.params, val.decl.is_variadic)
|
||||
g.definitions.go_back(g.definitions.len - def_pos)
|
||||
g.write(') = ')
|
||||
g.expr(*val)
|
||||
g.expr(val)
|
||||
g.writeln(';')
|
||||
if blank_assign {
|
||||
g.write('}')
|
||||
|
@ -1956,7 +1955,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
|
||||
fn (mut g Gen) gen_cross_tmp_variable(left []ast.Expr, val ast.Expr) {
|
||||
val_ := val
|
||||
match val {
|
||||
match union val {
|
||||
ast.Ident {
|
||||
mut has_var := false
|
||||
for lx in left {
|
||||
|
@ -2195,7 +2194,7 @@ fn (mut g Gen) gen_anon_fn_decl(it ast.AnonFn) {
|
|||
fn (mut g Gen) expr(node ast.Expr) {
|
||||
// println('cgen expr() line_nr=$node.pos.line_nr')
|
||||
// NB: please keep the type names in the match here in alphabetical order:
|
||||
match node {
|
||||
match union node {
|
||||
ast.AnonFn {
|
||||
// TODO: dont fiddle with buffers
|
||||
g.gen_anon_fn_decl(node)
|
||||
|
@ -2668,7 +2667,7 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) enum_expr(node ast.Expr) {
|
||||
match node {
|
||||
match union node {
|
||||
ast.EnumVal { g.write(node.val) }
|
||||
else { g.expr(node) }
|
||||
}
|
||||
|
@ -2832,19 +2831,16 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
g.write('!')
|
||||
}
|
||||
if right_sym.kind == .array {
|
||||
match node.right {
|
||||
ast.ArrayInit {
|
||||
if it.exprs.len > 0 {
|
||||
// `a in [1,2,3]` optimization => `a == 1 || a == 2 || a == 3`
|
||||
// avoids an allocation
|
||||
// g.write('/*in opt*/')
|
||||
g.write('(')
|
||||
g.in_optimization(node.left, it)
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
if mut node.right is ast.ArrayInit {
|
||||
if node.right.exprs.len > 0 {
|
||||
// `a in [1,2,3]` optimization => `a == 1 || a == 2 || a == 3`
|
||||
// avoids an allocation
|
||||
// g.write('/*in opt*/')
|
||||
g.write('(')
|
||||
g.in_optimization(node.left, node.right)
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
else {}
|
||||
}
|
||||
if left_sym.kind == .function {
|
||||
g.write('_IN(voidptr, ')
|
||||
|
@ -3163,9 +3159,9 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str
|
|||
} else if expr is ast.RangeExpr {
|
||||
// if type is unsigned and low is 0, check is unneeded
|
||||
mut skip_low := false
|
||||
if expr.low is ast.IntegerLiteral as expr_low {
|
||||
if expr.low is ast.IntegerLiteral {
|
||||
if node.cond_type in [table.u16_type, table.u32_type, table.u64_type] &&
|
||||
expr_low.val == '0' {
|
||||
expr.low.val == '0' {
|
||||
skip_low = true
|
||||
}
|
||||
}
|
||||
|
@ -3526,14 +3522,14 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|||
g.writeln('\tint errcode = ${cvar_name}.ecode;')
|
||||
}
|
||||
} else {
|
||||
match branch.cond as cond {
|
||||
match union branch.cond {
|
||||
ast.IfGuardExpr {
|
||||
var_name := guard_vars[i]
|
||||
g.write('if ($var_name = ')
|
||||
g.expr(it.expr)
|
||||
g.expr(branch.cond.expr)
|
||||
g.writeln(', ${var_name}.ok) {')
|
||||
if cond.var_name != '_' {
|
||||
g.writeln('\t${g.typ(cond.expr_type)} $cond.var_name = $var_name;')
|
||||
if branch.cond.var_name != '_' {
|
||||
g.writeln('\t${g.typ(branch.cond.expr_type)} $branch.cond.var_name = $var_name;')
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -3575,7 +3571,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
match node.index {
|
||||
match union node.index {
|
||||
ast.RangeExpr {
|
||||
sym := g.table.get_type_symbol(node.left_type)
|
||||
if sym.kind == .string {
|
||||
|
@ -3602,14 +3598,14 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||
g.expr(node.left)
|
||||
}
|
||||
g.write(', ')
|
||||
if it.has_low {
|
||||
g.expr(it.low)
|
||||
if node.index.has_low {
|
||||
g.expr(node.index.low)
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
g.write(', ')
|
||||
if it.has_high {
|
||||
g.expr(it.high)
|
||||
if node.index.has_high {
|
||||
g.expr(node.index.high)
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
g.write('.len')
|
||||
|
@ -3828,7 +3824,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||
|
||||
[inline]
|
||||
fn (g &Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.CallExpr { return g.table.get_type_symbol(expr.return_type).kind == .multi_return }
|
||||
else { return false }
|
||||
}
|
||||
|
@ -4051,13 +4047,13 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|||
}
|
||||
} else {
|
||||
*/
|
||||
match field.expr {
|
||||
match union field.expr {
|
||||
ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral {
|
||||
g.const_decl_simple_define(name, val)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
if it.is_fixed {
|
||||
styp := g.typ(it.typ)
|
||||
if field.expr.is_fixed {
|
||||
styp := g.typ(field.expr.typ)
|
||||
g.definitions.writeln('$styp _const_$name = $val; // fixed array const')
|
||||
} else {
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ)
|
||||
|
@ -4710,7 +4706,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
|
|||
g.expr(expr)
|
||||
return true
|
||||
} else if sym.kind == .enum_ {
|
||||
is_var := match expr {
|
||||
is_var := match union expr {
|
||||
ast.SelectorExpr, ast.Ident { true }
|
||||
else { false }
|
||||
}
|
||||
|
@ -4808,19 +4804,20 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
|||
g.expr(node.left)
|
||||
g.writeln('.data)[$i];')
|
||||
g.write('\t$ret_elem_type ti = ')
|
||||
match node.args[0].expr {
|
||||
expr := node.args[0].expr
|
||||
match union expr {
|
||||
ast.AnonFn {
|
||||
g.gen_anon_fn_decl(it)
|
||||
g.write('${it.decl.name}(it)')
|
||||
g.gen_anon_fn_decl(expr)
|
||||
g.write('${expr.decl.name}(it)')
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .function {
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
} else if it.kind == .variable {
|
||||
var_info := it.var_info()
|
||||
if expr.kind == .function {
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else if expr.kind == .variable {
|
||||
var_info := expr.var_info()
|
||||
sym := g.table.get_type_symbol(var_info.typ)
|
||||
if sym.kind == .function {
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
|
@ -4962,19 +4959,20 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
|
|||
g.expr(node.left)
|
||||
g.writeln('.data)[i];')
|
||||
g.write('if (')
|
||||
match node.args[0].expr {
|
||||
expr := node.args[0].expr
|
||||
match union expr {
|
||||
ast.AnonFn {
|
||||
g.gen_anon_fn_decl(it)
|
||||
g.write('${it.decl.name}(it)')
|
||||
g.gen_anon_fn_decl(expr)
|
||||
g.write('${expr.decl.name}(it)')
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .function {
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
} else if it.kind == .variable {
|
||||
var_info := it.var_info()
|
||||
if expr.kind == .function {
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else if expr.kind == .variable {
|
||||
var_info := expr.var_info()
|
||||
sym_t := g.table.get_type_symbol(var_info.typ)
|
||||
if sym_t.kind == .function {
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
g.write('${c_name(expr.name)}(it)')
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
|
@ -5152,7 +5150,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
|
|||
}
|
||||
|
||||
fn (mut g Gen) type_of_call_expr(node ast.Expr) string {
|
||||
match node {
|
||||
match union node {
|
||||
ast.CallExpr { return g.typ(node.return_type) }
|
||||
else { return typeof(node) }
|
||||
}
|
||||
|
@ -5461,9 +5459,9 @@ fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
|||
if expr.is_method {
|
||||
receiver_sym := g.table.get_type_symbol(expr.receiver_type)
|
||||
name = receiver_sym.name + '_' + name
|
||||
} else if expr.left is ast.AnonFn as anon_fn {
|
||||
g.gen_anon_fn_decl(anon_fn)
|
||||
fsym := g.table.get_type_symbol(anon_fn.typ)
|
||||
} else if expr.left is ast.AnonFn {
|
||||
g.gen_anon_fn_decl(expr.left)
|
||||
fsym := g.table.get_type_symbol(expr.left.typ)
|
||||
name = fsym.name
|
||||
}
|
||||
name = util.no_dots(name)
|
||||
|
|
|
@ -45,8 +45,7 @@ fn (mut g Gen) comptime_call(node ast.ComptimeCall) {
|
|||
}
|
||||
for i in 1 .. m.params.len {
|
||||
if node.left is ast.Ident {
|
||||
left_name := node.left as ast.Ident
|
||||
if m.params[i].name == left_name.name {
|
||||
if m.params[i].name == node.left.name {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +174,7 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) comp_if_expr(cond ast.Expr) {
|
||||
match cond {
|
||||
match union cond {
|
||||
ast.ParExpr {
|
||||
g.write('(')
|
||||
g.comp_if_expr(cond.expr)
|
||||
|
|
|
@ -403,7 +403,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
mut is_range_slice := false
|
||||
if node.receiver_type.is_ptr() && !node.left_type.is_ptr() {
|
||||
if node.left is ast.IndexExpr {
|
||||
idx := (node.left as ast.IndexExpr).index
|
||||
idx := node.left.index
|
||||
if idx is ast.RangeExpr {
|
||||
// expr is arr[range].clone()
|
||||
// use array_clone_static instead of array_clone
|
||||
|
@ -569,7 +569,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp')
|
||||
} else {
|
||||
expr := node.args[0].expr
|
||||
is_var := match expr {
|
||||
is_var := match union expr {
|
||||
ast.SelectorExpr { true }
|
||||
ast.Ident { true }
|
||||
else { false }
|
||||
|
@ -665,7 +665,7 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
|
|||
if arg.expr is ast.CallExpr {
|
||||
// Any argument can be an expression that has to be freed. Generate a tmp expression
|
||||
// for each of those recursively.
|
||||
g.autofree_call_pregen(arg.expr as ast.CallExpr)
|
||||
g.autofree_call_pregen(arg.expr)
|
||||
}
|
||||
free_tmp_arg_vars = true
|
||||
// t := g.new_tmp_var() + '_arg_expr_${name}_$i'
|
||||
|
|
|
@ -523,7 +523,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) expr(node ast.Expr) {
|
||||
match node {
|
||||
match union node {
|
||||
ast.CTempVar {
|
||||
g.write('/* ast.CTempVar: node.name */')
|
||||
}
|
||||
|
@ -1008,19 +1008,19 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
|
|||
|
||||
fn (mut g JsGen) gen_go_stmt(node ast.GoStmt) {
|
||||
// x := node.call_expr as ast.CallEpxr // TODO
|
||||
match node.call_expr {
|
||||
match union node.call_expr {
|
||||
ast.CallExpr {
|
||||
mut name := it.name
|
||||
if it.is_method {
|
||||
receiver_sym := g.table.get_type_symbol(it.receiver_type)
|
||||
mut name := node.call_expr.name
|
||||
if node.call_expr.is_method {
|
||||
receiver_sym := g.table.get_type_symbol(node.call_expr.receiver_type)
|
||||
name = receiver_sym.name + '.' + name
|
||||
}
|
||||
g.writeln('await new Promise(function(resolve){')
|
||||
g.inc_indent()
|
||||
g.write('${name}(')
|
||||
for i, arg in it.args {
|
||||
for i, arg in node.call_expr.args {
|
||||
g.expr(arg.expr)
|
||||
if i < it.args.len - 1 {
|
||||
if i < node.call_expr.args.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
|
@ -1184,21 +1184,22 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
|||
node := it
|
||||
g.write(it.name)
|
||||
g.write('(')
|
||||
match node.args[0].expr {
|
||||
expr := node.args[0].expr
|
||||
match union expr {
|
||||
ast.AnonFn {
|
||||
g.gen_fn_decl(it.decl)
|
||||
g.gen_fn_decl(expr.decl)
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .function {
|
||||
g.write(g.js_name(it.name))
|
||||
if expr.kind == .function {
|
||||
g.write(g.js_name(expr.name))
|
||||
g.write(')')
|
||||
return
|
||||
} else if it.kind == .variable {
|
||||
v_sym := g.table.get_type_symbol(it.var_info().typ)
|
||||
} else if expr.kind == .variable {
|
||||
v_sym := g.table.get_type_symbol(expr.var_info().typ)
|
||||
if v_sym.kind == .function {
|
||||
g.write(g.js_name(it.name))
|
||||
g.write(g.js_name(expr.name))
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
|
@ -1302,17 +1303,16 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
|
|||
left_typ := g.table.get_type_symbol(expr.left_type)
|
||||
// TODO: Handle splice setting if it's implemented
|
||||
if expr.index is ast.RangeExpr {
|
||||
range := expr.index as ast.RangeExpr
|
||||
g.expr(expr.left)
|
||||
g.write('.slice(')
|
||||
if range.has_low {
|
||||
g.expr(range.low)
|
||||
if expr.index.has_low {
|
||||
g.expr(expr.index.low)
|
||||
} else {
|
||||
g.write('0')
|
||||
}
|
||||
g.write(', ')
|
||||
if range.has_high {
|
||||
g.expr(range.high)
|
||||
if expr.index.has_high {
|
||||
g.expr(expr.index.high)
|
||||
} else {
|
||||
g.expr(expr.left)
|
||||
g.write('.length')
|
||||
|
|
|
@ -256,7 +256,7 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
|||
//
|
||||
// TODO `where id = some_column + 1` needs literal generation of `some_column` as a string,
|
||||
// not a V variable. Need to distinguish column names from V variables.
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.InfixExpr {
|
||||
g.sql_side = .left
|
||||
g.expr_to_sql(expr.left)
|
||||
|
@ -275,22 +275,22 @@ fn (mut g Gen) expr_to_sql(expr ast.Expr) {
|
|||
else {}
|
||||
}
|
||||
g.sql_side = .right
|
||||
g.expr_to_sql(it.right)
|
||||
g.expr_to_sql(expr.right)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
// g.write("'$it.val'")
|
||||
g.inc_sql_i()
|
||||
g.sql_bind_string('"$it.val"', it.val.len.str())
|
||||
g.sql_bind_string('"$expr.val"', expr.val.len.str())
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.inc_sql_i()
|
||||
g.sql_bind_int(it.val)
|
||||
g.sql_bind_int(expr.val)
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
// true/false literals were added to Sqlite 3.23 (2018-04-02)
|
||||
// but lots of apps/distros use older sqlite (e.g. Ubuntu 18.04 LTS )
|
||||
g.inc_sql_i()
|
||||
g.sql_bind_int(if it.val {
|
||||
g.sql_bind_int(if expr.val {
|
||||
'1'
|
||||
} else {
|
||||
'0'
|
||||
|
|
|
@ -479,7 +479,7 @@ pub fn (mut g Gen) save_main_fn_addr() {
|
|||
}
|
||||
|
||||
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) {
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.StringLiteral {
|
||||
if newline {
|
||||
g.gen_print(expr.val + '\n')
|
||||
|
@ -575,7 +575,7 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
|
|||
// g.mov(.eax, 0)
|
||||
for i in 0 .. node.args.len {
|
||||
expr := node.args[i].expr
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.IntegerLiteral {
|
||||
// `foo(2)` => `mov edi,0x2`
|
||||
g.mov(fn_arg_registers[i], expr.val.int())
|
||||
|
@ -648,7 +648,7 @@ fn C.strtol() int
|
|||
|
||||
fn (mut g Gen) expr(node ast.Expr) {
|
||||
// println('cgen expr()')
|
||||
match node {
|
||||
match union node {
|
||||
ast.ArrayInit {}
|
||||
ast.BoolLiteral {}
|
||||
ast.CallExpr {
|
||||
|
@ -719,7 +719,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||
name := left.str()
|
||||
// if left is ast.Ident {
|
||||
// ident := left as ast.Ident
|
||||
match right {
|
||||
match union right {
|
||||
ast.IntegerLiteral {
|
||||
g.allocate_var(name, 4, right.val.int())
|
||||
}
|
||||
|
@ -755,13 +755,12 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
if node.left is ast.InfixExpr {
|
||||
verror('only simple expressions are supported right now (not more than 2 operands)')
|
||||
}
|
||||
match node.left {
|
||||
ast.Ident { g.mov_var_to_reg(.eax, g.get_var_offset(it.name)) }
|
||||
match union mut node.left {
|
||||
ast.Ident { g.mov_var_to_reg(.eax, g.get_var_offset(node.left.name)) }
|
||||
else {}
|
||||
}
|
||||
if node.right is ast.Ident {
|
||||
ident := node.right as ast.Ident
|
||||
var_offset := g.get_var_offset(ident.name)
|
||||
if mut node.right is ast.Ident {
|
||||
var_offset := g.get_var_offset(node.right.name)
|
||||
match node.op {
|
||||
.plus { g.add8_var(.eax, var_offset) }
|
||||
.mul { g.mul8_var(.eax, var_offset) }
|
||||
|
@ -775,10 +774,10 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|||
branch := node.branches[0]
|
||||
infix_expr := branch.cond as ast.InfixExpr
|
||||
mut jne_addr := 0 // location of `jne *00 00 00 00*`
|
||||
match infix_expr.left {
|
||||
match union mut infix_expr.left {
|
||||
ast.Ident {
|
||||
lit := infix_expr.right as ast.IntegerLiteral
|
||||
g.cmp_var(it.name, lit.val.int())
|
||||
g.cmp_var(infix_expr.left.name, lit.val.int())
|
||||
jne_addr = g.jne()
|
||||
}
|
||||
else {
|
||||
|
@ -798,10 +797,10 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
|||
// g.mov(.eax, 0x77777777)
|
||||
mut jump_addr := 0 // location of `jne *00 00 00 00*`
|
||||
start := g.pos()
|
||||
match infix_expr.left {
|
||||
match union mut infix_expr.left {
|
||||
ast.Ident {
|
||||
lit := infix_expr.right as ast.IntegerLiteral
|
||||
g.cmp_var(it.name, lit.val.int())
|
||||
g.cmp_var(infix_expr.left.name, lit.val.int())
|
||||
jump_addr = g.jge()
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -12,7 +12,7 @@ fn (mut p Parser) assign_stmt() ast.Stmt {
|
|||
}
|
||||
|
||||
fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) {
|
||||
match val {
|
||||
match union val {
|
||||
ast.Ident {
|
||||
for expr in exprs {
|
||||
if expr is ast.Ident {
|
||||
|
@ -46,7 +46,7 @@ fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) {
|
|||
|
||||
fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
|
||||
val_ := val
|
||||
match val_ {
|
||||
match union val_ {
|
||||
ast.Ident {
|
||||
for expr in exprs {
|
||||
if expr is ast.Ident {
|
||||
|
@ -113,7 +113,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
|
|||
}
|
||||
mut is_static := false
|
||||
for i, lx in left {
|
||||
match mut lx {
|
||||
match union mut lx {
|
||||
ast.Ident {
|
||||
if op == .decl_assign {
|
||||
if p.scope.known_var(lx.name) {
|
||||
|
|
|
@ -122,17 +122,17 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
|
|||
}
|
||||
comments << p.eat_comments()
|
||||
mut left_as_name := ''
|
||||
if cond is ast.InfixExpr as infix {
|
||||
if mut cond is ast.InfixExpr {
|
||||
// if sum is T
|
||||
is_is_cast := infix.op == .key_is
|
||||
is_ident := infix.left is ast.Ident
|
||||
is_is_cast := cond.op == .key_is
|
||||
is_ident := cond.left is ast.Ident
|
||||
left_as_name = if is_comptime {
|
||||
''
|
||||
} else if is_is_cast && p.tok.kind == .key_as {
|
||||
p.next()
|
||||
p.check_name()
|
||||
} else if is_ident {
|
||||
ident := infix.left as ast.Ident
|
||||
ident := cond.left as ast.Ident
|
||||
ident.name
|
||||
} else {
|
||||
''
|
||||
|
@ -223,7 +223,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
|
|||
p.peek_tok.kind == .dot) && (p.tok.lit in table.builtin_type_names || p.tok.lit[0].is_capital() ||
|
||||
(p.peek_tok.kind == .dot && p.peek_tok2.lit[0].is_capital())) {
|
||||
if var_name.len == 0 {
|
||||
match cond {
|
||||
match union cond {
|
||||
ast.Ident {
|
||||
// shadow match cond variable
|
||||
var_name = cond.name
|
||||
|
@ -366,6 +366,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
|
|||
branches: branches
|
||||
cond: cond
|
||||
is_sum_type: is_sum_type
|
||||
is_union_match: is_union_match
|
||||
pos: pos
|
||||
is_mut: is_mut
|
||||
var_name: var_name
|
||||
|
@ -447,11 +448,11 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
|
|||
if !stmt.is_expr {
|
||||
p.error_with_pos('select: invalid expression', stmt.pos)
|
||||
} else {
|
||||
match stmt.expr as expr {
|
||||
match union stmt.expr {
|
||||
ast.InfixExpr {
|
||||
if expr.op != .arrow {
|
||||
if stmt.expr.op != .arrow {
|
||||
p.error_with_pos('select key: `<-` operator expected',
|
||||
expr.pos)
|
||||
stmt.expr.pos)
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -462,7 +463,8 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
|
|||
}
|
||||
}
|
||||
ast.AssignStmt {
|
||||
match stmt.right[0] as expr {
|
||||
expr := stmt.right[0]
|
||||
match union expr {
|
||||
ast.PrefixExpr {
|
||||
if expr.op != .arrow {
|
||||
p.error_with_pos('select key: `<-` operator expected',
|
||||
|
|
|
@ -353,7 +353,7 @@ fn (mut p Parser) prefix_expr() ast.PrefixExpr {
|
|||
p.next()
|
||||
mut right := if op == .minus { p.expr(token.Precedence.call) } else { p.expr(token.Precedence.prefix) }
|
||||
p.is_amp = false
|
||||
if right is ast.CastExpr {
|
||||
if mut right is ast.CastExpr {
|
||||
right.in_prexpr = true
|
||||
}
|
||||
mut or_stmts := []ast.Stmt{}
|
||||
|
|
|
@ -129,7 +129,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
|||
mut table_name := ''
|
||||
if kind != .delete {
|
||||
expr := p.expr(0)
|
||||
match expr {
|
||||
match union expr {
|
||||
ast.Ident {
|
||||
if kind == .insert {
|
||||
inserted_var_name = expr.name
|
||||
|
|
|
@ -203,7 +203,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
// default_expr = p.tok.lit
|
||||
// p.expr(0)
|
||||
default_expr = p.expr(0)
|
||||
match mut default_expr {
|
||||
match union mut default_expr {
|
||||
ast.EnumVal { default_expr.typ = typ }
|
||||
// TODO: implement all types??
|
||||
else {}
|
||||
|
|
Loading…
Reference in New Issue