v2: move more type handling to checker + some clean up
parent
41808f80fd
commit
d7f74ecf52
|
@ -199,23 +199,27 @@ pub:
|
|||
imports []Import
|
||||
stmts []Stmt
|
||||
scope Scope
|
||||
unresolved []Expr
|
||||
}
|
||||
|
||||
pub struct IdentFunc {
|
||||
pub mut:
|
||||
return_type table.Type
|
||||
}
|
||||
|
||||
pub struct IdentVar {
|
||||
pub mut:
|
||||
typ table.Type
|
||||
is_mut bool
|
||||
// name string
|
||||
}
|
||||
|
||||
type IdentInfo = IdentVar
|
||||
type IdentInfo = IdentFunc | IdentVar
|
||||
|
||||
pub enum IdentKind {
|
||||
unresolved
|
||||
blank_ident
|
||||
variable
|
||||
constant
|
||||
func
|
||||
function
|
||||
}
|
||||
|
||||
// A single identifier
|
||||
|
|
|
@ -20,7 +20,6 @@ pub fn new_scope(parent &Scope, start_pos int) &Scope {
|
|||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) {
|
||||
if name in s.vars {
|
||||
return s,s.vars[name]
|
||||
|
@ -30,12 +29,10 @@ pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) {
|
|||
return sc,sc.vars[name]
|
||||
}
|
||||
}
|
||||
return error('not found')
|
||||
return none
|
||||
}
|
||||
|
||||
[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]
|
||||
}
|
||||
|
@ -44,39 +41,9 @@ pub fn (s &Scope) find_var(name string) ?VarDecl {
|
|||
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')
|
||||
|
@ -85,16 +52,13 @@ pub fn (s mut Scope) register_var(var VarDecl) {
|
|||
s.vars[var.name] = var
|
||||
}
|
||||
|
||||
pub fn (s mut Scope) override_var(var VarDecl) {
|
||||
s.vars[var.name] = var
|
||||
}
|
||||
|
||||
// returns the innermost scope containing pos
|
||||
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
|
||||
|
@ -118,17 +82,29 @@ pub fn (s &Scope) innermost(pos int) ?&Scope {
|
|||
}
|
||||
return s
|
||||
}
|
||||
return s
|
||||
//return error('none')
|
||||
//return none
|
||||
return none
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
}
|
||||
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) {
|
||||
pub fn (sc &Scope) print_vars(level int) {
|
||||
mut indent := ''
|
||||
for _ in 0..level*4 {
|
||||
indent += ' '
|
||||
|
@ -138,6 +114,6 @@ pub fn print_scope_vars(sc &Scope, level int) {
|
|||
println('$indent * $var.name - $var.typ')
|
||||
}
|
||||
for child in sc.children {
|
||||
print_scope_vars(child, level+1)
|
||||
child.print_vars(level+1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,6 @@ 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)
|
||||
}
|
||||
|
||||
|
@ -58,9 +54,6 @@ 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,19 +14,20 @@ pub struct Checker {
|
|||
table &table.Table
|
||||
mut:
|
||||
file_name string
|
||||
scope ast.Scope
|
||||
scope &ast.Scope
|
||||
resolved []table.Type
|
||||
}
|
||||
|
||||
pub fn new_checker(table &table.Table) Checker {
|
||||
return Checker{
|
||||
table: table
|
||||
scope: 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) check(ast_file ast.File) {
|
||||
c.file_name = ast_file.path
|
||||
c.scope = ast_file.scope
|
||||
c.scope = &ast_file.scope
|
||||
|
||||
for stmt in ast_file.stmts {
|
||||
c.stmt(stmt)
|
||||
|
@ -268,10 +269,9 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
|||
}
|
||||
}
|
||||
ast.VarDecl {
|
||||
println('VARDECL')
|
||||
typ := c.expr(it.expr)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
//println('var $it.name - $typ - $it.typ')
|
||||
// typ_sym := c.table.get_type_symbol(typ)
|
||||
//println('var $it.name - $typ - $it.typ - $typ_sym.name')
|
||||
//if it.typ == 0 {
|
||||
// it.typ = typ
|
||||
//}
|
||||
|
@ -345,57 +345,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
|||
return c.array_init(mut it)
|
||||
}
|
||||
ast.Ident {
|
||||
//println('IDENT: $it.name - $it.pos.pos')
|
||||
if it.kind == .variable {
|
||||
//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
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle indents with unresolved types during the parsing step
|
||||
// (declared after first usage)
|
||||
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
|
||||
return c.ident(mut it)
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
return table.bool_type
|
||||
|
@ -420,6 +370,76 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
|||
return table.void_type
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
|
||||
//println('IDENT: $it.name - $it.pos.pos')
|
||||
if ident.kind == .variable {
|
||||
//println('===========================')
|
||||
//c.scope.print_vars(0)
|
||||
//println('===========================')
|
||||
info := ident.info as ast.IdentVar
|
||||
if info.typ != 0 {
|
||||
return info.typ
|
||||
}
|
||||
start_scope := c.scope.innermost(ident.pos.pos) or { c.scope }
|
||||
mut found := true
|
||||
mut var_scope, mut var := start_scope.find_scope_and_var(ident.name) or {
|
||||
found = false
|
||||
c.error('not found: $ident.name - POS: $ident.pos.pos', ident.pos)
|
||||
panic('')
|
||||
}
|
||||
if found {
|
||||
// update the variable
|
||||
// we need to do this here instead of var_decl since some
|
||||
// vars are registered manually for things like for loops etc
|
||||
// NOTE: or consider making those declerations part of those ast nodes
|
||||
mut typ := var.typ
|
||||
// set var type on first use
|
||||
if typ == 0 {
|
||||
typ = c.expr(var.expr)
|
||||
var.typ = typ
|
||||
var_scope.override_var(var)
|
||||
}
|
||||
// update ident
|
||||
ident.kind = .variable
|
||||
ident.info = ast.IdentVar{
|
||||
typ: typ
|
||||
}
|
||||
return typ
|
||||
}
|
||||
}
|
||||
// second use, already resovled in unresovled branch
|
||||
else if ident.kind == .constant {
|
||||
info := ident.info as ast.IdentVar
|
||||
return info.typ
|
||||
}
|
||||
// second use, already resovled in unresovled branch
|
||||
else if ident.kind == .function {
|
||||
info := ident.info as ast.IdentFunc
|
||||
return info.return_type
|
||||
}
|
||||
// Handle indents with unresolved types during the parsing step
|
||||
// (declared after first usage)
|
||||
else if ident.kind == .unresolved {
|
||||
// constant
|
||||
if constant := c.table.find_const(ident.name) {
|
||||
ident.kind = .constant
|
||||
ident.info = ast.IdentVar{
|
||||
typ: constant.typ
|
||||
}
|
||||
return constant.typ
|
||||
}
|
||||
// Function object (not a call), e.g. `onclick(my_click)`
|
||||
if func := c.table.find_fn(ident.name) {
|
||||
ident.kind = .function
|
||||
ident.info = ast.IdentFunc{
|
||||
return_type: func.return_type
|
||||
}
|
||||
return func.return_type
|
||||
}
|
||||
}
|
||||
return table.void_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 {
|
||||
|
|
|
@ -428,9 +428,7 @@ pub fn (p &Parser) warn(s string) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) parse_ident(is_c bool) (ast.Ident,table.Type) {
|
||||
mut node := ast.Ident{}
|
||||
mut typ := table.void_type
|
||||
pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
|
||||
// p.warn('name ')
|
||||
// left := p.parse_ident()
|
||||
name := p.check_name()
|
||||
|
@ -450,49 +448,13 @@ pub fn (p mut Parser) parse_ident(is_c bool) (ast.Ident,table.Type) {
|
|||
// println('#### IDENT: $var.name: $var.typ.typ.name - $var.typ.idx')
|
||||
ident.kind = .variable
|
||||
ident.info = ast.IdentVar{}
|
||||
// typ: typ
|
||||
// name: ident.name
|
||||
// expr: p.expr(0)// var.expr
|
||||
// }
|
||||
return ident,typ
|
||||
return ident
|
||||
}
|
||||
else {
|
||||
if is_c {
|
||||
typ = table.int_type
|
||||
ident.info = ast.IdentVar{
|
||||
typ: typ
|
||||
// name: ident.name
|
||||
|
||||
}
|
||||
return ident,typ
|
||||
}
|
||||
// const
|
||||
if c := p.table.find_const(name) {
|
||||
typ = c.typ
|
||||
ident.kind = .constant
|
||||
ident.info = ast.IdentVar{
|
||||
typ: typ
|
||||
// name: ident.name
|
||||
|
||||
}
|
||||
node = ident
|
||||
}else{
|
||||
// Function object (not a call), e.g. `onclick(my_click)`
|
||||
p.table.find_fn(name) or {
|
||||
// ident.info = ast.IdentVar
|
||||
node = ast.Ident{
|
||||
kind: .blank_ident
|
||||
name: name
|
||||
// pos: p.tok.position()
|
||||
|
||||
}
|
||||
return node,typ
|
||||
// p.error('parse_ident: unknown identifier `$name`')
|
||||
}
|
||||
// p.next()
|
||||
}
|
||||
// handle consts/fns in checker
|
||||
ident.kind = .unresolved
|
||||
return ident
|
||||
}
|
||||
return node,typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) struct_init() (ast.Expr,table.Type) {
|
||||
|
@ -544,7 +506,7 @@ fn (p mut Parser) struct_init() (ast.Expr,table.Type) {
|
|||
|
||||
pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||
mut node := ast.Expr{}
|
||||
mut typ := table.void_type
|
||||
typ := table.void_type
|
||||
// mut typ := table.unresolved_type
|
||||
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
|
||||
if is_c {
|
||||
|
@ -598,7 +560,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
|||
}
|
||||
else {
|
||||
mut ident := ast.Ident{}
|
||||
ident,typ = p.parse_ident(is_c)
|
||||
ident = p.parse_ident(is_c)
|
||||
node = ident
|
||||
}
|
||||
return node,typ
|
||||
|
@ -1400,7 +1362,7 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
|
|||
// TODO: multiple return & multiple assign
|
||||
mut idents := []ast.Ident
|
||||
for {
|
||||
ident,_ := p.parse_ident(false)
|
||||
ident := p.parse_ident(false)
|
||||
idents << ident
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
|
|
|
@ -98,8 +98,6 @@ fn test_one() {
|
|||
}
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue