parser: assign.v, containers.v, for.v, if.v
parent
b53fb365a6
commit
59baef89a0
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2019-2020 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 parser
|
||||
|
||||
import v.ast
|
||||
import v.table
|
||||
import v.token
|
||||
|
||||
fn (var p Parser) assign_stmt() ast.Stmt {
|
||||
is_static := p.tok.kind == .key_static
|
||||
if is_static {
|
||||
p.next()
|
||||
}
|
||||
idents := p.parse_assign_lhs()
|
||||
op := p.tok.kind
|
||||
p.next() // :=, =
|
||||
pos := p.tok.position()
|
||||
exprs := p.parse_assign_rhs()
|
||||
is_decl := op == .decl_assign
|
||||
for i, ident in idents {
|
||||
known_var := p.scope.known_var(ident.name)
|
||||
if !is_decl && !known_var {
|
||||
p.error('unknown variable `$ident.name`')
|
||||
}
|
||||
if is_decl && ident.kind != .blank_ident {
|
||||
if p.scope.known_var(ident.name) {
|
||||
p.error('redefinition of `$ident.name`')
|
||||
}
|
||||
if idents.len == exprs.len {
|
||||
p.scope.register(ident.name, ast.Var{
|
||||
name: ident.name
|
||||
expr: exprs[i]
|
||||
is_mut: ident.is_mut || p.inside_for
|
||||
})
|
||||
} else {
|
||||
p.scope.register(ident.name, ast.Var{
|
||||
name: ident.name
|
||||
is_mut: ident.is_mut || p.inside_for
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ast.AssignStmt{
|
||||
left: idents
|
||||
right: exprs
|
||||
op: op
|
||||
pos: pos
|
||||
is_static: is_static
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: is it possible to merge with AssignStmt?
|
||||
pub fn (var p Parser) assign_expr(left ast.Expr) ast.AssignExpr {
|
||||
op := p.tok.kind
|
||||
p.next()
|
||||
pos := p.tok.position()
|
||||
val := p.expr(0)
|
||||
match left {
|
||||
ast.IndexExpr {
|
||||
// it.mark_as_setter()
|
||||
it.is_setter = true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
node := ast.AssignExpr{
|
||||
left: left
|
||||
val: val
|
||||
op: op
|
||||
pos: pos
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
fn (var p Parser) parse_assign_lhs() []ast.Ident {
|
||||
var idents := []ast.Ident
|
||||
for {
|
||||
is_mut := p.tok.kind == .key_mut || p.tok.kind == .key_var
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
is_static := p.tok.kind == .key_static
|
||||
if is_static {
|
||||
p.check(.key_static)
|
||||
}
|
||||
var ident := p.parse_ident(false, false)
|
||||
ident.is_mut = is_mut
|
||||
ident.info = ast.IdentVar{
|
||||
is_mut: is_mut
|
||||
is_static: is_static
|
||||
}
|
||||
idents << ident
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return idents
|
||||
}
|
||||
|
||||
// right hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
||||
fn (var p Parser) parse_assign_rhs() []ast.Expr {
|
||||
var exprs := []ast.Expr
|
||||
for {
|
||||
expr := p.expr(0)
|
||||
exprs << expr
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return exprs
|
||||
}
|
|
@ -2,3 +2,114 @@
|
|||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module parser
|
||||
|
||||
import v.ast
|
||||
import v.table
|
||||
import v.token
|
||||
|
||||
fn (var p Parser) array_init() ast.ArrayInit {
|
||||
first_pos := p.tok.position()
|
||||
var last_pos := token.Position{}
|
||||
p.check(.lsbr)
|
||||
// p.warn('array_init() exp=$p.expected_type')
|
||||
var array_type := table.void_type
|
||||
var elem_type := table.void_type
|
||||
var exprs := []ast.Expr
|
||||
var is_fixed := false
|
||||
if p.tok.kind == .rsbr {
|
||||
// []typ => `[]` and `typ` must be on the same line
|
||||
line_nr := p.tok.line_nr
|
||||
p.check(.rsbr)
|
||||
// []string
|
||||
if p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr {
|
||||
elem_type = p.parse_type()
|
||||
// this is set here becasue its a known type, others could be the
|
||||
// result of expr so we do those in checker
|
||||
idx := p.table.find_or_register_array(elem_type, 1)
|
||||
array_type = table.new_type(idx)
|
||||
}
|
||||
} else {
|
||||
// [1,2,3] or [const]byte
|
||||
for i := 0; p.tok.kind != .rsbr; i++ {
|
||||
expr := p.expr(0)
|
||||
exprs << expr
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
}
|
||||
// p.check_comment()
|
||||
}
|
||||
line_nr := p.tok.line_nr
|
||||
$if tinyc {
|
||||
// NB: do not remove the next line without testing
|
||||
// v selfcompilation with tcc first
|
||||
tcc_stack_bug := 12345
|
||||
}
|
||||
last_pos = p.tok.position()
|
||||
p.check(.rsbr)
|
||||
// [100]byte
|
||||
if exprs.len == 1 && p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr {
|
||||
elem_type = p.parse_type()
|
||||
is_fixed = true
|
||||
}
|
||||
}
|
||||
// !
|
||||
if p.tok.kind == .not {
|
||||
last_pos = p.tok.position()
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .not {
|
||||
last_pos = p.tok.position()
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .lcbr && exprs.len == 0 {
|
||||
// `[]int{ len: 10, cap: 100}` syntax
|
||||
p.next()
|
||||
for p.tok.kind != .rcbr {
|
||||
key := p.check_name()
|
||||
p.check(.colon)
|
||||
if !(key in ['len', 'cap', 'init']) {
|
||||
p.error('wrong field `$key`, expecting `len`, `cap`, or `init`')
|
||||
}
|
||||
p.expr(0)
|
||||
if p.tok.kind != .rcbr {
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
p.check(.rcbr)
|
||||
}
|
||||
pos := token.Position{
|
||||
line_nr: first_pos.line_nr
|
||||
pos: first_pos.pos
|
||||
len: last_pos.pos - first_pos.pos + last_pos.len
|
||||
}
|
||||
return ast.ArrayInit{
|
||||
is_fixed: is_fixed
|
||||
mod: p.mod
|
||||
elem_type: elem_type
|
||||
typ: array_type
|
||||
exprs: exprs
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) map_init() ast.MapInit {
|
||||
pos := p.tok.position()
|
||||
var keys := []ast.Expr
|
||||
var vals := []ast.Expr
|
||||
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
||||
// p.check(.str)
|
||||
key := p.expr(0)
|
||||
keys << key
|
||||
p.check(.colon)
|
||||
val := p.expr(0)
|
||||
vals << val
|
||||
if p.tok.kind == .comma {
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
return ast.MapInit{
|
||||
keys: keys
|
||||
vals: vals
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright (c) 2019-2020 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 parser
|
||||
|
||||
import v.ast
|
||||
import v.table
|
||||
import v.token
|
||||
|
||||
fn (var p Parser) for_stmt() ast.Stmt {
|
||||
p.check(.key_for)
|
||||
pos := p.tok.position()
|
||||
p.open_scope()
|
||||
p.inside_for = true
|
||||
// defer { p.close_scope() }
|
||||
// Infinite loop
|
||||
if p.tok.kind == .lcbr {
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
return ast.ForStmt{
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
is_inf: true
|
||||
}
|
||||
} else if p.tok.kind in [.key_mut, .key_var] {
|
||||
p.error('`mut` is not needed in for loops')
|
||||
} else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon {
|
||||
// `for i := 0; i < 10; i++ {`
|
||||
var init := ast.Stmt{}
|
||||
var cond := p.new_true_expr()
|
||||
// mut inc := ast.Stmt{}
|
||||
var inc := ast.Expr{}
|
||||
var has_init := false
|
||||
var has_cond := false
|
||||
var has_inc := false
|
||||
if p.peek_tok.kind in [.assign, .decl_assign] {
|
||||
init = p.assign_stmt()
|
||||
has_init = true
|
||||
} else if p.tok.kind != .semicolon {
|
||||
}
|
||||
// allow `for ;; i++ {`
|
||||
// Allow `for i = 0; i < ...`
|
||||
p.check(.semicolon)
|
||||
if p.tok.kind != .semicolon {
|
||||
var typ := table.void_type
|
||||
cond = p.expr(0)
|
||||
has_cond = true
|
||||
}
|
||||
p.check(.semicolon)
|
||||
if p.tok.kind != .lcbr {
|
||||
// inc = p.stmt()
|
||||
inc = p.expr(0)
|
||||
has_inc = true
|
||||
}
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
return ast.ForCStmt{
|
||||
stmts: stmts
|
||||
has_init: has_init
|
||||
has_cond: has_cond
|
||||
has_inc: has_inc
|
||||
init: init
|
||||
cond: cond
|
||||
inc: inc
|
||||
pos: pos
|
||||
}
|
||||
} else if p.peek_tok.kind in [.key_in, .comma] {
|
||||
// `for i in vals`, `for i in start .. end`
|
||||
var key_var_name := ''
|
||||
var val_var_name := p.check_name()
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
key_var_name = val_var_name
|
||||
val_var_name = p.check_name()
|
||||
p.scope.register(key_var_name, ast.Var{
|
||||
name: key_var_name
|
||||
typ: table.int_type
|
||||
})
|
||||
}
|
||||
p.check(.key_in)
|
||||
// arr_expr
|
||||
cond := p.expr(0)
|
||||
// 0 .. 10
|
||||
// start := p.tok.lit.int()
|
||||
// TODO use RangeExpr
|
||||
var high_expr := ast.Expr{}
|
||||
var is_range := false
|
||||
if p.tok.kind == .dotdot {
|
||||
is_range = true
|
||||
p.check(.dotdot)
|
||||
high_expr = p.expr(0)
|
||||
p.scope.register(val_var_name, ast.Var{
|
||||
name: val_var_name
|
||||
typ: table.int_type
|
||||
})
|
||||
} else {
|
||||
// this type will be set in checker
|
||||
p.scope.register(val_var_name, ast.Var{
|
||||
name: val_var_name
|
||||
})
|
||||
}
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
// println('nr stmts=$stmts.len')
|
||||
p.close_scope()
|
||||
return ast.ForInStmt{
|
||||
stmts: stmts
|
||||
cond: cond
|
||||
key_var: key_var_name
|
||||
val_var: val_var_name
|
||||
high: high_expr
|
||||
is_range: is_range
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
// `for cond {`
|
||||
cond := p.expr(0)
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
return ast.ForStmt{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
// Copyright (c) 2019-2020 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 parser
|
||||
|
||||
import v.ast
|
||||
import v.table
|
||||
import v.token
|
||||
|
||||
fn (var p Parser) if_expr() ast.IfExpr {
|
||||
pos := p.tok.position()
|
||||
var branches := []ast.IfBranch
|
||||
var has_else := false
|
||||
for p.tok.kind in [.key_if, .key_else] {
|
||||
p.inside_if = true
|
||||
branch_pos := p.tok.position()
|
||||
var comment := ast.Comment{}
|
||||
if p.tok.kind == .key_if {
|
||||
p.check(.key_if)
|
||||
} else {
|
||||
// if p.tok.kind == .comment {
|
||||
// p.error('place comments inside {}')
|
||||
// }
|
||||
// comment = p.check_comment()
|
||||
p.check(.key_else)
|
||||
if p.tok.kind == .key_if {
|
||||
p.check(.key_if)
|
||||
} else {
|
||||
has_else = true
|
||||
p.inside_if = false
|
||||
branches << ast.IfBranch{
|
||||
stmts: p.parse_block()
|
||||
pos: branch_pos
|
||||
comment: comment
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
var cond := ast.Expr{}
|
||||
var is_or := false
|
||||
// `if x := opt() {`
|
||||
if p.peek_tok.kind == .decl_assign {
|
||||
is_or = true
|
||||
p.open_scope()
|
||||
var_name := p.check_name()
|
||||
p.check(.decl_assign)
|
||||
expr := p.expr(0)
|
||||
p.scope.register(var_name, ast.Var{
|
||||
name: var_name
|
||||
expr: expr
|
||||
})
|
||||
cond = ast.IfGuardExpr{
|
||||
var_name: var_name
|
||||
expr: expr
|
||||
}
|
||||
} else {
|
||||
cond = p.expr(0)
|
||||
}
|
||||
p.inside_if = false
|
||||
stmts := p.parse_block()
|
||||
if is_or {
|
||||
p.close_scope()
|
||||
}
|
||||
branches << ast.IfBranch{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
pos: branch_pos
|
||||
comment: ast.Comment{}
|
||||
}
|
||||
if p.tok.kind != .key_else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ast.IfExpr{
|
||||
branches: branches
|
||||
pos: pos
|
||||
has_else: has_else
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) match_expr() ast.MatchExpr {
|
||||
match_first_pos := p.tok.position()
|
||||
p.inside_match = true
|
||||
p.check(.key_match)
|
||||
is_mut := p.tok.kind in [.key_mut, .key_var]
|
||||
var is_sum_type := false
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
cond := p.expr(0)
|
||||
p.inside_match = false
|
||||
p.check(.lcbr)
|
||||
var branches := []ast.MatchBranch
|
||||
for {
|
||||
branch_first_pos := p.tok.position()
|
||||
comment := p.check_comment() // comment before {}
|
||||
var exprs := []ast.Expr
|
||||
p.open_scope()
|
||||
// final else
|
||||
var is_else := false
|
||||
if p.tok.kind == .key_else {
|
||||
is_else = true
|
||||
p.next()
|
||||
} else if p.tok.kind == .name && (p.tok.lit in table.builtin_type_names || (p.tok.lit[0].is_capital() &&
|
||||
!p.tok.lit.is_upper()) || p.peek_tok.kind == .dot) {
|
||||
// Sum type match
|
||||
// if sym.kind == .sum_type {
|
||||
// p.warn('is sum')
|
||||
// TODO `exprs << ast.Type{...}
|
||||
typ := p.parse_type()
|
||||
x := ast.Type{
|
||||
typ: typ
|
||||
}
|
||||
var expr := ast.Expr{}
|
||||
expr = x
|
||||
exprs << expr
|
||||
p.scope.register('it', ast.Var{
|
||||
name: 'it'
|
||||
typ: table.type_to_ptr(typ)
|
||||
})
|
||||
// TODO
|
||||
if p.tok.kind == .comma {
|
||||
p.next()
|
||||
p.parse_type()
|
||||
}
|
||||
is_sum_type = true
|
||||
} else {
|
||||
// Expression match
|
||||
for {
|
||||
p.inside_match_case = true
|
||||
expr := p.expr(0)
|
||||
p.inside_match_case = false
|
||||
exprs << expr
|
||||
if p.tok.kind != .comma {
|
||||
break
|
||||
}
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
branch_last_pos := p.tok.position()
|
||||
// p.warn('match block')
|
||||
stmts := p.parse_block()
|
||||
pos := token.Position{
|
||||
line_nr: branch_first_pos.line_nr
|
||||
pos: branch_first_pos.pos
|
||||
len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len
|
||||
}
|
||||
branches << ast.MatchBranch{
|
||||
exprs: exprs
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
comment: comment
|
||||
is_else: is_else
|
||||
}
|
||||
p.close_scope()
|
||||
if p.tok.kind == .rcbr {
|
||||
break
|
||||
}
|
||||
}
|
||||
match_last_pos := p.tok.position()
|
||||
pos := token.Position{
|
||||
line_nr: match_first_pos.line_nr
|
||||
pos: match_first_pos.pos
|
||||
len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len
|
||||
}
|
||||
p.check(.rcbr)
|
||||
return ast.MatchExpr{
|
||||
branches: branches
|
||||
cond: cond
|
||||
is_sum_type: is_sum_type
|
||||
pos: pos
|
||||
is_mut: is_mut
|
||||
}
|
||||
}
|
||||
|
|
@ -455,28 +455,6 @@ pub fn (var p Parser) stmt() ast.Stmt {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: is it possible to merge with AssignStmt?
|
||||
pub fn (var p Parser) assign_expr(left ast.Expr) ast.AssignExpr {
|
||||
op := p.tok.kind
|
||||
p.next()
|
||||
pos := p.tok.position()
|
||||
val := p.expr(0)
|
||||
match left {
|
||||
ast.IndexExpr {
|
||||
// it.mark_as_setter()
|
||||
it.is_setter = true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
node := ast.AssignExpr{
|
||||
left: left
|
||||
val: val
|
||||
op: op
|
||||
pos: pos
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
fn (var p Parser) attribute() ast.Attr {
|
||||
p.check(.lsbr)
|
||||
if p.tok.kind == .key_if {
|
||||
|
@ -826,197 +804,6 @@ fn (var p Parser) enum_val() ast.EnumVal {
|
|||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) for_stmt() ast.Stmt {
|
||||
p.check(.key_for)
|
||||
pos := p.tok.position()
|
||||
p.open_scope()
|
||||
p.inside_for = true
|
||||
// defer { p.close_scope() }
|
||||
// Infinite loop
|
||||
if p.tok.kind == .lcbr {
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
return ast.ForStmt{
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
is_inf: true
|
||||
}
|
||||
} else if p.tok.kind in [.key_mut, .key_var] {
|
||||
p.error('`mut` is not needed in for loops')
|
||||
} else if p.peek_tok.kind in [.decl_assign, .assign, .semicolon] || p.tok.kind == .semicolon {
|
||||
// `for i := 0; i < 10; i++ {`
|
||||
var init := ast.Stmt{}
|
||||
var cond := p.new_true_expr()
|
||||
// mut inc := ast.Stmt{}
|
||||
var inc := ast.Expr{}
|
||||
var has_init := false
|
||||
var has_cond := false
|
||||
var has_inc := false
|
||||
if p.peek_tok.kind in [.assign, .decl_assign] {
|
||||
init = p.assign_stmt()
|
||||
has_init = true
|
||||
} else if p.tok.kind != .semicolon {
|
||||
}
|
||||
// allow `for ;; i++ {`
|
||||
// Allow `for i = 0; i < ...`
|
||||
p.check(.semicolon)
|
||||
if p.tok.kind != .semicolon {
|
||||
var typ := table.void_type
|
||||
cond = p.expr(0)
|
||||
has_cond = true
|
||||
}
|
||||
p.check(.semicolon)
|
||||
if p.tok.kind != .lcbr {
|
||||
// inc = p.stmt()
|
||||
inc = p.expr(0)
|
||||
has_inc = true
|
||||
}
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
return ast.ForCStmt{
|
||||
stmts: stmts
|
||||
has_init: has_init
|
||||
has_cond: has_cond
|
||||
has_inc: has_inc
|
||||
init: init
|
||||
cond: cond
|
||||
inc: inc
|
||||
pos: pos
|
||||
}
|
||||
} else if p.peek_tok.kind in [.key_in, .comma] {
|
||||
// `for i in vals`, `for i in start .. end`
|
||||
var key_var_name := ''
|
||||
var val_var_name := p.check_name()
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
key_var_name = val_var_name
|
||||
val_var_name = p.check_name()
|
||||
p.scope.register(key_var_name, ast.Var{
|
||||
name: key_var_name
|
||||
typ: table.int_type
|
||||
})
|
||||
}
|
||||
p.check(.key_in)
|
||||
// arr_expr
|
||||
cond := p.expr(0)
|
||||
// 0 .. 10
|
||||
// start := p.tok.lit.int()
|
||||
// TODO use RangeExpr
|
||||
var high_expr := ast.Expr{}
|
||||
var is_range := false
|
||||
if p.tok.kind == .dotdot {
|
||||
is_range = true
|
||||
p.check(.dotdot)
|
||||
high_expr = p.expr(0)
|
||||
p.scope.register(val_var_name, ast.Var{
|
||||
name: val_var_name
|
||||
typ: table.int_type
|
||||
})
|
||||
} else {
|
||||
// this type will be set in checker
|
||||
p.scope.register(val_var_name, ast.Var{
|
||||
name: val_var_name
|
||||
})
|
||||
}
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
// println('nr stmts=$stmts.len')
|
||||
p.close_scope()
|
||||
return ast.ForInStmt{
|
||||
stmts: stmts
|
||||
cond: cond
|
||||
key_var: key_var_name
|
||||
val_var: val_var_name
|
||||
high: high_expr
|
||||
is_range: is_range
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
// `for cond {`
|
||||
cond := p.expr(0)
|
||||
p.inside_for = false
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
return ast.ForStmt{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) if_expr() ast.IfExpr {
|
||||
pos := p.tok.position()
|
||||
var branches := []ast.IfBranch
|
||||
var has_else := false
|
||||
for p.tok.kind in [.key_if, .key_else] {
|
||||
p.inside_if = true
|
||||
branch_pos := p.tok.position()
|
||||
var comment := ast.Comment{}
|
||||
if p.tok.kind == .key_if {
|
||||
p.check(.key_if)
|
||||
} else {
|
||||
// if p.tok.kind == .comment {
|
||||
// p.error('place comments inside {}')
|
||||
// }
|
||||
// comment = p.check_comment()
|
||||
p.check(.key_else)
|
||||
if p.tok.kind == .key_if {
|
||||
p.check(.key_if)
|
||||
} else {
|
||||
has_else = true
|
||||
p.inside_if = false
|
||||
branches << ast.IfBranch{
|
||||
stmts: p.parse_block()
|
||||
pos: branch_pos
|
||||
comment: comment
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
var cond := ast.Expr{}
|
||||
var is_or := false
|
||||
// `if x := opt() {`
|
||||
if p.peek_tok.kind == .decl_assign {
|
||||
is_or = true
|
||||
p.open_scope()
|
||||
var_name := p.check_name()
|
||||
p.check(.decl_assign)
|
||||
expr := p.expr(0)
|
||||
p.scope.register(var_name, ast.Var{
|
||||
name: var_name
|
||||
expr: expr
|
||||
})
|
||||
cond = ast.IfGuardExpr{
|
||||
var_name: var_name
|
||||
expr: expr
|
||||
}
|
||||
} else {
|
||||
cond = p.expr(0)
|
||||
}
|
||||
p.inside_if = false
|
||||
stmts := p.parse_block()
|
||||
if is_or {
|
||||
p.close_scope()
|
||||
}
|
||||
branches << ast.IfBranch{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
pos: branch_pos
|
||||
comment: ast.Comment{}
|
||||
}
|
||||
if p.tok.kind != .key_else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return ast.IfExpr{
|
||||
branches: branches
|
||||
pos: pos
|
||||
has_else: has_else
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) string_expr() ast.Expr {
|
||||
is_raw := p.tok.kind == .name && p.tok.lit == 'r'
|
||||
is_cstr := p.tok.kind == .name && p.tok.lit == 'c'
|
||||
|
@ -1078,113 +865,6 @@ fn (var p Parser) string_expr() ast.Expr {
|
|||
return node
|
||||
}
|
||||
|
||||
fn (var p Parser) array_init() ast.ArrayInit {
|
||||
first_pos := p.tok.position()
|
||||
var last_pos := token.Position{}
|
||||
p.check(.lsbr)
|
||||
// p.warn('array_init() exp=$p.expected_type')
|
||||
var array_type := table.void_type
|
||||
var elem_type := table.void_type
|
||||
var exprs := []ast.Expr
|
||||
var is_fixed := false
|
||||
if p.tok.kind == .rsbr {
|
||||
// []typ => `[]` and `typ` must be on the same line
|
||||
line_nr := p.tok.line_nr
|
||||
p.check(.rsbr)
|
||||
// []string
|
||||
if p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr {
|
||||
elem_type = p.parse_type()
|
||||
// this is set here becasue its a known type, others could be the
|
||||
// result of expr so we do those in checker
|
||||
idx := p.table.find_or_register_array(elem_type, 1)
|
||||
array_type = table.new_type(idx)
|
||||
}
|
||||
} else {
|
||||
// [1,2,3] or [const]byte
|
||||
for i := 0; p.tok.kind != .rsbr; i++ {
|
||||
expr := p.expr(0)
|
||||
exprs << expr
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
}
|
||||
// p.check_comment()
|
||||
}
|
||||
line_nr := p.tok.line_nr
|
||||
$if tinyc {
|
||||
// NB: do not remove the next line without testing
|
||||
// v selfcompilation with tcc first
|
||||
tcc_stack_bug := 12345
|
||||
}
|
||||
last_pos = p.tok.position()
|
||||
p.check(.rsbr)
|
||||
// [100]byte
|
||||
if exprs.len == 1 && p.tok.kind in [.name, .amp] && p.tok.line_nr == line_nr {
|
||||
elem_type = p.parse_type()
|
||||
is_fixed = true
|
||||
}
|
||||
}
|
||||
// !
|
||||
if p.tok.kind == .not {
|
||||
last_pos = p.tok.position()
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .not {
|
||||
last_pos = p.tok.position()
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .lcbr && exprs.len == 0 {
|
||||
// `[]int{ len: 10, cap: 100}` syntax
|
||||
p.next()
|
||||
for p.tok.kind != .rcbr {
|
||||
key := p.check_name()
|
||||
p.check(.colon)
|
||||
if !(key in ['len', 'cap', 'init']) {
|
||||
p.error('wrong field `$key`, expecting `len`, `cap`, or `init`')
|
||||
}
|
||||
p.expr(0)
|
||||
if p.tok.kind != .rcbr {
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
p.check(.rcbr)
|
||||
}
|
||||
pos := token.Position{
|
||||
line_nr: first_pos.line_nr
|
||||
pos: first_pos.pos
|
||||
len: last_pos.pos - first_pos.pos + last_pos.len
|
||||
}
|
||||
return ast.ArrayInit{
|
||||
is_fixed: is_fixed
|
||||
mod: p.mod
|
||||
elem_type: elem_type
|
||||
typ: array_type
|
||||
exprs: exprs
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) map_init() ast.MapInit {
|
||||
pos := p.tok.position()
|
||||
var keys := []ast.Expr
|
||||
var vals := []ast.Expr
|
||||
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
||||
// p.check(.str)
|
||||
key := p.expr(0)
|
||||
keys << key
|
||||
p.check(.colon)
|
||||
val := p.expr(0)
|
||||
vals << val
|
||||
if p.tok.kind == .comma {
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
return ast.MapInit{
|
||||
keys: keys
|
||||
vals: vals
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) parse_number_literal() ast.Expr {
|
||||
lit := p.tok.lit
|
||||
pos := p.tok.position()
|
||||
|
@ -1329,91 +1009,6 @@ fn (var p Parser) return_stmt() ast.Return {
|
|||
}
|
||||
|
||||
// left hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
||||
fn (var p Parser) parse_assign_lhs() []ast.Ident {
|
||||
var idents := []ast.Ident
|
||||
for {
|
||||
is_mut := p.tok.kind == .key_mut || p.tok.kind == .key_var
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
is_static := p.tok.kind == .key_static
|
||||
if is_static {
|
||||
p.check(.key_static)
|
||||
}
|
||||
var ident := p.parse_ident(false, false)
|
||||
ident.is_mut = is_mut
|
||||
ident.info = ast.IdentVar{
|
||||
is_mut: is_mut
|
||||
is_static: is_static
|
||||
}
|
||||
idents << ident
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return idents
|
||||
}
|
||||
|
||||
// right hand side of `=` or `:=` in `a,b,c := 1,2,3`
|
||||
fn (var p Parser) parse_assign_rhs() []ast.Expr {
|
||||
var exprs := []ast.Expr
|
||||
for {
|
||||
expr := p.expr(0)
|
||||
exprs << expr
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return exprs
|
||||
}
|
||||
|
||||
fn (var p Parser) assign_stmt() ast.Stmt {
|
||||
is_static := p.tok.kind == .key_static
|
||||
if is_static {
|
||||
p.next()
|
||||
}
|
||||
idents := p.parse_assign_lhs()
|
||||
op := p.tok.kind
|
||||
p.next() // :=, =
|
||||
pos := p.tok.position()
|
||||
exprs := p.parse_assign_rhs()
|
||||
is_decl := op == .decl_assign
|
||||
for i, ident in idents {
|
||||
known_var := p.scope.known_var(ident.name)
|
||||
if !is_decl && !known_var {
|
||||
p.error('unknown variable `$ident.name`')
|
||||
}
|
||||
if is_decl && ident.kind != .blank_ident {
|
||||
if p.scope.known_var(ident.name) {
|
||||
p.error('redefinition of `$ident.name`')
|
||||
}
|
||||
if idents.len == exprs.len {
|
||||
p.scope.register(ident.name, ast.Var{
|
||||
name: ident.name
|
||||
expr: exprs[i]
|
||||
is_mut: ident.is_mut || p.inside_for
|
||||
})
|
||||
} else {
|
||||
p.scope.register(ident.name, ast.Var{
|
||||
name: ident.name
|
||||
is_mut: ident.is_mut || p.inside_for
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ast.AssignStmt{
|
||||
left: idents
|
||||
right: exprs
|
||||
op: op
|
||||
pos: pos
|
||||
is_static: is_static
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) global_decl() ast.GlobalDecl {
|
||||
if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod !=
|
||||
'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
|
||||
|
@ -1454,101 +1049,6 @@ fn (var p Parser) global_decl() ast.GlobalDecl {
|
|||
return glob
|
||||
}
|
||||
|
||||
fn (var p Parser) match_expr() ast.MatchExpr {
|
||||
match_first_pos := p.tok.position()
|
||||
p.inside_match = true
|
||||
p.check(.key_match)
|
||||
is_mut := p.tok.kind in [.key_mut, .key_var]
|
||||
var is_sum_type := false
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
cond := p.expr(0)
|
||||
p.inside_match = false
|
||||
p.check(.lcbr)
|
||||
var branches := []ast.MatchBranch
|
||||
for {
|
||||
branch_first_pos := p.tok.position()
|
||||
comment := p.check_comment() // comment before {}
|
||||
var exprs := []ast.Expr
|
||||
p.open_scope()
|
||||
// final else
|
||||
var is_else := false
|
||||
if p.tok.kind == .key_else {
|
||||
is_else = true
|
||||
p.next()
|
||||
} else if p.tok.kind == .name && (p.tok.lit in table.builtin_type_names || (p.tok.lit[0].is_capital() &&
|
||||
!p.tok.lit.is_upper()) || p.peek_tok.kind == .dot) {
|
||||
// Sum type match
|
||||
// if sym.kind == .sum_type {
|
||||
// p.warn('is sum')
|
||||
// TODO `exprs << ast.Type{...}
|
||||
typ := p.parse_type()
|
||||
x := ast.Type{
|
||||
typ: typ
|
||||
}
|
||||
var expr := ast.Expr{}
|
||||
expr = x
|
||||
exprs << expr
|
||||
p.scope.register('it', ast.Var{
|
||||
name: 'it'
|
||||
typ: table.type_to_ptr(typ)
|
||||
})
|
||||
// TODO
|
||||
if p.tok.kind == .comma {
|
||||
p.next()
|
||||
p.parse_type()
|
||||
}
|
||||
is_sum_type = true
|
||||
} else {
|
||||
// Expression match
|
||||
for {
|
||||
p.inside_match_case = true
|
||||
expr := p.expr(0)
|
||||
p.inside_match_case = false
|
||||
exprs << expr
|
||||
if p.tok.kind != .comma {
|
||||
break
|
||||
}
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
branch_last_pos := p.tok.position()
|
||||
// p.warn('match block')
|
||||
stmts := p.parse_block()
|
||||
pos := token.Position{
|
||||
line_nr: branch_first_pos.line_nr
|
||||
pos: branch_first_pos.pos
|
||||
len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len
|
||||
}
|
||||
branches << ast.MatchBranch{
|
||||
exprs: exprs
|
||||
stmts: stmts
|
||||
pos: pos
|
||||
comment: comment
|
||||
is_else: is_else
|
||||
}
|
||||
p.close_scope()
|
||||
if p.tok.kind == .rcbr {
|
||||
break
|
||||
}
|
||||
}
|
||||
match_last_pos := p.tok.position()
|
||||
pos := token.Position{
|
||||
line_nr: match_first_pos.line_nr
|
||||
pos: match_first_pos.pos
|
||||
len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len
|
||||
}
|
||||
p.check(.rcbr)
|
||||
return ast.MatchExpr{
|
||||
branches: branches
|
||||
cond: cond
|
||||
is_sum_type: is_sum_type
|
||||
pos: pos
|
||||
is_mut: is_mut
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) enum_decl() ast.EnumDecl {
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
|
|
Loading…
Reference in New Issue