mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v2: remove unresolved types; handle types in checker; add ast.scope
This commit is contained in:
parent
c2c6260ba2
commit
dc90f4f4a6
@ -70,6 +70,7 @@ pub struct Field {
|
||||
pub:
|
||||
name string
|
||||
// type_idx int
|
||||
mut:
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
@ -197,6 +198,7 @@ pub:
|
||||
mod Module
|
||||
imports []Import
|
||||
stmts []Stmt
|
||||
scope Scope
|
||||
unresolved []Expr
|
||||
}
|
||||
|
||||
@ -292,9 +294,10 @@ pub:
|
||||
cond Expr
|
||||
stmts []Stmt
|
||||
else_stmts []Stmt
|
||||
typ table.Type
|
||||
left Expr // `a` in `a := if ...`
|
||||
pos token.Position
|
||||
mut:
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct MatchExpr {
|
||||
@ -303,8 +306,9 @@ pub:
|
||||
cond Expr
|
||||
blocks []StmtBlock
|
||||
match_exprs []Expr
|
||||
typ table.Type
|
||||
pos token.Position
|
||||
mut:
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct CompIf {
|
||||
|
143
vlib/v/ast/scope.v
Normal file
143
vlib/v/ast/scope.v
Normal file
@ -0,0 +1,143 @@
|
||||
// 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 ast
|
||||
|
||||
pub struct Scope {
|
||||
mut:
|
||||
parent &Scope
|
||||
children []&Scope
|
||||
start_pos int
|
||||
end_pos int
|
||||
//vars map[string]table.Var
|
||||
vars map[string]VarDecl
|
||||
}
|
||||
|
||||
pub fn new_scope(parent &Scope, start_pos int) &Scope {
|
||||
return &Scope{
|
||||
parent: parent
|
||||
start_pos: start_pos
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) {
|
||||
if name in s.vars {
|
||||
return s,s.vars[name]
|
||||
}
|
||||
for sc := s; !isnil(sc.parent); sc = sc.parent {
|
||||
if name in sc.vars {
|
||||
return sc,sc.vars[name]
|
||||
}
|
||||
}
|
||||
return error('not found')
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (s &Scope) find_var(name string) ?VarDecl {
|
||||
//pub fn (s &Scope) find_var(name string) ?table.Var {
|
||||
if name in s.vars {
|
||||
return s.vars[name]
|
||||
}
|
||||
for sc := s; !isnil(sc.parent); sc = sc.parent {
|
||||
if name in sc.vars {
|
||||
return sc.vars[name]
|
||||
}
|
||||
}
|
||||
return error('not found')
|
||||
}
|
||||
|
||||
/*
|
||||
[inline]
|
||||
pub fn (s &Scope) find_var2(name string, pos int) ?VarDecl {
|
||||
return find_var_in_scope(name, pos, s)
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn find_var_in_scope(name string, pos int, scope &Scope) ?VarDecl {
|
||||
if pos != 0 && (pos < scope.start_pos || pos > scope.end_pos) {
|
||||
return none
|
||||
}
|
||||
if name in scope.vars {
|
||||
return scope.vars[name]
|
||||
}
|
||||
for child in scope.children {
|
||||
//if pos < child.start_pos || pos > child.end_pos {
|
||||
// continue
|
||||
//}
|
||||
var := find_var_in_scope(name, pos, child) or {
|
||||
continue
|
||||
}
|
||||
return var
|
||||
//return find_var_in_scope(name, pos, child)
|
||||
}
|
||||
return none
|
||||
}
|
||||
*/
|
||||
|
||||
//pub fn (s mut Scope) register_var(var table.Var) {
|
||||
[inline]
|
||||
pub fn (s mut Scope) register_var(var VarDecl) {
|
||||
if x := s.find_var(var.name) {
|
||||
println('existing var: $var.name')
|
||||
return
|
||||
}
|
||||
s.vars[var.name] = var
|
||||
}
|
||||
|
||||
pub fn (s &Scope) innermost(pos int) ?&Scope {
|
||||
if s.contains(pos) {
|
||||
/*
|
||||
for s1 in s.children {
|
||||
if s1.contains(pos) {
|
||||
return s1.innermost(pos)
|
||||
}
|
||||
}
|
||||
return s
|
||||
*/
|
||||
// binary search
|
||||
mut first := 0
|
||||
mut last := s.children.len-1
|
||||
mut middle := last/2
|
||||
for first <= last {
|
||||
//println('FIRST: $first, LAST: $last, LEN: $s.children.len-1')
|
||||
s1 := s.children[middle]
|
||||
if s1.end_pos < pos {
|
||||
first = middle+1
|
||||
}
|
||||
else if s1.contains(pos) {
|
||||
return s1.innermost(pos)
|
||||
}
|
||||
else {
|
||||
last = middle-1
|
||||
}
|
||||
middle = (first+last)/2
|
||||
if first > last {
|
||||
break
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
return s
|
||||
//return error('none')
|
||||
//return none
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn (s &Scope) contains(pos int) bool {
|
||||
return pos > s.start_pos && pos < s.end_pos
|
||||
}
|
||||
|
||||
pub fn print_scope_vars(sc &Scope, level int) {
|
||||
mut indent := ''
|
||||
for _ in 0..level*4 {
|
||||
indent += ' '
|
||||
}
|
||||
println('$indent# $sc.start_pos - $sc.end_pos')
|
||||
for _, var in sc.vars {
|
||||
println('$indent * $var.name - $var.typ')
|
||||
}
|
||||
for child in sc.children {
|
||||
print_scope_vars(child, level+1)
|
||||
}
|
||||
}
|
@ -39,6 +39,10 @@ pub fn (b mut Builder) gen_c(v_files []string) string {
|
||||
b.parsed_files = parser.parse_files(v_files, b.table)
|
||||
b.parse_imports()
|
||||
b.checker.check_files(b.parsed_files)
|
||||
//println('=======================')
|
||||
//ast.print_scope_vars(&b.parsed_files[0].scope, 0)
|
||||
//println('=======================')
|
||||
//return gen.cgen(b.parsed_files, b.table)
|
||||
return gen.cgen(b.parsed_files, b.table)
|
||||
}
|
||||
|
||||
@ -54,6 +58,9 @@ pub fn (b mut Builder) build_x64(v_files []string, out_file string) {
|
||||
parse_time := t1 - t0
|
||||
println('PARSE: ${parse_time}ms')
|
||||
b.checker.check_files(b.parsed_files)
|
||||
//println('=======================')
|
||||
//ast.print_scope_vars(&b.parsed_files[0].scope, 0)
|
||||
//println('=======================')
|
||||
t2 := time.ticks()
|
||||
check_time := t2 - t1
|
||||
println('CHECK: ${check_time}ms')
|
||||
|
@ -14,6 +14,7 @@ pub struct Checker {
|
||||
table &table.Table
|
||||
mut:
|
||||
file_name string
|
||||
scope ast.Scope
|
||||
resolved []table.Type
|
||||
}
|
||||
|
||||
@ -25,109 +26,49 @@ pub fn new_checker(table &table.Table) Checker {
|
||||
|
||||
pub fn (c mut Checker) check(ast_file ast.File) {
|
||||
c.file_name = ast_file.path
|
||||
// if ast_file.unresolved.len != c.resolved.len {
|
||||
// c.resolve_exprs(file)
|
||||
// }
|
||||
c.complete_types()
|
||||
c.scope = ast_file.scope
|
||||
|
||||
for stmt in ast_file.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) check_files(ast_files []ast.File) {
|
||||
// this cant be moved to check() for multiple
|
||||
// files this muse be done first. TODO: optimize
|
||||
for file in ast_files {
|
||||
c.file_name = file.path
|
||||
c.resolve_expr_types(file.unresolved)
|
||||
}
|
||||
for file in ast_files {
|
||||
c.check(file)
|
||||
}
|
||||
}
|
||||
|
||||
// resolve type of unresolved expressions
|
||||
fn (c mut Checker) resolve_expr_types(exprs []ast.Expr) {
|
||||
for x in exprs {
|
||||
c.resolved << c.expr(x)
|
||||
}
|
||||
}
|
||||
|
||||
// update any types chich contain unresolved sub types
|
||||
fn (c &Checker) complete_types() {
|
||||
for idx, t in c.table.types {
|
||||
// skip builtin types
|
||||
if idx <= table.map_type_idx {
|
||||
continue
|
||||
}
|
||||
// println('Resolve type: $t.name')
|
||||
if t.kind == .array {
|
||||
mut info := t.array_info()
|
||||
if table.type_is_unresolved(info.elem_type) {
|
||||
info.elem_type = c.resolve(info.elem_type)
|
||||
elem_type_sym := c.table.get_type_symbol(info.elem_type)
|
||||
mut t1 := &c.table.types[idx]
|
||||
t1.name = table.array_name(elem_type_sym, info.nr_dims)
|
||||
t1.info = info
|
||||
}
|
||||
}
|
||||
else if t.kind == .map {
|
||||
mut info := t.map_info()
|
||||
mut updated := false
|
||||
if table.type_is_unresolved(info.key_type) {
|
||||
info.key_type = c.resolve(info.key_type)
|
||||
updated = true
|
||||
}
|
||||
if table.type_is_unresolved(info.value_type) {
|
||||
info.value_type = c.resolve(info.value_type)
|
||||
updated = true
|
||||
}
|
||||
if updated {
|
||||
mut t1 := &c.table.types[idx]
|
||||
key_type_sym := c.table.get_type_symbol(info.key_type)
|
||||
value_type_sym := c.table.get_type_symbol(info.value_type)
|
||||
t1.name = table.map_name(key_type_sym, value_type_sym)
|
||||
t1.info = info
|
||||
}
|
||||
}
|
||||
else if t.kind == .multi_return {
|
||||
mut info := t.mr_info()
|
||||
mut types := info.types
|
||||
mut updated := false
|
||||
for i, ut in types {
|
||||
if table.type_is_unresolved(ut) {
|
||||
types[i] = c.resolve(ut)
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
if updated {
|
||||
mut t1 := &c.table.types[idx]
|
||||
info.types = types
|
||||
t1.info = info
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the resolved Type from unresovled Type
|
||||
pub fn (c &Checker) resolve(unresolved table.Type) table.Type {
|
||||
return c.resolved[-table.type_idx(unresolved) - 1]
|
||||
}
|
||||
|
||||
pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) table.Type {
|
||||
pub fn (c mut Checker) check_struct_init(struct_init ast.StructInit) table.Type {
|
||||
// typ := c.table.find_type(struct_init.typ.typ.name) or {
|
||||
// c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
|
||||
// panic('')
|
||||
// }
|
||||
typ := c.table.get_type_symbol(struct_init.typ)
|
||||
match typ.kind {
|
||||
typ_sym := c.table.get_type_symbol(struct_init.typ)
|
||||
match typ_sym.kind {
|
||||
.placeholder {
|
||||
c.error('unknown struct: $typ.name', struct_init.pos)
|
||||
c.error('unknown struct: $typ_sym.name', struct_init.pos)
|
||||
}
|
||||
.struct_ {
|
||||
info := typ.info as table.Struct
|
||||
info := typ_sym.info as table.Struct
|
||||
if struct_init.exprs.len > info.fields.len {
|
||||
c.error('too many fields', struct_init.pos)
|
||||
}
|
||||
for i, expr in struct_init.exprs {
|
||||
field := info.fields[i]
|
||||
//struct_field info.
|
||||
field_name := struct_init.fields[i]
|
||||
mut field := info.fields[i]
|
||||
mut found_field := false
|
||||
for f in info.fields {
|
||||
if f.name == field_name {
|
||||
field = f
|
||||
found_field = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found_field {
|
||||
c.error('struct init: no such field `$field_name` for struct `$typ_sym.name`', struct_init.pos)
|
||||
}
|
||||
expr_type := c.expr(expr)
|
||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||
field_type_sym := c.table.get_type_symbol(field.typ)
|
||||
@ -141,7 +82,7 @@ pub fn (c &Checker) check_struct_init(struct_init ast.StructInit) table.Type {
|
||||
return struct_init.typ
|
||||
}
|
||||
|
||||
pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type {
|
||||
pub fn (c mut Checker) infix_expr(infix_expr ast.InfixExpr) table.Type {
|
||||
left_type := c.expr(infix_expr.left)
|
||||
right_type := c.expr(infix_expr.right)
|
||||
if !c.table.check(right_type, left_type) {
|
||||
@ -157,7 +98,7 @@ pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type {
|
||||
return left_type
|
||||
}
|
||||
|
||||
fn (c &Checker) check_assign_expr(assign_expr ast.AssignExpr) {
|
||||
fn (c mut Checker) check_assign_expr(assign_expr ast.AssignExpr) {
|
||||
left_type := c.expr(assign_expr.left)
|
||||
right_type := c.expr(assign_expr.val)
|
||||
if !c.table.check(right_type, left_type) {
|
||||
@ -167,7 +108,7 @@ fn (c &Checker) check_assign_expr(assign_expr ast.AssignExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type {
|
||||
pub fn (c mut Checker) call_expr(call_expr ast.CallExpr) table.Type {
|
||||
fn_name := call_expr.name
|
||||
if f := c.table.find_fn(fn_name) {
|
||||
// return_ti := f.return_ti
|
||||
@ -195,7 +136,7 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type {
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.Type {
|
||||
pub fn (c mut Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr) table.Type {
|
||||
typ := c.expr(method_call_expr.expr)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
if method := typ_sym.find_method(method_call_expr.name) {
|
||||
@ -211,7 +152,7 @@ pub fn (c &Checker) check_method_call_expr(method_call_expr ast.MethodCallExpr)
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type {
|
||||
pub fn (c mut Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type {
|
||||
typ := c.expr(selector_expr.expr)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
field_name := selector_expr.field
|
||||
@ -221,9 +162,6 @@ pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type {
|
||||
// check parent
|
||||
if !isnil(typ_sym.parent) {
|
||||
if field := typ_sym.parent.find_field(field_name) {
|
||||
if table.type_is_unresolved(field.typ) {
|
||||
return c.resolved[field.typ]
|
||||
}
|
||||
return field.typ
|
||||
}
|
||||
}
|
||||
@ -237,7 +175,7 @@ pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type {
|
||||
}
|
||||
|
||||
// TODO: non deferred
|
||||
pub fn (c &Checker) return_stmt(return_stmt ast.Return) {
|
||||
pub fn (c mut Checker) return_stmt(return_stmt ast.Return) {
|
||||
mut got_types := []table.Type
|
||||
if return_stmt.exprs.len == 0 {
|
||||
return
|
||||
@ -268,8 +206,14 @@ pub fn (c &Checker) return_stmt(return_stmt ast.Return) {
|
||||
|
||||
pub fn (c &Checker) assign_stmt(assign_stmt ast.AssignStmt) {}
|
||||
|
||||
pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.Type {
|
||||
pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
|
||||
mut elem_type := table.void_type
|
||||
|
||||
// a = []
|
||||
if array_init.exprs.len == 0 {
|
||||
|
||||
}
|
||||
|
||||
for i, expr in array_init.exprs {
|
||||
c.expr(expr)
|
||||
typ := c.expr(expr)
|
||||
@ -283,10 +227,21 @@ pub fn (c &Checker) array_init(array_init ast.ArrayInit) table.Type {
|
||||
c.error('expected array element with type `$elem_type_sym.name`', array_init.pos)
|
||||
}
|
||||
}
|
||||
//idx := if is_fixed { p.table.find_or_register_array_fixed(val_type, fixed_size, 1) } else { p.table.find_or_register_array(val_type, 1) }
|
||||
is_fixed := false
|
||||
fixed_size := 1
|
||||
idx := if is_fixed {
|
||||
c.table.find_or_register_array_fixed(elem_type, fixed_size, 1)
|
||||
}
|
||||
else {
|
||||
c.table.find_or_register_array(elem_type, 1)
|
||||
}
|
||||
array_type := table.new_type(idx)
|
||||
array_init.typ = array_type
|
||||
return array_init.typ
|
||||
}
|
||||
|
||||
fn (c &Checker) stmt(node ast.Stmt) {
|
||||
fn (c mut Checker) stmt(node ast.Stmt) {
|
||||
match mut node {
|
||||
ast.FnDecl {
|
||||
for stmt in it.stmts {
|
||||
@ -299,14 +254,29 @@ fn (c &Checker) stmt(node ast.Stmt) {
|
||||
ast.AssignStmt {
|
||||
c.assign_stmt(it)
|
||||
}
|
||||
ast.VarDecl {
|
||||
typ := c.expr(it.expr)
|
||||
// println('checker: var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr')
|
||||
// if typ.typ.kind != .void {
|
||||
if table.type_idx(typ) != table.void_type_idx {
|
||||
it.typ = typ
|
||||
ast.ConstDecl {
|
||||
for i, expr in it.exprs {
|
||||
mut field := it.fields[i]
|
||||
typ := c.expr(expr)
|
||||
mut xconst := c.table.consts[field.name]
|
||||
//if xconst.typ == 0 {
|
||||
xconst.typ = typ
|
||||
c.table.consts[field.name] = xconst
|
||||
//}
|
||||
field.typ = typ
|
||||
it.fields[i] = field
|
||||
}
|
||||
}
|
||||
ast.VarDecl {
|
||||
println('VARDECL')
|
||||
typ := c.expr(it.expr)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
//println('var $it.name - $typ - $it.typ')
|
||||
//if it.typ == 0 {
|
||||
// it.typ = typ
|
||||
//}
|
||||
it.typ = typ
|
||||
}
|
||||
ast.ForStmt {
|
||||
typ := c.expr(it.cond)
|
||||
// typ_sym := c.table.get_type_symbol(typ)
|
||||
@ -334,7 +304,7 @@ fn (c &Checker) stmt(node ast.Stmt) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
||||
match mut node {
|
||||
ast.AssignExpr {
|
||||
c.check_assign_expr(it)
|
||||
@ -342,7 +312,9 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
ast.IntegerLiteral {
|
||||
return table.int_type
|
||||
}
|
||||
// ast.FloatLiteral {}
|
||||
ast.FloatLiteral{
|
||||
return table.f64_type
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
return c.postfix_expr(it)
|
||||
}
|
||||
@ -351,7 +323,6 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
c.expr(it.left)
|
||||
}
|
||||
*/
|
||||
|
||||
ast.StringLiteral {
|
||||
return table.string_type
|
||||
}
|
||||
@ -371,26 +342,59 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
return c.check_method_call_expr(it)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
return c.array_init(it)
|
||||
return c.array_init(mut it)
|
||||
}
|
||||
ast.Ident {
|
||||
//println('IDENT: $it.name - $it.pos.pos')
|
||||
if it.kind == .variable {
|
||||
mut info := it.info as ast.IdentVar
|
||||
if table.type_is_unresolved(info.typ) {
|
||||
typ := c.resolve(info.typ)
|
||||
info.typ = typ
|
||||
it.info = info
|
||||
//println('===========================')
|
||||
//ast.print_scope_vars(&c.scope, 0)
|
||||
//println('===========================')
|
||||
info := it.info as ast.IdentVar
|
||||
if info.typ != 0 {
|
||||
return info.typ
|
||||
}
|
||||
if inner := c.scope.innermost(it.pos.pos) {
|
||||
mut found := true
|
||||
mut varscope, var := inner.find_scope_and_var(it.name) or {
|
||||
//ast.print_scope_vars(inner, 0)
|
||||
found = false
|
||||
c.error('not found: $it.name - POS: $it.pos.pos', it.pos)
|
||||
panic('')
|
||||
}
|
||||
if found {
|
||||
mut typ := var.typ
|
||||
// set var type on first use
|
||||
if var.typ == 0 {
|
||||
typ = c.expr(var.expr)
|
||||
mut v1 := var
|
||||
v1.typ = typ
|
||||
varscope.vars[var.name] = v1
|
||||
}
|
||||
// update ident
|
||||
it.kind = .variable
|
||||
it.info = ast.IdentVar{
|
||||
typ: typ
|
||||
}
|
||||
return typ
|
||||
}
|
||||
return info.typ
|
||||
}
|
||||
}
|
||||
// Handle indents with unresolved types during the parsing step
|
||||
// (declared after first usage)
|
||||
else if it.kind == .blank_ident {
|
||||
else if it.kind == .constant {
|
||||
if constant := c.table.find_const(it.name) {
|
||||
return constant.typ
|
||||
}
|
||||
}
|
||||
else if it.kind == .blank_ident {
|
||||
println('CONST A: $it.name')
|
||||
if constant := c.table.find_const(it.name) {
|
||||
println('CONST: $it.name')
|
||||
|
||||
return constant.typ
|
||||
}
|
||||
}
|
||||
return table.void_type
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
@ -403,20 +407,10 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
return c.index_expr(it)
|
||||
}
|
||||
ast.IfExpr {
|
||||
typ := c.expr(it.cond)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
// if typ_sym.kind != .bool {
|
||||
if table.type_idx(typ) != table.bool_type_idx {
|
||||
c.error('non-bool (`$typ_sym.name`) used as if condition', it.pos)
|
||||
}
|
||||
for i, stmt in it.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
if it.else_stmts.len > 0 {
|
||||
for stmt in it.else_stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
return c.if_expr(mut it)
|
||||
}
|
||||
ast.MatchExpr {
|
||||
return c.match_expr(mut it)
|
||||
}
|
||||
ast.CastExpr {
|
||||
return it.typ
|
||||
@ -426,7 +420,70 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
return table.void_type
|
||||
}
|
||||
|
||||
pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type {
|
||||
pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type {
|
||||
t := c.expr(node.cond)
|
||||
for i, block in node.blocks {
|
||||
match_expr := node.match_exprs[i]
|
||||
c.expr(match_expr)
|
||||
for stmt in block.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
// If the last statement is an expression, return its type
|
||||
if block.stmts.len > 0 {
|
||||
match block.stmts[block.stmts.len - 1] {
|
||||
ast.ExprStmt {
|
||||
// TODO: ask alex about this
|
||||
//typ := c.expr(it.expr)
|
||||
//type_sym := c.table.get_type_symbol(typ)
|
||||
//p.warn('match expr ret $type_sym.name')
|
||||
//node.typ = typ
|
||||
//return typ
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
node.typ = t
|
||||
return t
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
|
||||
typ := c.expr(node.cond)
|
||||
node.typ = typ
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
// if typ_sym.kind != .bool {
|
||||
if table.type_idx(typ) != table.bool_type_idx {
|
||||
c.error('non-bool (`$typ_sym.name`) used as if condition', node.pos)
|
||||
}
|
||||
for i, stmt in node.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
if node.else_stmts.len > 0 {
|
||||
for stmt in node.else_stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
if node.stmts.len > 0 {
|
||||
match node.stmts[node.stmts.len - 1] {
|
||||
ast.ExprStmt {
|
||||
//type_sym := p.table.get_type_symbol(it.typ)
|
||||
//p.warn('if expr ret $type_sym.name')
|
||||
//typ = it.typ
|
||||
//return it.typ
|
||||
t := c.expr(it.expr)
|
||||
node.typ = t
|
||||
return t
|
||||
// return node,it.ti
|
||||
// left =
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
return typ
|
||||
//return table.void_type
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type {
|
||||
/*
|
||||
match node.expr {
|
||||
ast.IdentVar {
|
||||
@ -444,7 +501,16 @@ pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type {
|
||||
return typ
|
||||
}
|
||||
|
||||
pub fn (c &Checker) index_expr(node ast.IndexExpr) table.Type {
|
||||
pub fn (c mut Checker) index_expr(node ast.IndexExpr) table.Type {
|
||||
/*
|
||||
mut typ := left_type
|
||||
left_type_sym := p.table.get_type_symbol(left_type)
|
||||
if left_type_sym.kind == .array {
|
||||
info := left_type_sym.info as table.Array
|
||||
typ = info.elem_type
|
||||
}
|
||||
*/
|
||||
|
||||
mut typ := c.expr(node.left)
|
||||
mut is_range := false // TODO is_range := node.index is ast.RangeExpr
|
||||
match node.index {
|
||||
|
@ -112,12 +112,12 @@ void println(string s) {
|
||||
|
||||
void matches() {
|
||||
int a = 100;
|
||||
int tmp2 = a;
|
||||
if tmp2 == 10{
|
||||
int tmp3 = a;
|
||||
if tmp3 == 10{
|
||||
println(tos3("10"));
|
||||
|
||||
}
|
||||
if tmp2 == 20{
|
||||
if tmp3 == 20{
|
||||
int k = a + 1;
|
||||
|
||||
}
|
||||
|
@ -310,6 +310,7 @@ pub fn (g mut Gen) call_fn(name string) {
|
||||
|
||||
fn (g mut Gen) stmt(node ast.Stmt) {
|
||||
match node {
|
||||
ast.ConstDecl {}
|
||||
ast.FnDecl {
|
||||
is_main := it.name == 'main'
|
||||
if is_main {
|
||||
|
@ -8,17 +8,15 @@ import (
|
||||
v.table
|
||||
)
|
||||
|
||||
pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
|
||||
pub fn (p mut Parser) call_expr() ast.CallExpr {
|
||||
tok := p.tok
|
||||
fn_name := p.check_name()
|
||||
p.check(.lpar)
|
||||
// mut return_ti := types.void_ti
|
||||
args := p.call_args()
|
||||
node := ast.CallExpr{
|
||||
name: fn_name
|
||||
args: args
|
||||
// tok: tok
|
||||
|
||||
pos: tok.position()
|
||||
}
|
||||
if p.tok.kind == .key_orelse {
|
||||
@ -26,10 +24,9 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
|
||||
p.parse_block()
|
||||
}
|
||||
if f := p.table.find_fn(fn_name) {
|
||||
return node,f.return_type
|
||||
return node
|
||||
}
|
||||
typ := p.add_unresolved('${fn_name}()', node)
|
||||
return node,typ
|
||||
return node
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) call_args() []ast.Expr {
|
||||
@ -49,12 +46,13 @@ pub fn (p mut Parser) call_args() []ast.Expr {
|
||||
}
|
||||
|
||||
fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
p.table.clear_vars()
|
||||
//p.table.clear_vars()
|
||||
p.open_scope()
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
p.table.clear_vars()
|
||||
//p.table.clear_vars()
|
||||
p.check(.key_fn)
|
||||
// C.
|
||||
is_c := p.tok.kind == .name && p.tok.lit == 'C'
|
||||
@ -74,7 +72,11 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
p.next()
|
||||
}
|
||||
rec_type = p.parse_type()
|
||||
p.table.register_var(table.Var{
|
||||
//p.table.register_var(table.Var{
|
||||
// name: rec_name
|
||||
// typ: rec_type
|
||||
//})
|
||||
p.scope.register_var(ast.VarDecl{
|
||||
name: rec_name
|
||||
typ: rec_type
|
||||
})
|
||||
@ -101,7 +103,11 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
typ: ast_arg.typ
|
||||
}
|
||||
args << var
|
||||
p.table.register_var(var)
|
||||
p.scope.register_var(ast.VarDecl{
|
||||
name: ast_arg.name
|
||||
typ: ast_arg.typ
|
||||
})
|
||||
//p.table.register_var(var)
|
||||
}
|
||||
//
|
||||
/*
|
||||
@ -149,6 +155,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
if p.tok.kind == .lcbr {
|
||||
stmts = p.parse_block()
|
||||
}
|
||||
p.close_scope()
|
||||
return ast.FnDecl{
|
||||
name: name
|
||||
stmts: stmts
|
||||
|
@ -78,6 +78,13 @@ pub fn (p mut Parser) parse_fn_type() table.Type {
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) parse_type() table.Type {
|
||||
// optional
|
||||
mut is_optional := false
|
||||
if p.tok.kind == .question {
|
||||
p.next()
|
||||
is_optional = true
|
||||
}
|
||||
// &Type
|
||||
mut nr_muls := 0
|
||||
for p.tok.kind == .amp {
|
||||
p.check(.amp)
|
||||
@ -87,9 +94,6 @@ pub fn (p mut Parser) parse_type() table.Type {
|
||||
p.next()
|
||||
p.check(.dot)
|
||||
}
|
||||
if p.tok.kind == .question {
|
||||
p.next()
|
||||
}
|
||||
// `module.Type`
|
||||
if p.peek_tok.kind == .dot {
|
||||
// /if !(p.tok.lit in p.table.imports) {
|
||||
|
@ -43,18 +43,19 @@ mut:
|
||||
pref &pref.Preferences // Preferences shared from V struct
|
||||
builtin_mod bool
|
||||
mod string
|
||||
unresolved []ast.Expr
|
||||
unresolved_offset int
|
||||
expected_type table.Type
|
||||
scope &ast.Scope
|
||||
}
|
||||
|
||||
// for tests
|
||||
pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
|
||||
pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt {
|
||||
s := scanner.new_scanner(text)
|
||||
mut p := Parser{
|
||||
scanner: s
|
||||
table: table
|
||||
pref: &pref.Preferences{}
|
||||
scope: scope
|
||||
//scope: &ast.Scope{start_pos: 0, parent: 0}
|
||||
}
|
||||
p.init_parse_fns()
|
||||
p.read_first_token()
|
||||
@ -72,9 +73,10 @@ pub fn parse_file(path string, table &table.Table) ast.File {
|
||||
table: table
|
||||
file_name: path
|
||||
pref: &pref.Preferences{}
|
||||
unresolved_offset: table.unresolved_idxs.size
|
||||
scope: &ast.Scope{start_pos: 0, parent: 0}
|
||||
}
|
||||
p.read_first_token()
|
||||
//p.scope = &ast.Scope{start_pos: p.tok.position(), parent: 0}
|
||||
// module decl
|
||||
module_decl := if p.tok.kind == .key_module { p.module_decl() } else { ast.Module{name: 'main'
|
||||
} }
|
||||
@ -97,12 +99,15 @@ pub fn parse_file(path string, table &table.Table) ast.File {
|
||||
}
|
||||
// println('nr stmts = $stmts.len')
|
||||
// println(stmts[0])
|
||||
|
||||
p.scope.end_pos = p.tok.pos
|
||||
|
||||
return ast.File{
|
||||
path: path
|
||||
mod: module_decl
|
||||
imports: imports
|
||||
stmts: stmts
|
||||
unresolved: p.unresolved
|
||||
scope: *p.scope
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +131,22 @@ pub fn (p mut Parser) read_first_token() {
|
||||
p.next()
|
||||
}
|
||||
|
||||
|
||||
pub fn (p mut Parser) open_scope() {
|
||||
p.scope = &ast.Scope{
|
||||
parent: p.scope
|
||||
start_pos: p.tok.pos
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) close_scope() {
|
||||
p.scope.end_pos = p.tok.pos
|
||||
p.scope.parent.children << p.scope
|
||||
p.scope = p.scope.parent
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) parse_block() []ast.Stmt {
|
||||
p.open_scope()
|
||||
p.table.open_scope()
|
||||
p.check(.lcbr)
|
||||
mut stmts := []ast.Stmt
|
||||
@ -140,6 +160,8 @@ pub fn (p mut Parser) parse_block() []ast.Stmt {
|
||||
}
|
||||
}
|
||||
p.check(.rcbr)
|
||||
println('parse block')
|
||||
p.close_scope()
|
||||
p.table.close_scope()
|
||||
// println('nr exprs in block = $exprs.len')
|
||||
return stmts
|
||||
@ -266,10 +288,11 @@ pub fn (p mut Parser) stmt() ast.Stmt {
|
||||
if p.tok.kind == .name && p.peek_tok.kind in [.comma] {
|
||||
return p.assign_stmt()
|
||||
}
|
||||
expr,typ := p.expr(0)
|
||||
//expr,typ := p.expr(0)
|
||||
expr,_ := p.expr(0)
|
||||
return ast.ExprStmt{
|
||||
expr: expr
|
||||
typ: typ
|
||||
//typ: typ
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,21 +435,21 @@ pub fn (p mut Parser) parse_ident(is_c bool) (ast.Ident,table.Type) {
|
||||
mut ident := ast.Ident{
|
||||
name: name
|
||||
is_c: is_c
|
||||
pos: p.tok.position()
|
||||
}
|
||||
mut known_var := false
|
||||
if var := p.table.find_var(name) {
|
||||
if var := p.scope.find_var(name) {
|
||||
known_var = true
|
||||
typ = var.typ
|
||||
// typ = var.typ
|
||||
}
|
||||
// variable
|
||||
if known_var || p.tok.kind in [.comma, .decl_assign, .assign] {
|
||||
if known_var /* || p.tok.kind in [.comma, .decl_assign, .assign]*/ {
|
||||
// println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx')
|
||||
ident.kind = .variable
|
||||
ident.info = ast.IdentVar{
|
||||
typ: typ
|
||||
//typ: typ
|
||||
// name: ident.name
|
||||
// expr: p.expr(0)// var.expr
|
||||
|
||||
}
|
||||
return ident,typ
|
||||
}
|
||||
@ -457,6 +480,7 @@ pub fn (p mut Parser) parse_ident(is_c bool) (ast.Ident,table.Type) {
|
||||
node = ast.Ident{
|
||||
kind: .blank_ident
|
||||
name: name
|
||||
//pos: p.tok.position()
|
||||
}
|
||||
return node,typ
|
||||
// p.error('parse_ident: unknown identifier `$name`')
|
||||
@ -559,9 +583,8 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||
// fn call
|
||||
else {
|
||||
println('calling $p.tok.lit')
|
||||
x,ti2 := p.call_expr() // TODO `node,typ :=` should work
|
||||
x := p.call_expr() // TODO `node,typ :=` should work
|
||||
node = x
|
||||
typ = ti2
|
||||
}
|
||||
}
|
||||
else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || p.tok.lit in ['array', 'string', 'ustring', 'mapnode', 'map']) && !p.tok.lit[p.tok.lit.len - 1].is_capital() {
|
||||
@ -615,7 +638,8 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
|
||||
p.next()
|
||||
}
|
||||
.key_match {
|
||||
node,typ = p.match_expr()
|
||||
//node,typ = p.match_expr()
|
||||
node = p.match_expr()
|
||||
}
|
||||
.number {
|
||||
node,typ = p.parse_number_literal()
|
||||
@ -626,10 +650,11 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
|
||||
p.check(.rpar)
|
||||
}
|
||||
.key_if {
|
||||
node,typ = p.if_expr()
|
||||
node = p.if_expr()
|
||||
}
|
||||
.lsbr {
|
||||
node,typ = p.array_init()
|
||||
//node,typ = p.array_init()
|
||||
node = p.array_init()
|
||||
}
|
||||
.key_none {
|
||||
p.next()
|
||||
@ -669,13 +694,15 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
|
||||
node = p.assign_expr(node)
|
||||
}
|
||||
else if p.tok.kind == .dot {
|
||||
node,typ = p.dot_expr(node, typ)
|
||||
node = p.dot_expr(node, typ)
|
||||
}
|
||||
else if p.tok.kind == .lsbr {
|
||||
// node = p.index_expr(node) // , typ)
|
||||
node = p.index_expr(node) // , typ)
|
||||
/*
|
||||
ie_node,ie_typ := p.index_expr(node, typ)
|
||||
node = ie_node
|
||||
typ = ie_typ
|
||||
*/
|
||||
}
|
||||
else if p.tok.kind == .key_as {
|
||||
p.next()
|
||||
@ -712,7 +739,7 @@ fn (p mut Parser) prefix_expr() (ast.Expr,table.Type) {
|
||||
return expr,typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) index_expr(left ast.Expr, left_type table.Type) (ast.IndexExpr,table.Type) {
|
||||
fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr {
|
||||
// left == `a` in `a[0]`
|
||||
p.next() // [
|
||||
if p.tok.kind == .dotdot {
|
||||
@ -727,7 +754,7 @@ fn (p mut Parser) index_expr(left ast.Expr, left_type table.Type) (ast.IndexExpr
|
||||
low: ast.Expr{}
|
||||
high: high
|
||||
}
|
||||
},left_type // TODO: return correct type
|
||||
}
|
||||
}
|
||||
expr,_ := p.expr(0) // `[expr]` or `[expr..]`
|
||||
if p.tok.kind == .dotdot {
|
||||
@ -745,35 +772,44 @@ fn (p mut Parser) index_expr(left ast.Expr, left_type table.Type) (ast.IndexExpr
|
||||
low: expr
|
||||
high: high
|
||||
}
|
||||
},left_type // TODO: return correct type
|
||||
}
|
||||
}
|
||||
// get the element type
|
||||
/*
|
||||
mut typ := left_type
|
||||
left_type_sym := p.table.get_type_symbol(left_type)
|
||||
if left_type_sym.kind == .array {
|
||||
info := left_type_sym.info as table.Array
|
||||
typ = info.elem_type
|
||||
}
|
||||
*/
|
||||
// [expr]
|
||||
p.check(.rsbr)
|
||||
return ast.IndexExpr{
|
||||
left: left
|
||||
index: expr
|
||||
pos: p.tok.position()
|
||||
},typ
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) filter(typ table.Type) {
|
||||
/*
|
||||
p.table.register_var(table.Var{
|
||||
name: 'it'
|
||||
typ: typ
|
||||
})
|
||||
*/
|
||||
p.scope.register_var(ast.VarDecl{
|
||||
name: 'it'
|
||||
typ: typ
|
||||
})
|
||||
}
|
||||
|
||||
fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) (ast.Expr,table.Type) {
|
||||
fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) ast.Expr {
|
||||
p.next()
|
||||
field_name := p.check_name()
|
||||
if field_name == 'filter' {
|
||||
p.open_scope()
|
||||
p.table.open_scope()
|
||||
p.filter(left_type)
|
||||
}
|
||||
@ -794,8 +830,8 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) (ast.Expr,table.
|
||||
mut node := ast.Expr{}
|
||||
node = mcall_expr
|
||||
// typ := p.add_unresolved('${left_type.typ.name}.${field_name}()', mcall_expr)
|
||||
typ := p.add_unresolved('${table.type_idx(left_type)}.${field_name}()', mcall_expr)
|
||||
return node,typ
|
||||
// typ := p.add_unresolved('${table.type_idx(left_type)}.${field_name}()', mcall_expr)
|
||||
return node
|
||||
}
|
||||
sel_expr := ast.SelectorExpr{
|
||||
expr: left
|
||||
@ -803,13 +839,14 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_type table.Type) (ast.Expr,table.
|
||||
pos: p.tok.position()
|
||||
}
|
||||
// typ := p.add_unresolved('${left_type.typ.name}.$field_name', sel_expr)
|
||||
typ := p.add_unresolved('${table.type_idx(left_type)}.$field_name', sel_expr)
|
||||
// typ := p.add_unresolved('${table.type_idx(left_type)}.$field_name', sel_expr)
|
||||
mut node := ast.Expr{}
|
||||
node = sel_expr
|
||||
if field_name == 'filter' {
|
||||
p.close_scope()
|
||||
p.table.close_scope()
|
||||
}
|
||||
return node,typ
|
||||
return node
|
||||
}
|
||||
|
||||
fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,table.Type) {
|
||||
@ -853,11 +890,13 @@ fn (p mut Parser) enum_val() (ast.Expr,table.Type) {
|
||||
|
||||
fn (p mut Parser) for_statement() ast.Stmt {
|
||||
p.check(.key_for)
|
||||
p.open_scope()
|
||||
p.table.open_scope()
|
||||
// defer { p.table.close_scope() }
|
||||
// Infinite loop
|
||||
if p.tok.kind == .lcbr {
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
p.table.close_scope()
|
||||
return ast.ForStmt{
|
||||
stmts: stmts
|
||||
@ -896,6 +935,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
inc = p.stmt()
|
||||
}
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
p.table.close_scope()
|
||||
return ast.ForCStmt{
|
||||
stmts: stmts
|
||||
@ -910,7 +950,11 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
val_name := p.check_name()
|
||||
p.table.register_var(table.Var{
|
||||
//p.table.register_var(table.Var{
|
||||
// name: val_name
|
||||
// typ: table.int_type
|
||||
//})
|
||||
p.scope.register_var(ast.VarDecl{
|
||||
name: val_name
|
||||
typ: table.int_type
|
||||
})
|
||||
@ -945,12 +989,17 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
p.check(.dotdot)
|
||||
p.expr(0)
|
||||
}
|
||||
p.table.register_var(table.Var{
|
||||
//p.table.register_var(table.Var{
|
||||
// name: var_name
|
||||
// typ: elem_type
|
||||
//})
|
||||
p.scope.register_var(ast.VarDecl{
|
||||
name: var_name
|
||||
typ: elem_type
|
||||
})
|
||||
stmts := p.parse_block()
|
||||
// println('nr stmts=$stmts.len')
|
||||
p.close_scope()
|
||||
p.table.close_scope()
|
||||
return ast.ForStmt{
|
||||
stmts: stmts
|
||||
@ -960,6 +1009,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
// `for cond {`
|
||||
cond,_ := p.expr(0)
|
||||
stmts := p.parse_block()
|
||||
p.close_scope()
|
||||
p.table.close_scope()
|
||||
return ast.ForStmt{
|
||||
cond: cond
|
||||
@ -968,7 +1018,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
|
||||
fn (p mut Parser) if_expr() ast.Expr {
|
||||
p.inside_if = true
|
||||
// defer {
|
||||
// }
|
||||
@ -996,9 +1046,10 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
|
||||
else_stmts = p.parse_block()
|
||||
}
|
||||
}
|
||||
mut typ := table.void_type
|
||||
//mut typ := table.void_type
|
||||
// mut left := ast.Expr{}
|
||||
// If the last statement is an expression, return its type
|
||||
/*
|
||||
if stmts.len > 0 {
|
||||
match stmts[stmts.len - 1] {
|
||||
ast.ExprStmt {
|
||||
@ -1011,16 +1062,17 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
|
||||
else {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
node = ast.IfExpr{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
else_stmts: else_stmts
|
||||
typ: typ
|
||||
//typ: typ
|
||||
pos: p.tok.position()
|
||||
// left: left
|
||||
|
||||
}
|
||||
return node,typ
|
||||
return node
|
||||
}
|
||||
|
||||
fn (p mut Parser) string_expr() (ast.Expr,table.Type) {
|
||||
@ -1054,7 +1106,8 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) {
|
||||
return node,table.string_type
|
||||
}
|
||||
|
||||
fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
//fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
fn (p mut Parser) array_init() ast.Expr {
|
||||
mut node := ast.Expr{}
|
||||
p.check(.lsbr)
|
||||
// `[]` - empty array with an automatically deduced type
|
||||
@ -1066,6 +1119,7 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
}
|
||||
*/
|
||||
|
||||
/* TODO: joe
|
||||
if p.tok.kind == .rsbr && int(p.expected_type) != 0 && p.table.get_type_symbol(p.expected_type).kind == .array {
|
||||
// p.warn('[] expr')
|
||||
node = ast.ArrayInit{
|
||||
@ -1076,10 +1130,11 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
p.check(.rsbr)
|
||||
return node,p.expected_type
|
||||
}
|
||||
*/
|
||||
mut val_type := table.void_type
|
||||
mut exprs := []ast.Expr
|
||||
mut is_fixed := false
|
||||
mut fixed_size := 0
|
||||
//mut is_fixed := false
|
||||
//mut fixed_size := 0
|
||||
if p.tok.kind == .rsbr {
|
||||
p.check(.rsbr)
|
||||
// []string
|
||||
@ -1104,9 +1159,11 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
line_nr := p.tok.line_nr
|
||||
//line_nr := p.tok.line_nr
|
||||
p.check(.rsbr)
|
||||
// Fixed size array? (`[100]byte`)
|
||||
// NOTE: this should be hanled in parse_type() ?
|
||||
/*
|
||||
if exprs.len == 1 && p.tok.kind == .name && p.tok.line_nr == line_nr {
|
||||
is_fixed = true
|
||||
val_type = p.parse_type()
|
||||
@ -1118,15 +1175,16 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
}
|
||||
p.warn('fixed size array')
|
||||
}
|
||||
*/
|
||||
}
|
||||
idx := if is_fixed { p.table.find_or_register_array_fixed(val_type, fixed_size, 1) } else { p.table.find_or_register_array(val_type, 1) }
|
||||
array_type := table.new_type(idx)
|
||||
//idx := if is_fixed { p.table.find_or_register_array_fixed(val_type, fixed_size, 1) } else { p.table.find_or_register_array(val_type, 1) }
|
||||
//array_type := table.new_type(idx)
|
||||
node = ast.ArrayInit{
|
||||
typ: array_type
|
||||
//typ: array_type
|
||||
exprs: exprs
|
||||
pos: p.tok.position()
|
||||
}
|
||||
return node,array_type
|
||||
return node
|
||||
}
|
||||
|
||||
fn (p mut Parser) parse_number_literal() (ast.Expr,table.Type) {
|
||||
@ -1363,26 +1421,37 @@ fn (p mut Parser) var_decl() ast.VarDecl {
|
||||
}
|
||||
name := p.check_name()
|
||||
p.next()
|
||||
expr,typ := p.expr(0)
|
||||
if _ := p.table.find_var(name) {
|
||||
//expr,typ := p.expr(0)
|
||||
expr,_ := p.expr(0)
|
||||
//if _ := p.table.find_var(name) {
|
||||
// p.error('redefinition of `$name`')
|
||||
//}
|
||||
//p.table.register_var(table.Var{
|
||||
// name: name
|
||||
// is_mut: is_mut
|
||||
// typ: typ
|
||||
//})
|
||||
if _ := p.scope.find_var(name) {
|
||||
p.error('redefinition of `$name`')
|
||||
}
|
||||
p.table.register_var(table.Var{
|
||||
name: name
|
||||
is_mut: is_mut
|
||||
typ: typ
|
||||
})
|
||||
typ_sym := p.table.get_type_symbol(typ)
|
||||
p.warn('var decl name=$name typ=$typ_sym.name')
|
||||
//p.scope.register_var(table.Var{
|
||||
// name: name
|
||||
// is_mut: is_mut
|
||||
// typ: typ
|
||||
//})
|
||||
|
||||
//typ_sym := p.table.get_type_symbol(typ)
|
||||
//p.warn('var decl name=$name typ=$typ_sym.name')
|
||||
// println(p.table.names)
|
||||
node := ast.VarDecl{
|
||||
name: name
|
||||
expr: expr // p.expr(token.lowest_prec)
|
||||
|
||||
is_mut: is_mut
|
||||
typ: typ
|
||||
//typ: typ
|
||||
pos: p.tok.position()
|
||||
}
|
||||
p.scope.register_var(node)
|
||||
return node
|
||||
}
|
||||
|
||||
@ -1427,19 +1496,19 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
|
||||
fn (p mut Parser) match_expr() ast.Expr {
|
||||
p.check(.key_match)
|
||||
is_mut := p.tok.kind == .key_mut
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
cond,typ := p.expr(0)
|
||||
cond,_ := p.expr(0)
|
||||
// sym := p.table.get_type_symbol(typ)
|
||||
// p.warn('match typ $sym.name')
|
||||
p.check(.lcbr)
|
||||
mut blocks := []ast.StmtBlock
|
||||
mut match_exprs := []ast.Expr
|
||||
mut return_type := table.void_type
|
||||
//mut return_type := table.void_type
|
||||
for {
|
||||
// Sum type match
|
||||
if p.tok.kind == .name && (p.tok.lit[0].is_capital() || p.peek_tok.kind == .dot) {
|
||||
@ -1475,6 +1544,7 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
|
||||
}
|
||||
}
|
||||
// If the last statement is an expression, return its type
|
||||
/*
|
||||
if stmts.len > 0 {
|
||||
match stmts[stmts.len - 1] {
|
||||
ast.ExprStmt {
|
||||
@ -1485,6 +1555,8 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
|
||||
else {}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if p.tok.kind == .rcbr {
|
||||
break
|
||||
}
|
||||
@ -1494,10 +1566,11 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
|
||||
node = ast.MatchExpr{
|
||||
blocks: blocks
|
||||
match_exprs: match_exprs
|
||||
typ: typ
|
||||
//typ: typ
|
||||
cond: cond
|
||||
}
|
||||
return node,return_type
|
||||
return node
|
||||
//return node,return_type
|
||||
}
|
||||
|
||||
fn (p mut Parser) enum_decl() ast.EnumDecl {
|
||||
@ -1562,18 +1635,6 @@ fn (p mut Parser) type_decl() ast.TypeDecl {
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) add_unresolved(key string, expr ast.Expr) table.Type {
|
||||
mut idx := p.unresolved_offset + p.unresolved.len
|
||||
if key in p.table.unresolved_idxs {
|
||||
idx = p.table.unresolved_idxs[key]
|
||||
}
|
||||
else {
|
||||
p.table.unresolved_idxs[key] = idx
|
||||
p.unresolved << expr
|
||||
}
|
||||
return table.new_type((-idx) - 1)
|
||||
}
|
||||
|
||||
fn verror(s string) {
|
||||
println(s)
|
||||
exit(1)
|
||||
|
@ -32,20 +32,26 @@ fn test_eval() {
|
||||
'20',
|
||||
//
|
||||
]
|
||||
/*
|
||||
table := table.new_table()
|
||||
mut scope := ast.Scope{start_pos: 0, parent: 0}
|
||||
mut stmts := []ast.Stmt
|
||||
for input in inputs {
|
||||
stmts << parse_stmt(input, table)
|
||||
stmts << parse_stmt(input, table, &scope)
|
||||
}
|
||||
file := ast.File{
|
||||
stmts: stmts
|
||||
scope: &scope
|
||||
}
|
||||
mut checker := checker.new_checker(table)
|
||||
checker.check(file)
|
||||
mut ev := eval.Eval{}
|
||||
s := ev.eval(file, table)
|
||||
println('eval done')
|
||||
println(s)
|
||||
assert s == expected.join('\n')
|
||||
// exit(0)
|
||||
*/
|
||||
}
|
||||
|
||||
fn test_parse_file() {
|
||||
@ -65,6 +71,8 @@ x := 10
|
||||
'
|
||||
table := &table.Table{}
|
||||
prog := parse_file(s, table)
|
||||
mut checker := checker.new_checker(table)
|
||||
checker.check(prog)
|
||||
res := gen.cgen([prog], table)
|
||||
println(res)
|
||||
}
|
||||
@ -79,14 +87,21 @@ fn test_one() {
|
||||
]
|
||||
expected := 'int a = 10;int b = -a;int c = 20;'
|
||||
table := table.new_table()
|
||||
mut scope := ast.Scope{start_pos: 0, parent: 0}
|
||||
mut e := []ast.Stmt
|
||||
for line in input {
|
||||
e << parse_stmt(line, table)
|
||||
e << parse_stmt(line, table, &scope)
|
||||
}
|
||||
program := ast.File{
|
||||
stmts: e
|
||||
scope: scope
|
||||
}
|
||||
mut checker := checker.new_checker(table)
|
||||
checker.check(program)
|
||||
//ast.print_scope_vars(scope, 0)
|
||||
//ast.print_scope_vars(program.scope, 0)
|
||||
res := gen.cgen([program], table).replace('\n', '').trim_space()
|
||||
println(res)
|
||||
ok := expected == res
|
||||
println(res)
|
||||
assert ok
|
||||
@ -166,12 +181,14 @@ fn test_parse_expr() {
|
||||
mut e := []ast.Stmt
|
||||
table := table.new_table()
|
||||
mut checker := checker.new_checker(table)
|
||||
mut scope := ast.Scope{start_pos: 0, parent: 0}
|
||||
for s in input {
|
||||
println('\n\nst="$s"')
|
||||
e << parse_stmt(s, table)
|
||||
e << parse_stmt(s, table, &scope)
|
||||
}
|
||||
program := ast.File{
|
||||
stmts: e
|
||||
scope: scope
|
||||
}
|
||||
checker.check(program)
|
||||
res := gen.cgen([program], table)
|
||||
|
@ -80,6 +80,7 @@ fn (s &Scanner) scan_res(tok_kind token.Kind, lit string) token.Token {
|
||||
kind: tok_kind
|
||||
lit: lit
|
||||
line_nr: s.line_nr + 1
|
||||
pos: s.pos
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ pub mut:
|
||||
types []TypeSymbol
|
||||
// type_idxs Hashmap
|
||||
type_idxs map[string]int
|
||||
unresolved_idxs map[string]int
|
||||
local_vars []Var
|
||||
scope_level int
|
||||
var_idx int
|
||||
@ -308,7 +307,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
|
||||
return &t.types[idx]
|
||||
}
|
||||
// this should never happen
|
||||
panic('get_type_symbol: invalid type $idx')
|
||||
panic('get_type_symbol: invalid type $typ - $idx')
|
||||
}
|
||||
|
||||
// this will override or register builtin type
|
||||
|
@ -6,14 +6,13 @@ module token
|
||||
pub struct Position {
|
||||
pub:
|
||||
line_nr int // the line number in the source where the token occured
|
||||
// pos int // the position of the token in scanner text
|
||||
pos int // the position of the token in scanner text
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (tok &Token) position() Position {
|
||||
return Position{
|
||||
line_nr: tok.line_nr - 1
|
||||
// pos: tok.pos
|
||||
|
||||
pos: tok.pos
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ pub:
|
||||
lit string // literal representation of the token
|
||||
line_nr int // the line number in the source where the token occured
|
||||
// name_idx int // name table index for O(1) lookup
|
||||
// pos int // the position of the token in scanner text
|
||||
pos int // the position of the token in scanner text
|
||||
}
|
||||
|
||||
pub enum Kind {
|
||||
|
Loading…
Reference in New Issue
Block a user