1
0
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:
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:
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
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.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')

View File

@ -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
return typ
//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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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

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 {
// 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) {

View File

@ -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()
@ -1115,18 +1172,19 @@ fn (p mut Parser) array_init() (ast.Expr,table.Type) {
fixed_size = it.val
}
else {}
}
}
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 {
@ -1483,8 +1553,10 @@ fn (p mut Parser) match_expr() (ast.Expr,table.Type) {
return_type = it.typ
}
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)

View File

@ -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)

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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 {