v2: remove unresolved types; handle types in checker; add ast.scope

pull/3748/head
joe-conigliaro 2020-02-15 23:37:48 +11:00 committed by GitHub
parent c2c6260ba2
commit dc90f4f4a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 536 additions and 227 deletions

View File

@ -70,6 +70,7 @@ pub struct Field {
pub: pub:
name string name string
// type_idx int // type_idx int
mut:
typ table.Type typ table.Type
} }
@ -197,6 +198,7 @@ pub:
mod Module mod Module
imports []Import imports []Import
stmts []Stmt stmts []Stmt
scope Scope
unresolved []Expr unresolved []Expr
} }
@ -292,9 +294,10 @@ pub:
cond Expr cond Expr
stmts []Stmt stmts []Stmt
else_stmts []Stmt else_stmts []Stmt
typ table.Type
left Expr // `a` in `a := if ...` left Expr // `a` in `a := if ...`
pos token.Position pos token.Position
mut:
typ table.Type
} }
pub struct MatchExpr { pub struct MatchExpr {
@ -303,8 +306,9 @@ pub:
cond Expr cond Expr
blocks []StmtBlock blocks []StmtBlock
match_exprs []Expr match_exprs []Expr
typ table.Type
pos token.Position pos token.Position
mut:
typ table.Type
} }
pub struct CompIf { pub struct CompIf {

143
vlib/v/ast/scope.v 100644
View 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)
}
}

View File

@ -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.parsed_files = parser.parse_files(v_files, b.table)
b.parse_imports() b.parse_imports()
b.checker.check_files(b.parsed_files) 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) 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 parse_time := t1 - t0
println('PARSE: ${parse_time}ms') println('PARSE: ${parse_time}ms')
b.checker.check_files(b.parsed_files) b.checker.check_files(b.parsed_files)
//println('=======================')
//ast.print_scope_vars(&b.parsed_files[0].scope, 0)
//println('=======================')
t2 := time.ticks() t2 := time.ticks()
check_time := t2 - t1 check_time := t2 - t1
println('CHECK: ${check_time}ms') println('CHECK: ${check_time}ms')

View File

