mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v2: move more type handling to checker + some clean up
This commit is contained in:
parent
41808f80fd
commit
d7f74ecf52
@ -199,23 +199,27 @@ pub:
|
|||||||
imports []Import
|
imports []Import
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
scope Scope
|
scope Scope
|
||||||
unresolved []Expr
|
}
|
||||||
|
|
||||||
|
pub struct IdentFunc {
|
||||||
|
pub mut:
|
||||||
|
return_type table.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IdentVar {
|
pub struct IdentVar {
|
||||||
pub mut:
|
pub mut:
|
||||||
typ table.Type
|
typ table.Type
|
||||||
is_mut bool
|
is_mut bool
|
||||||
// name string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type IdentInfo = IdentVar
|
type IdentInfo = IdentFunc | IdentVar
|
||||||
|
|
||||||
pub enum IdentKind {
|
pub enum IdentKind {
|
||||||
|
unresolved
|
||||||
blank_ident
|
blank_ident
|
||||||
variable
|
variable
|
||||||
constant
|
constant
|
||||||
func
|
function
|
||||||
}
|
}
|
||||||
|
|
||||||
// A single identifier
|
// 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) {
|
pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,VarDecl) {
|
||||||
if name in s.vars {
|
if name in s.vars {
|
||||||
return s,s.vars[name]
|
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 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) ?VarDecl {
|
||||||
//pub fn (s &Scope) find_var(name string) ?table.Var {
|
|
||||||
if name in s.vars {
|
if name in s.vars {
|
||||||
return s.vars[name]
|
return s.vars[name]
|
||||||
}
|
}
|
||||||
@ -44,39 +41,9 @@ pub fn (s &Scope) find_var(name string) ?VarDecl {
|
|||||||
return sc.vars[name]
|
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
|
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) {
|
pub fn (s mut Scope) register_var(var VarDecl) {
|
||||||
if x := s.find_var(var.name) {
|
if x := s.find_var(var.name) {
|
||||||
println('existing 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
|
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 {
|
pub fn (s &Scope) innermost(pos int) ?&Scope {
|
||||||
if s.contains(pos) {
|
if s.contains(pos) {
|
||||||
/*
|
|
||||||
for s1 in s.children {
|
|
||||||
if s1.contains(pos) {
|
|
||||||
return s1.innermost(pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
*/
|
|
||||||
// binary search
|
// binary search
|
||||||
mut first := 0
|
mut first := 0
|
||||||
mut last := s.children.len-1
|
mut last := s.children.len-1
|
||||||
@ -118,17 +82,29 @@ pub fn (s &Scope) innermost(pos int) ?&Scope {
|
|||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
return s
|
return none
|
||||||
//return error('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]
|
[inline]
|
||||||
fn (s &Scope) contains(pos int) bool {
|
fn (s &Scope) contains(pos int) bool {
|
||||||
return pos > s.start_pos && pos < s.end_pos
|
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 := ''
|
mut indent := ''
|
||||||
for _ in 0..level*4 {
|
for _ in 0..level*4 {
|
||||||
indent += ' '
|
indent += ' '
|
||||||
@ -138,6 +114,6 @@ pub fn print_scope_vars(sc &Scope, level int) {
|
|||||||
println('$indent * $var.name - $var.typ')
|
println('$indent * $var.name - $var.typ')
|
||||||
}
|
}
|
||||||
for child in sc.children {
|
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.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,9 +54,6 @@ 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')
|
||||||
|
@ -14,19 +14,20 @@ pub struct Checker {
|
|||||||
table &table.Table
|
table &table.Table
|
||||||
mut:
|
mut:
|
||||||
file_name string
|
file_name string
|
||||||
scope ast.Scope
|
scope &ast.Scope
|
||||||
resolved []table.Type
|
resolved []table.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_checker(table &table.Table) Checker {
|
pub fn new_checker(table &table.Table) Checker {
|
||||||
return Checker{
|
return Checker{
|
||||||
table: table
|
table: table
|
||||||
|
scope: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
c.scope = ast_file.scope
|
c.scope = &ast_file.scope
|
||||||
|
|
||||||
for stmt in ast_file.stmts {
|
for stmt in ast_file.stmts {
|
||||||
c.stmt(stmt)
|
c.stmt(stmt)
|
||||||
@ -268,10 +269,9 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.VarDecl {
|
ast.VarDecl {
|
||||||
println('VARDECL')
|
|
||||||
typ := c.expr(it.expr)
|
typ := c.expr(it.expr)
|
||||||
typ_sym := c.table.get_type_symbol(typ)
|
// typ_sym := c.table.get_type_symbol(typ)
|
||||||
//println('var $it.name - $typ - $it.typ')
|
//println('var $it.name - $typ - $it.typ - $typ_sym.name')
|
||||||
//if it.typ == 0 {
|
//if it.typ == 0 {
|
||||||
// it.typ = typ
|
// it.typ = typ
|
||||||
//}
|
//}
|
||||||
@ -345,57 +345,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
|||||||
return c.array_init(mut it)
|
return c.array_init(mut it)
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
//println('IDENT: $it.name - $it.pos.pos')
|
return c.ident(mut it)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
return table.bool_type
|
return table.bool_type
|
||||||
@ -420,6 +370,76 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
|
|||||||
return table.void_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 {
|
pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type {
|
||||||
t := c.expr(node.cond)
|
t := c.expr(node.cond)
|
||||||
for i, block in node.blocks {
|
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) {
|
pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
|
||||||
mut node := ast.Ident{}
|
|
||||||
mut typ := table.void_type
|
|
||||||
// p.warn('name ')
|
// p.warn('name ')
|
||||||
// left := p.parse_ident()
|
// left := p.parse_ident()
|
||||||
name := p.check_name()
|
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')
|
// 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
|
return ident
|
||||||
// name: ident.name
|
|
||||||
// expr: p.expr(0)// var.expr
|
|
||||||
// }
|
|
||||||
return ident,typ
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if is_c {
|
// handle consts/fns in checker
|
||||||
typ = table.int_type
|
ident.kind = .unresolved
|
||||||
ident.info = ast.IdentVar{
|
return ident
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node,typ
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) struct_init() (ast.Expr,table.Type) {
|
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) {
|
pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||||
mut node := ast.Expr{}
|
mut node := ast.Expr{}
|
||||||
mut typ := table.void_type
|
typ := table.void_type
|
||||||
// mut typ := table.unresolved_type
|
// mut typ := table.unresolved_type
|
||||||
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
|
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
|
||||||
if is_c {
|
if is_c {
|
||||||
@ -598,7 +560,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mut ident := ast.Ident{}
|
mut ident := ast.Ident{}
|
||||||
ident,typ = p.parse_ident(is_c)
|
ident = p.parse_ident(is_c)
|
||||||
node = ident
|
node = ident
|
||||||
}
|
}
|
||||||
return node,typ
|
return node,typ
|
||||||
@ -1400,7 +1362,7 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
|
|||||||
// TODO: multiple return & multiple assign
|
// TODO: multiple return & multiple assign
|
||||||
mut idents := []ast.Ident
|
mut idents := []ast.Ident
|
||||||
for {
|
for {
|
||||||
ident,_ := p.parse_ident(false)
|
ident := p.parse_ident(false)
|
||||||
idents << ident
|
idents << ident
|
||||||
if p.tok.kind == .comma {
|
if p.tok.kind == .comma {
|
||||||
p.check(.comma)
|
p.check(.comma)
|
||||||
|
@ -98,8 +98,6 @@ fn test_one() {
|
|||||||
}
|
}
|
||||||
mut checker := checker.new_checker(table)
|
mut checker := checker.new_checker(table)
|
||||||
checker.check(program)
|
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)
|
println(res)
|
||||||
ok := expected == res
|
ok := expected == res
|
||||||
|
Loading…
Reference in New Issue
Block a user