v2: move more type handling to checker + some clean up

pull/3756/head
joe-conigliaro 2020-02-17 22:25:18 +11:00 committed by GitHub
parent 41808f80fd
commit d7f74ecf52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 162 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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