@ -14,6 +14,7 @@ pub struct Checker {
table &table.Table table &table.Table
mut: mut:
file_name string file_name string
scope ast.Scope
resolved []table.Type 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) { pub fn (c mut Checker) check(ast_file ast.File) {
c.file_name = ast_file.path c.file_name = ast_file.path
// if ast_file.unresolved.len != c.resolved.len { c.scope = ast_file.scope
// c.resolve_exprs(file)
// }
c.complete_types()
for stmt in ast_file.stmts { for stmt in ast_file.stmts {
c.stmt(stmt) c.stmt(stmt)
} }
} }
pub fn (c mut Checker) check_files(ast_files []ast.File) { 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 { for file in ast_files {
c.check(file) c.check(file)
} }
} }
// resolve type of unresolved expressions pub fn (c mut Checker) check_struct_init(struct_init ast.StructInit) table.Type {
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 {
// typ := c.table.find_type(struct_init.typ.typ.name) or { // typ := c.table.find_type(struct_init.typ.typ.name) or {
// c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos) // c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
// panic('') // panic('')
// } // }
typ := c.table.get_type_symbol(struct_init.typ) typ_sym := c.table.get_type_symbol(struct_init.typ)
match typ.kind { match typ_sym.kind {
.placeholder { .placeholder {
c.error('unknown struct: $typ.name', struct_init.pos) c.error('unknown struct: $typ_sym.name', struct_init.pos)
} }
.struct_ { .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 { 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 := c.expr(expr)
expr_type_sym := c.table.get_type_symbol(expr_type) expr_type_sym := c.table.get_type_symbol(expr_type)
field_type_sym := c.table.get_type_symbol(field.typ) 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 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) left_type := c.expr(infix_expr.left)
right_type := c.expr(infix_expr.right) right_type := c.expr(infix_expr.right)
if !c.table.check(right_type, left_type) { 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 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) left_type := c.expr(assign_expr.left)
right_type := c.expr(assign_expr.val) right_type := c.expr(assign_expr.val)
if !c.table.check(right_type, left_type) { 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 fn_name := call_expr.name
if f := c.table.find_fn(fn_name) { if f := c.table.find_fn(fn_name) {
// return_ti := f.return_ti // return_ti := f.return_ti
@ -195,7 +136,7 @@ pub fn (c &Checker) call_expr(call_expr ast.CallExpr) table.Type {
exit(1) 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 := c.expr(method_call_expr.expr)
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
if method := typ_sym.find_method(method_call_expr.name) { 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) 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 := c.expr(selector_expr.expr)
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
field_name := selector_expr.field field_name := selector_expr.field
@ -221,9 +162,6 @@ pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type {
// check parent // check parent
if !isnil(typ_sym.parent) { if !isnil(typ_sym.parent) {
if field := typ_sym.parent.find_field(field_name) { if field := typ_sym.parent.find_field(field_name) {
if table.type_is_unresolved(field.typ) {
return c.resolved[field.typ]
}
return field.typ return field.typ
} }
} }
@ -237,7 +175,7 @@ pub fn (c &Checker) selector_expr(selector_expr ast.SelectorExpr) table.Type {
} }
// TODO: non deferred // 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 mut got_types := []table.Type
if return_stmt.exprs.len == 0 { if return_stmt.exprs.len == 0 {
return 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) 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 mut elem_type := table.void_type
// a = []
if array_init.exprs.len == 0 {
}
for i, expr in array_init.exprs { for i, expr in array_init.exprs {
c.expr(expr) c.expr(expr)
typ := 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) 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 return array_init.typ
} }
fn (c &Checker) stmt(node ast.Stmt) { fn (c mut Checker) stmt(node ast.Stmt) {
match mut node { match mut node {
ast.FnDecl { ast.FnDecl {
for stmt in it.stmts { for stmt in it.stmts {
@ -299,14 +254,29 @@ fn (c &Checker) stmt(node ast.Stmt) {
ast.AssignStmt { ast.AssignStmt {
c.assign_stmt(it) c.assign_stmt(it)
} }
ast.VarDecl { ast.ConstDecl {
typ := c.expr(it.expr) for i, expr in it.exprs {
// println('checker: var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr') mut field := it.fields[i]
// if typ.typ.kind != .void { typ := c.expr(expr)
if table.type_idx(typ) != table.void_type_idx { mut xconst := c.table.consts[field.name]
it.typ = typ //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 { ast.ForStmt {
typ := c.expr(it.cond) typ := c.expr(it.cond)
// typ_sym := c.table.get_type_symbol(typ) // 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 { match mut node {
ast.AssignExpr { ast.AssignExpr {
c.check_assign_expr(it) c.check_assign_expr(it)
@ -342,7 +312,9 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
ast.IntegerLiteral { ast.IntegerLiteral {
return table.int_type return table.int_type
} }
// ast.FloatLiteral {} ast.FloatLiteral{
return table.f64_type
}
ast.PostfixExpr { ast.PostfixExpr {
return c.postfix_expr(it) return c.postfix_expr(it)
} }
@ -351,7 +323,6 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
c.expr(it.left) c.expr(it.left)
} }
*/ */
ast.StringLiteral { ast.StringLiteral {
return table.string_type 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) return c.check_method_call_expr(it)
} }
ast.ArrayInit { ast.ArrayInit {
return c.array_init(it) return c.array_init(mut it)
} }
ast.Ident { ast.Ident {
//println('IDENT: $it.name - $it.pos.pos')
if it.kind == .variable { if it.kind == .variable {
mut info := it.info as ast.IdentVar //println('===========================')
if table.type_is_unresolved(info.typ) { //ast.print_scope_vars(&c.scope, 0)
typ := c.resolve(info.typ) //println('===========================')
info.typ = typ info := it.info as ast.IdentVar
it.info = info if info.typ != 0 {
return typ 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 // Handle indents with unresolved types during the parsing step
// (declared after first usage) // (declared after first usage)
else if it.kind == .blank_ident { else if it.kind == .constant {
if constant := c.table.find_const(it.name) { if constant := c.table.find_const(it.name) {
return constant.typ 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 return table.void_type
} }
ast.BoolLiteral { ast.BoolLiteral {
@ -403,20 +407,10 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
return c.index_expr(it) return c.index_expr(it)
} }
ast.IfExpr { ast.IfExpr {
typ := c.expr(it.cond) return c.if_expr(mut it)
typ_sym := c.table.get_type_symbol(typ) }
// if typ_sym.kind != .bool { ast.MatchExpr {
if table.type_idx(typ) != table.bool_type_idx { return c.match_expr(mut it)
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)
}
}
} }
ast.CastExpr { ast.CastExpr {
return it.typ return it.typ
@ -426,7 +420,70 @@ pub fn (c &Checker) expr(node ast.Expr) table.Type {
return table.void_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 { match node.expr {
ast.IdentVar { ast.IdentVar {
@ -444,7 +501,16 @@ pub fn (c &Checker) postfix_expr(node ast.PostfixExpr) table.Type {
return typ 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 typ := c.expr(node.left)
mut is_range := false // TODO is_range := node.index is ast.RangeExpr mut is_range := false // TODO is_range := node.index is ast.RangeExpr
match node.index { match node.index {

View File

@ -112,12 +112,12 @@ void println(string s) {
void matches() { void matches() {
int a = 100; int a = 100;
int tmp2 = a; int tmp3 = a;
if tmp2 == 10{ if tmp3 == 10{
println(tos3("10")); println(tos3("10"));
} }
if tmp2 == 20{ if tmp3 == 20{
int k = a + 1; int k = a + 1;
} }

View File

@ -310,6 +310,7 @@ pub fn (g mut Gen) call_fn(name string) {
fn (g mut Gen) stmt(node ast.Stmt) { fn (g mut Gen) stmt(node ast.Stmt) {
match node { match node {
ast.ConstDecl {}
ast.FnDecl { ast.FnDecl {
is_main := it.name == 'main' is_main := it.name == 'main'
if is_main { if is_main {

View File

@ -8,17 +8,15 @@ import (
v.table 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 tok := p.tok
fn_name := p.check_name() fn_name := p.check_name()
p.check(.lpar) p.check(.lpar)
// mut return_ti := types.void_ti
args := p.call_args() args := p.call_args()
node := ast.CallExpr{ node := ast.CallExpr{
name: fn_name name: fn_name
args: args args: args
// tok: tok // tok: tok
pos: tok.position() pos: tok.position()
} }
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
@ -26,10 +24,9 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) {
p.parse_block() p.parse_block()
} }
if f := p.table.find_fn(fn_name) { if f := p.table.find_fn(fn_name) {
return node,f.return_type return node
} }
typ := p.add_unresolved('${fn_name}()', node) return node
return node,typ
} }
pub fn (p mut Parser) call_args() []ast.Expr { 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 { 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 is_pub := p.tok.kind == .key_pub
if is_pub { if is_pub {
p.next() p.next()
} }
p.table.clear_vars() //p.table.clear_vars()
p.check(.key_fn) p.check(.key_fn)
// C. // C.
is_c := p.tok.kind == .name && p.tok.lit == '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() p.next()
} }
rec_type = p.parse_type() 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 name: rec_name
typ: rec_type typ: rec_type
}) })
@ -101,7 +103,11 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
typ: ast_arg.typ typ: ast_arg.typ
} }
args << var 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 { if p.tok.kind == .lcbr {
stmts = p.parse_block() stmts = p.parse_block()
} }
p.close_scope()
return ast.FnDecl{ return ast.FnDecl{
name: name name: name
stmts: stmts stmts: stmts

View File

@ -78,6 +78,13 @@ pub fn (p mut Parser) parse_fn_type() table.Type {
} }
pub fn (p mut Parser) parse_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 mut nr_muls := 0
for p.tok.kind == .amp { for p.tok.kind == .amp {
p.check(.amp) p.check(.amp)
@ -87,9 +94,6 @@ pub fn (p mut Parser) parse_type() table.Type {
p.next() p.next()
p.check(.dot) p.check(.dot)
} }
if p.tok.kind == .question {
p.next()
}
// `module.Type` // `module.Type`
if p.peek_tok.kind == .dot { if p.peek_tok.kind == .dot {
// /if !(p.tok.lit in p.table.imports) { // /if !(p.tok.lit in p.table.imports) {

View File

@ -43,18 +43,19 @@ mut:
pref &pref.Preferences // Preferences shared from V struct pref &pref.Preferences // Preferences shared from V struct
builtin_mod bool builtin_mod bool
mod string mod string
unresolved []ast.Expr
unresolved_offset int
expected_type table.Type expected_type table.Type
scope &ast.Scope
} }
// for tests // 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) s := scanner.new_scanner(text)
mut p := Parser{ mut p := Parser{
scanner: s scanner: s
table: table table: table
pref: &pref.Preferences{} pref: &pref.Preferences{}
scope: scope
//scope: &ast.Scope{start_pos: 0, parent: 0}
} }
p.init_parse_fns() p.init_parse_fns()
p.read_first_token() p.read_first_token()
@ -72,9 +73,10 @@ pub fn parse_file(path string, table &table.Table) ast.File {
table: table table: table
file_name: path file_name: path
pref: &pref.Preferences{} pref: &pref.Preferences{}
unresolved_offset: table.unresolved_idxs.size scope: &ast.Scope{start_pos: 0, parent: 0}
} }
p.read_first_token() p.read_first_token()
//p.scope = &ast.Scope{start_pos: p.tok.position(), parent: 0}
// module decl // module decl
module_decl := if p.tok.kind == .key_module { p.module_decl() } else { ast.Module{name: 'main' 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('nr stmts = $stmts.len')
// println(stmts[0]) // println(stmts[0])
p.scope.end_pos = p.tok.pos
return ast.File{ return ast.File{
path: path path: path
mod: module_decl mod: module_decl
imports: imports imports: imports
stmts: stmts stmts: stmts
unresolved: p.unresolved scope: *p.scope
} }
} }
@ -126,7 +131,22 @@ pub fn (p mut Parser) read_first_token() {
p.next() 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 { pub fn (p mut Parser) parse_block() []ast.Stmt {
p.open_scope()
p.table.open_scope() p.table.open_scope()
p.check(.lcbr) p.check(.lcbr)
mut stmts := []ast.Stmt mut stmts := []ast.Stmt
@ -140,6 +160,8 @@ pub fn (p mut Parser) parse_block() []ast.Stmt {
} }
} }
p.check(.rcbr) p.check(.rcbr)
println('parse block')
p.close_scope()
p.table.close_scope() p.table.close_scope()
// println('nr exprs in block = $exprs.len') // println('nr exprs in block = $exprs.len')
return stmts 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] { if p.tok.kind == .name && p.peek_tok.kind in [.comma] {
return p.assign_stmt() return p.assign_stmt()
} }
expr,typ := p.expr(0) //expr,typ := p.expr(0)
expr,_ := p.expr(0)
return ast.ExprStmt{ return ast.ExprStmt{
expr: expr 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{ mut ident := ast.Ident{
name: name name: name
is_c: is_c is_c: is_c
pos: p.tok.position()
} }
mut known_var := false mut known_var := false
if var := p.table.find_var(name) { if var := p.scope.find_var(name) {
known_var = true known_var = true
typ = var.typ // typ = var.typ
} }
// variable // 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') // println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx')
ident.kind = .variable ident.kind = .variable
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ //typ: typ
// name: ident.name // name: ident.name
// expr: p.expr(0)// var.expr // expr: p.expr(0)// var.expr
} }
return ident,typ return ident,typ
} }
@ -457,6 +480,7 @@ pub fn (p mut Parser) parse_ident(is_c bool) (ast.Ident,table.Type) {
node = ast.Ident{ node = ast.Ident{
kind: .blank_ident kind: .blank_ident
name: name name: name
//pos: p.tok.position()
} }
return node,typ return node,typ
// p.error('parse_ident: unknown identifier `$name`') // p.error('parse_ident: unknown identifier `$name`')
@ -559,9 +583,8 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
// fn call // fn call
else { else {
println('calling $p.tok.lit') 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 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() { 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() p.next()
} }
.key_match { .key_match {
node,typ = p.match_expr() //node,typ = p.match_expr()
node = p.match_expr()
} }
.number { .number {
node,typ = p.parse_number_literal() 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) p.check(.rpar)
} }
.key_if { .key_if {
node,typ = p.if_expr() node = p.if_expr()
} }
.lsbr { .lsbr {
node,typ = p.array_init() //node,typ = p.array_init()
node = p.array_init()
} }
.key_none { .key_none {
p.next() p.next()
@ -669,13 +694,15 @@ pub fn (p mut Parser) expr(precedence int) (ast.Expr,table.Type) {
node = p.assign_expr(node) node = p.assign_expr(node)
} }
else if p.tok.kind == .dot { 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 { 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) ie_node,ie_typ := p.index_expr(node, typ)
node = ie_node node = ie_node
typ = ie_typ typ = ie_typ
*/
} }
else if p.tok.kind == .key_as { else if p.tok.kind == .key_as {
p.next() p.next()
@ -712,7 +739,7 @@ fn (p mut Parser) prefix_expr() (ast.Expr,table.Type) {
return expr,typ 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]` // left == `a` in `a[0]`
p.next() // [ p.next() // [
if p.tok.kind == .dotdot { 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{} low: ast.Expr{}
high: high high: high
} }
},left_type // TODO: return correct type }
} }
expr,_ := p.expr(0) // `[expr]` or `[expr..]` expr,_ := p.expr(0) // `[expr]` or `[expr..]`
if p.tok.kind == .dotdot { 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 low: expr
high: high high: high
} }
},left_type // TODO: return correct type }
} }
// get the element type // get the element type
/*
mut typ := left_type mut typ := left_type
left_type_sym := p.table.get_type_symbol(left_type) left_type_sym := p.table.get_type_symbol(left_type)
if left_type_sym.kind == .array { if left_type_sym.kind == .array {
info := left_type_sym.info as table.Array info := left_type_sym.info as table.Array
typ = info.elem_type typ = info.elem_type
} }
*/
// [expr] // [expr]
p.check(.rsbr) p.check(.rsbr)
return ast.IndexExpr{ return ast.IndexExpr{
left: left left: left
index: expr index: expr
pos: p.tok.position() pos: p.tok.position()
},typ }
} }
fn (p mut Parser) filter(typ table.Type) { fn (p mut Parser) filter(typ table.Type) {
/*
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: 'it' name: 'it'
typ: typ 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() p.next()
field_name := p.check_name() field_name := p.check_name()
if field_name == 'filter' { if field_name == 'filter' {
p.open_scope()
p.table.open_scope() p.table.open_scope()
p.filter(left_type) 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{} mut node := ast.Expr{}
node = mcall_expr node = mcall_expr
// typ := p.add_unresolved('${left_type.typ.name}.${field_name}()', 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) // typ := p.add_unresolved('${table.type_idx(left_type)}.${field_name}()', mcall_expr)
return node,typ return node
} }
sel_expr := ast.SelectorExpr{ sel_expr := ast.SelectorExpr{
expr: left 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() pos: p.tok.position()
} }
// typ := p.add_unresolved('${left_type.typ.name}.$field_name', sel_expr) // 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{} mut node := ast.Expr{}
node = sel_expr node = sel_expr
if field_name == 'filter' { if field_name == 'filter' {
p.close_scope()
p.table.close_scope() p.table.close_scope()
} }
return node,typ return node
} }
fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,table.Type) { 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 { fn (p mut Parser) for_statement() ast.Stmt {
p.check(.key_for) p.check(.key_for)
p.open_scope()
p.table.open_scope() p.table.open_scope()
// defer { p.table.close_scope() } // defer { p.table.close_scope() }
// Infinite loop // Infinite loop
if p.tok.kind == .lcbr { if p.tok.kind == .lcbr {
stmts := p.parse_block() stmts := p.parse_block()
p.close_scope()
p.table.close_scope() p.table.close_scope()
return ast.ForStmt{ return ast.ForStmt{
stmts: stmts stmts: stmts
@ -896,6 +935,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
inc = p.stmt() inc = p.stmt()
} }
stmts := p.parse_block() stmts := p.parse_block()
p.close_scope()
p.table.close_scope() p.table.close_scope()
return ast.ForCStmt{ return ast.ForCStmt{
stmts: stmts stmts: stmts
@ -910,7 +950,11 @@ fn (p mut Parser) for_statement() ast.Stmt {
if p.tok.kind == .comma { if p.tok.kind == .comma {
p.check(.comma) p.check(.comma)
val_name := p.check_name() 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 name: val_name
typ: table.int_type typ: table.int_type
}) })
@ -945,12 +989,17 @@ fn (p mut Parser) for_statement() ast.Stmt {
p.check(.dotdot) p.check(.dotdot)
p.expr(0) 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 name: var_name
typ: elem_type typ: elem_type
}) })
stmts := p.parse_block() stmts := p.parse_block()
// println('nr stmts=$stmts.len') // println('nr stmts=$stmts.len')
p.close_scope()
p.table.close_scope() p.table.close_scope()
return ast.ForStmt{ return ast.ForStmt{
stmts: stmts stmts: stmts
@ -960,6 +1009,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
// `for cond {` // `for cond {`
cond,_ := p.expr(0) cond,_ := p.expr(0)
stmts := p.parse_block() stmts := p.parse_block()
p.close_scope()
p.table.close_scope() p.table.close_scope()
return ast.ForStmt{ return ast.ForStmt{
cond: cond 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 p.inside_if = true
// defer { // defer {
// } // }
@ -996,9 +1046,10 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
else_stmts = p.parse_block() else_stmts = p.parse_block()
} }
} }
mut typ := table.void_type //mut typ := table.void_type
// mut left := ast.Expr{} // mut left := ast.Expr{}
// If the last statement is an expression, return its type // If the last statement is an expression, return its type
/*
if stmts.len > 0 { if stmts.len > 0 {
match stmts[stmts.len - 1] { match stmts[stmts.len - 1] {
ast.ExprStmt { ast.ExprStmt {
@ -1011,16 +1062,17 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
else {} else {}
} }
} }
*/
node = ast.IfExpr{ node = ast.IfExpr{
cond: cond cond: cond
stmts: stmts stmts: stmts
else_stmts: else_stmts else_stmts: else_stmts
typ: typ //typ: typ
pos: p.tok.position() pos: p.tok.position()
// left: left // left: left
} }
return node,typ return node
} }
fn (p mut Parser) string_expr() (ast.Expr,table.Type) { 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 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{} mut node := ast.Expr{}
p.check(.lsbr) p.check(.lsbr)
// `[]` - empty array with an automatically deduced type // `[]` - 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 { if p.tok.kind == .rsbr && int(p.expected_type) != 0 && p.table.get_type_symbol(p.expected_type).kind == .array {
// p.warn('[] expr') // p.warn('[] expr')
node = ast.ArrayInit{ node = ast.ArrayInit{
@ -1076,10 +1130,11 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
p.check(.rsbr) p.check(.rsbr)
return node,p.expected_type return node,p.expected_type
} }
*/
mut val_type := table.void_type mut val_type := table.void_type
mut exprs := []ast.Expr mut exprs := []ast.Expr
mut is_fixed := false //mut is_fixed := false
mut fixed_size := 0 //mut fixed_size := 0
if p.tok.kind == .rsbr { if p.tok.kind == .rsbr {
p.check(.rsbr) p.check(.rsbr)
// []string // []string
@ -1104,9 +1159,11 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
p.check(.comma) p.check(.comma)
} }
} }
line_nr := p.tok.line_nr //line_nr := p.tok.line_nr
p.check(.rsbr) p.check(.rsbr)
// Fixed size array? (`[100]byte`) // 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 { if exprs.len == 1 && p.tok.kind == .name && p.tok.line_nr == line_nr {
is_fixed = true is_fixed = true
val_type = p.parse_type() val_type = p.parse_type()
@ -1115,18 +1172,19 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
fixed_size = it.val fixed_size = it.val
} }
else {} else {}
} }
p.warn('fixed size array') 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) } //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) //array_type := table.new_type(idx)
node = ast.ArrayInit{ node = ast.ArrayInit{
typ: array_type //typ: array_type
exprs: exprs exprs: exprs
pos: p.tok.position() pos: p.tok.position()
} }
return node,array_type return node
} }
fn (p mut Parser) parse_number_literal() (ast.Expr,table.Type) { 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() name := p.check_name()
p.next() p.next()
expr,typ := p.expr(0) //expr,typ := p.expr(0)
if _ := p.table.find_var(name) { 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.error('redefinition of `$name`')
} }
p.table.register_var(table.Var{ //p.scope.register_var(table.Var{
name: name // name: name
is_mut: is_mut // is_mut: is_mut
typ: typ // typ: typ
}) //})
typ_sym := p.table.get_type_symbol(typ)
p.warn('var decl name=$name typ=$typ_sym.name') //typ_sym := p.table.get_type_symbol(typ)
//p.warn('var decl name=$name typ=$typ_sym.name')
// println(p.table.names) // println(p.table.names)
node := ast.VarDecl{ node := ast.VarDecl{
name: name name: name
expr: expr // p.expr(token.lowest_prec) expr: expr // p.expr(token.lowest_prec)
is_mut: is_mut is_mut: is_mut
typ: typ //typ: typ
pos: p.tok.position() pos: p.tok.position()
} }
p.scope.register_var(node)
return 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) p.check(.key_match)
is_mut := p.tok.kind == .key_mut is_mut := p.tok.kind == .key_mut
if is_mut { if is_mut {
p.next() p.next()
} }
cond,typ := p.expr(0) cond,_ := p.expr(0)
// sym := p.table.get_type_symbol(typ) // sym := p.table.get_type_symbol(typ)
// p.warn('match typ $sym.name') // p.warn('match typ $sym.name')
p.check(.lcbr) p.check(.lcbr)
mut blocks := []ast.StmtBlock mut blocks := []ast.StmtBlock
mut match_exprs := []ast.Expr mut match_exprs := []ast.Expr
mut return_type := table.void_type //mut return_type := table.void_type
for { for {
// Sum type match // Sum type match
if p.tok.kind == .name && (p.tok.lit[0].is_capital() || p.peek_tok.kind == .dot) { 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 the last statement is an expression, return its type
/*
if stmts.len > 0 { if stmts.len > 0 {
match stmts[stmts.len - 1] { match stmts[stmts.len - 1] {
ast.ExprStmt { ast.ExprStmt {
@ -1483,8 +1553,10 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
return_type = it.typ return_type = it.typ
} }
else {} else {}
} }
} }
*/
if p.tok.kind == .rcbr { if p.tok.kind == .rcbr {
break break
} }
@ -1494,10 +1566,11 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
node = ast.MatchExpr{ node = ast.MatchExpr{
blocks: blocks blocks: blocks
match_exprs: match_exprs match_exprs: match_exprs
typ: typ //typ: typ
cond: cond cond: cond
} }
return node,return_type return node
//return node,return_type
} }
fn (p mut Parser) enum_decl() ast.EnumDecl { 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) { fn verror(s string) {
println(s) println(s)
exit(1) exit(1)

View File

@ -32,20 +32,26 @@ fn test_eval() {
'20', '20',
// //
] ]
/*
table := table.new_table() table := table.new_table()
mut scope := ast.Scope{start_pos: 0, parent: 0}
mut stmts := []ast.Stmt mut stmts := []ast.Stmt
for input in inputs { for input in inputs {
stmts << parse_stmt(input, table) stmts << parse_stmt(input, table, &scope)
} }
file := ast.File{ file := ast.File{
stmts: stmts stmts: stmts
scope: &scope
} }
mut checker := checker.new_checker(table)
checker.check(file)
mut ev := eval.Eval{} mut ev := eval.Eval{}
s := ev.eval(file, table) s := ev.eval(file, table)
println('eval done') println('eval done')
println(s) println(s)
assert s == expected.join('\n') assert s == expected.join('\n')
// exit(0) // exit(0)
*/
} }
fn test_parse_file() { fn test_parse_file() {
@ -65,6 +71,8 @@ x := 10
' '
table := &table.Table{} table := &table.Table{}
prog := parse_file(s, table) prog := parse_file(s, table)
mut checker := checker.new_checker(table)
checker.check(prog)
res := gen.cgen([prog], table) res := gen.cgen([prog], table)
println(res) println(res)
} }
@ -79,14 +87,21 @@ fn test_one() {
] ]
expected := 'int a = 10;int b = -a;int c = 20;' expected := 'int a = 10;int b = -a;int c = 20;'
table := table.new_table() table := table.new_table()
mut scope := ast.Scope{start_pos: 0, parent: 0}
mut e := []ast.Stmt mut e := []ast.Stmt
for line in input { for line in input {
e << parse_stmt(line, table) e << parse_stmt(line, table, &scope)
} }
program := ast.File{ program := ast.File{
stmts: e 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() res := gen.cgen([program], table).replace('\n', '').trim_space()
println(res)
ok := expected == res ok := expected == res
println(res) println(res)
assert ok assert ok
@ -166,12 +181,14 @@ fn test_parse_expr() {
mut e := []ast.Stmt mut e := []ast.Stmt
table := table.new_table() table := table.new_table()
mut checker := checker.new_checker(table) mut checker := checker.new_checker(table)
mut scope := ast.Scope{start_pos: 0, parent: 0}
for s in input { for s in input {
println('\n\nst="$s"') println('\n\nst="$s"')
e << parse_stmt(s, table) e << parse_stmt(s, table, &scope)
} }
program := ast.File{ program := ast.File{
stmts: e stmts: e
scope: scope
} }
checker.check(program) checker.check(program)
res := gen.cgen([program], table) res := gen.cgen([program], table)

View File

@ -80,6 +80,7 @@ fn (s &Scanner) scan_res(tok_kind token.Kind, lit string) token.Token {
kind: tok_kind kind: tok_kind
lit: lit lit: lit
line_nr: s.line_nr + 1 line_nr: s.line_nr + 1
pos: s.pos
} }
} }

View File

@ -11,7 +11,6 @@ pub mut:
types []TypeSymbol types []TypeSymbol
// type_idxs Hashmap // type_idxs Hashmap
type_idxs map[string]int type_idxs map[string]int
unresolved_idxs map[string]int
local_vars []Var local_vars []Var
scope_level int scope_level int
var_idx int var_idx int
@ -308,7 +307,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
return &t.types[idx] return &t.types[idx]
} }
// this should never happen // 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 // this will override or register builtin type

View File

@ -6,14 +6,13 @@ module token
pub struct Position { pub struct Position {
pub: pub:
line_nr int // the line number in the source where the token occured 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] [inline]
pub fn (tok &Token) position() Position { pub fn (tok &Token) position() Position {
return Position{ return Position{
line_nr: tok.line_nr - 1 line_nr: tok.line_nr - 1
// pos: tok.pos pos: tok.pos
} }
} }

View File

@ -9,7 +9,7 @@ pub:
lit string // literal representation of the token lit string // literal representation of the token
line_nr int // the line number in the source where the token occured line_nr int // the line number in the source where the token occured
// name_idx int // name table index for O(1) lookup // 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 { pub enum Kind {