ast: const impl & global scope & objects

pull/4224/head
joe-conigliaro 2020-04-04 14:14:40 +11:00
parent bb5ed66bb4
commit bf59828897
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
13 changed files with 295 additions and 316 deletions

View File

@ -6,6 +6,7 @@ module main
import ( import (
os os
os.cmdline os.cmdline
v.ast
v.pref v.pref
v.fmt v.fmt
v.util v.util
@ -160,7 +161,7 @@ fn (foptions &FormatOptions) format_file(file string) {
eprintln('vfmt2 running fmt.fmt over file: $file') eprintln('vfmt2 running fmt.fmt over file: $file')
} }
table := table.new_table() table := table.new_table()
file_ast := parser.parse_file(file, table, .parse_comments, prefs) file_ast := parser.parse_file(file, table, .parse_comments, prefs, &ast.Scope{parent: 0})
formatted_content := fmt.fmt(file_ast, table) formatted_content := fmt.fmt(file_ast, table)
file_name := os.file_name(file) file_name := os.file_name(file)
vfmt_output_path := os.join_path(os.temp_dir(), 'vfmt_' + file_name) vfmt_output_path := os.join_path(os.temp_dir(), 'vfmt_' + file_name)

View File

@ -20,6 +20,9 @@ pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt |
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl
pub type ScopeObject = ConstField | GlobalDecl | Var
// pub type Type = StructType | ArrayType // pub type Type = StructType | ArrayType
// pub struct StructType { // pub struct StructType {
// fields []Field // fields []Field
@ -110,12 +113,21 @@ mut:
// typ2 Type // typ2 Type
} }
pub struct ConstField {
pub:
name string
expr Expr
is_pub bool
pos token.Position
mut:
typ table.Type
}
pub struct ConstDecl { pub struct ConstDecl {
pub: pub:
pos token.Position fields []ConstField
fields []Field
exprs []Expr
is_pub bool is_pub bool
pos token.Position
} }
pub struct StructDecl { pub struct StructDecl {
@ -184,6 +196,7 @@ pub:
pos token.Position pos token.Position
left Expr // `user` in `user.register()` left Expr // `user` in `user.register()`
is_method bool is_method bool
mod string
mut: mut:
name string name string
args []CallArg args []CallArg
@ -253,6 +266,8 @@ pub:
imports []Import imports []Import
stmts []Stmt stmts []Stmt
scope &Scope scope &Scope
// TODO: consider parent instead of field
global_scope &Scope
} }
pub struct IdentFn { pub struct IdentFn {
@ -275,6 +290,7 @@ pub enum IdentKind {
blank_ident blank_ident
variable variable
constant constant
global
function function
} }
@ -284,6 +300,7 @@ pub:
value string value string
is_c bool is_c bool
tok_kind token.Kind tok_kind token.Kind
mod string
pos token.Position pos token.Position
mut: mut:
name string name string

View File

@ -11,7 +11,7 @@ mut:
children []&Scope children []&Scope
start_pos int start_pos int
end_pos int end_pos int
vars map[string]Var objects map[string]ScopeObject
} }
pub fn new_scope(parent &Scope, start_pos int) &Scope { pub fn new_scope(parent &Scope, start_pos int) &Scope {
@ -21,25 +21,47 @@ pub fn new_scope(parent &Scope, start_pos int) &Scope {
} }
} }
pub fn (s &Scope) find_scope_and_var(name string) ?(&Scope,Var) { pub fn (s &Scope) find_with_scope(name string) ?(ScopeObject,&Scope) {
if name in s.vars { mut sc := s
return s,s.vars[name] for {
if name in sc.objects {
return sc.objects[name],sc
} }
for sc := s; !isnil(sc.parent); sc = sc.parent { if isnil(sc.parent) {
if name in sc.vars { break
return sc,sc.vars[name] }
sc = sc.parent
}
return none
}
pub fn (s &Scope) find(name string) ?ScopeObject {
for sc := s; ; sc = sc.parent {
if name in sc.objects {
return sc.objects[name]
}
if isnil(sc.parent) {
break
} }
} }
return none return none
} }
pub fn (s &Scope) find_var(name string) ?Var { pub fn (s &Scope) is_known(name string) bool {
if name in s.vars { if _ := s.find(name) {
return s.vars[name] return true
} }
for sc := s; !isnil(sc.parent); sc = sc.parent { return false
if name in sc.vars { }
return sc.vars[name]
pub fn (s &Scope) find_var(name string) ?Var {
if obj := s.find(name) {
match obj {
Var {
return *it
}
else {}
} }
} }
return none return none
@ -52,28 +74,24 @@ pub fn (s &Scope) known_var(name string) bool {
return false return false
} }
pub fn (s mut Scope) register_var(var Var) {
if x := s.find_var(var.name) {
// println('existing var: $var.name')
return
}
s.vars[var.name] = var
}
pub fn (s mut Scope) override_var(var Var) {
s.vars[var.name] = var
}
pub fn (s mut Scope) update_var_type(name string, typ table.Type) { pub fn (s mut Scope) update_var_type(name string, typ table.Type) {
mut x := s.vars[name] match mut s.objects[name] {
// dont do an insert for no reason Var {
if x.typ == typ { if it.typ == typ {
return return
} }
x.typ = typ it.typ = typ
s.vars[name] = x }
// TODO else {}
// s.vars[name].typ = typ }
}
pub fn (s mut Scope) register(name string, obj ScopeObject) {
if x := s.find(name) {
// println('existing obect: $name')
return
}
s.objects[name] = obj
} }
pub fn (s &Scope) outermost() &Scope { pub fn (s &Scope) outermost() &Scope {
@ -115,42 +133,37 @@ pub fn (s &Scope) innermost(pos int) &Scope {
return s return s
} }
/*
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 (sc &Scope) show(level int) string { pub fn (sc &Scope) show(depth int, max_depth int) string {
mut out := '' mut out := ''
mut indent := '' mut indent := ''
for _ in 0 .. level * 4 { for _ in 0 .. depth * 4 {
indent += ' ' indent += ' '
} }
out += '$indent# $sc.start_pos - $sc.end_pos\n' out += '$indent# $sc.start_pos - $sc.end_pos\n'
for _, var in sc.vars { for _, obj in sc.objects {
out += '$indent * $var.name - $var.typ\n' match obj {
ConstField {
out += '$indent * const: $it.name - $it.typ\n'
}
Var {
out += '$indent * var: $it.name - $it.typ\n'
}
else {}
}
}
if max_depth == 0 || depth < max_depth-1 {
for i, _ in sc.children {
out += sc.children[i].show(depth + 1, max_depth)
} }
for child in sc.children {
out += child.show(level + 1)
} }
return out return out
} }
pub fn (sc &Scope) str() string { pub fn (sc &Scope) str() string {
return sc.show(0) return sc.show(0, 0)
} }

View File

@ -25,6 +25,7 @@ pub:
mut: mut:
module_search_paths []string module_search_paths []string
parsed_files []ast.File parsed_files []ast.File
global_scope &ast.Scope
} }
pub fn new_builder(pref &pref.Preferences) Builder { pub fn new_builder(pref &pref.Preferences) Builder {
@ -34,12 +35,15 @@ pub fn new_builder(pref &pref.Preferences) Builder {
pref: pref pref: pref
table: table table: table
checker: checker.new_checker(table, pref) checker: checker.new_checker(table, pref)
global_scope: &ast.Scope{
parent: 0
}
} }
} }
pub fn (b mut Builder) gen_c(v_files []string) string { pub fn (b mut Builder) gen_c(v_files []string) string {
t0 := time.ticks() t0 := time.ticks()
b.parsed_files = parser.parse_files(v_files, b.table, b.pref) b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
b.parse_imports() b.parse_imports()
t1 := time.ticks() t1 := time.ticks()
parse_time := t1 - t0 parse_time := t1 - t0
@ -74,7 +78,7 @@ pub fn (b mut Builder) build_c(v_files []string, out_file string) {
pub fn (b mut Builder) build_x64(v_files []string, out_file string) { pub fn (b mut Builder) build_x64(v_files []string, out_file string) {
t0 := time.ticks() t0 := time.ticks()
b.parsed_files = parser.parse_files(v_files, b.table, b.pref) b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
b.parse_imports() b.parse_imports()
t1 := time.ticks() t1 := time.ticks()
parse_time := t1 - t0 parse_time := t1 - t0
@ -112,7 +116,7 @@ pub fn (b mut Builder) parse_imports() {
panic('cannot import module "$mod" (no .v files in "$import_path")') panic('cannot import module "$mod" (no .v files in "$import_path")')
} }
// Add all imports referenced by these libs // Add all imports referenced by these libs
parsed_files := parser.parse_files(v_files, b.table, b.pref) parsed_files := parser.parse_files(v_files, b.table, b.pref, b.global_scope)
for file in parsed_files { for file in parsed_files {
if file.mod.name != mod { if file.mod.name != mod {
// v.parsers[pidx].error_with_token_index('bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1 // v.parsers[pidx].error_with_token_index('bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1

View File

@ -5,6 +5,7 @@ module checker
import ( import (
v.ast v.ast
v.depgraph
v.table v.table
v.token v.token
v.pref v.pref
@ -25,6 +26,7 @@ mut:
error_lines []int // to avoid printing multiple errors for the same line error_lines []int // to avoid printing multiple errors for the same line
expected_type table.Type expected_type table.Type
fn_return_type table.Type // current function's return type fn_return_type table.Type // current function's return type
const_deps []string
// fn_decl ast.FnDecl // fn_decl ast.FnDecl
pref &pref.Preferences // Preferences shared from V struct pref &pref.Preferences // Preferences shared from V struct
} }
@ -41,13 +43,6 @@ pub fn (c mut Checker) check(ast_file ast.File) {
for stmt in ast_file.stmts { for stmt in ast_file.stmts {
c.stmt(stmt) c.stmt(stmt)
} }
/*
println('all types:')
for t in c.table.types {
println(t.name + ' - ' + t.kind.str())
}
*/
} }
pub fn (c mut Checker) check2(ast_file ast.File) []string { pub fn (c mut Checker) check2(ast_file ast.File) []string {
@ -59,18 +54,6 @@ pub fn (c mut Checker) check2(ast_file ast.File) []string {
} }
pub fn (c mut Checker) check_files(ast_files []ast.File) { pub fn (c mut Checker) check_files(ast_files []ast.File) {
// TODO: temp fix, impl proper solution
for file in ast_files {
c.file = file
for stmt in file.stmts {
match mut stmt {
ast.ConstDecl {
c.stmt(*it)
}
else {}
}
}
}
for file in ast_files { for file in ast_files {
c.check(file) c.check(file)
} }
@ -294,8 +277,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
mut f := table.Fn{} mut f := table.Fn{}
mut found := false mut found := false
// try prefix with current module as it would have never gotten prefixed // try prefix with current module as it would have never gotten prefixed
if !fn_name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { if !fn_name.contains('.') && !(call_expr.mod in ['builtin', 'main']) {
name_prefixed := '${c.file.mod.name}.$fn_name' name_prefixed := '${call_expr.mod}.$fn_name'
if f1 := c.table.find_fn(name_prefixed) { if f1 := c.table.find_fn(name_prefixed) {
call_expr.name = name_prefixed call_expr.name = name_prefixed
found = true found = true
@ -435,7 +418,7 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
return return
} }
if expected_types.len > 0 && expected_types.len != got_types.len { if expected_types.len > 0 && expected_types.len != got_types.len {
// c.error('wrong number of return arguments:\n\texpected: $expected_types.str()\n\tgot: $got_types.str()', return_stmt.pos) // c.error('wrong number of return arguments:\n\texpected: $expected_table.str()\n\tgot: $got_types.str()', return_stmt.pos)
c.error('wrong number of return arguments', return_stmt.pos) c.error('wrong number of return arguments', return_stmt.pos)
} }
for i, exp_typ in expected_types { for i, exp_typ in expected_types {
@ -589,66 +572,45 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.stmts(it.stmts) c.stmts(it.stmts)
} }
ast.ConstDecl { ast.ConstDecl {
mut unresolved_num:= 0 // number of type-unresolved consts mut field_names := []string
mut ordered_exprs := []ast.Expr mut field_order := []int
mut ordered_fields := []ast.Field for i, field in it.fields {
for i, expr in it.exprs { field_names << field.name
mut field := it.fields[i] field_order << i
typ := c.expr(expr)
if typ == table.void_type {
unresolved_num++
} }
else { // succeed in resolving type mut needs_order := false
c.table.register_const(table.Var{ mut done_fields := []int
name: field.name for i, field in it.fields {
typ: typ mut set_const := false
}) if c.const_deps.len == 0 {
field.typ = typ set_const = true
it.fields[i] = field
ordered_exprs << expr
ordered_fields << field
if unresolved_num == 0 {
continue
} }
for j, _expr in it.exprs[0..i]{ c.const_deps << field.name
mut _field := it.fields[j] typ := c.expr(field.expr)
_typ := c.expr(_expr) it.fields[i].typ = typ
if _field.typ == 0 && _typ != table.void_type { if set_const {
// succeed in resolving type for cd in c.const_deps {
c.table.register_const(table.Var{ for j, f in it.fields {
name: _field.name if j != i && cd in field_names && cd == f.name && !(j in done_fields) {
typ: _typ needs_order = true
}) x := field_order[j]
unresolved_num-- field_order[j] = field_order[i]
_field.typ = _typ field_order[i] = x
it.fields[j] = _field break
ordered_exprs << _expr
ordered_fields << _field
} }
} }
} }
} done_fields << i
if unresolved_num != 0 { c.const_deps = []
for i, expr in it.exprs {
typ := c.expr(expr)
if typ == table.void_type {
mut _field := it.fields[i]
if !_field.already_reported {
_field.already_reported = true
it.fields[i] = _field
c.error("$unresolved_num ill-defined const `$_field.name`", _field.pos)
} }
} }
if needs_order {
mut ordered_fields := []ast.ConstField
for order in field_order {
ordered_fields << it.fields[order]
} }
}
for i, field in ordered_fields { // set the fields and exprs as ordered
it.fields[i] = field
it.exprs[i] = ordered_exprs[i]
}
/*
it.exprs = ordered_exprs
it.fields = ordered_fields it.fields = ordered_fields
*/ }
} }
ast.ExprStmt { ast.ExprStmt {
c.expr(it.expr) c.expr(it.expr)
@ -876,34 +838,42 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
} }
pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
// println('IDENT: $ident.name - $ident.pos.pos') // TODO: move this
if c.const_deps.len > 0 {
mut name := ident.name
if !name.contains('.') && !(ident.mod in ['builtin', 'main']) {
name = '${ident.mod}.$ident.name'
}
if name in c.const_deps {
c.error('cycle in constants', ident.pos)
return table.void_type
}
c.const_deps << name
}
if ident.kind == .blank_ident {
return table.void_type
}
// second use
if ident.kind == .variable { if ident.kind == .variable {
// println('===========================')
// c.scope.print_vars(0)
// println('===========================')
info := ident.info as ast.IdentVar info := ident.info as ast.IdentVar
if info.typ != 0 {
return info.typ return info.typ
} }
start_scope := c.file.scope.innermost(ident.pos.pos) else if ident.kind == .constant {
mut found := true info := ident.info as ast.IdentVar
mut var_scope,var := start_scope.find_scope_and_var(ident.name) or { return info.typ
found = false
c.error('not found: $ident.name - POS: $ident.pos.pos', ident.pos)
panic('')
} }
if found { else if ident.kind == .function {
// update the variable info := ident.info as ast.IdentFn
// we need to do this here instead of var_decl since some return info.typ
// vars are registered manually for things like for loops etc }
// NOTE: or consider making those declarations part of those ast nodes // first use
else if ident.kind == .unresolved {
start_scope := c.file.scope.innermost(ident.pos.pos)
if var := start_scope.find_var(ident.name) {
mut typ := var.typ mut typ := var.typ
// set var type on first use
if typ == 0 { if typ == 0 {
typ = c.expr(var.expr) typ = c.expr(var.expr)
var_scope.update_var_type(var.name, typ)
} }
// update ident
ident.kind = .variable ident.kind = .variable
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: typ typ: typ
@ -915,33 +885,35 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
} }
return typ return typ
} }
}
// second use, already resovled in unresolved 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.IdentFn
return info.typ
}
// Handle indents with unresolved types during the parsing step
// (declared after first usage)
else if ident.kind == .unresolved {
// prepend mod to look for fn call or const // prepend mod to look for fn call or const
mut name := ident.name mut name := ident.name
if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { if !name.contains('.') && !(ident.mod in ['builtin', 'main']) {
name = '${c.file.mod.name}.$ident.name' name = '${ident.mod}.$ident.name'
}
if obj := c.file.global_scope.find(name) {
match obj {
ast.GlobalDecl {
ident.kind = .global
ident.info = ast.IdentVar{
typ: it.typ
}
return it.typ
}
ast.ConstField {
mut typ := it.typ
if typ == 0 {
typ = c.expr(it.expr)
} }
// constant
if constant := c.table.find_const(name) {
ident.name = name ident.name = name
ident.kind = .constant ident.kind = .constant
ident.info = ast.IdentVar{ ident.info = ast.IdentVar{
typ: constant.typ typ: typ
}
it.typ = typ
return typ
}
else {}
} }
return constant.typ
} }
// Function object (not a call), e.g. `onclick(my_click)` // Function object (not a call), e.g. `onclick(my_click)`
if func := c.table.find_fn(name) { if func := c.table.find_fn(name) {

View File

@ -45,7 +45,7 @@ pub fn doc(mod string, table &table.Table) string {
if file.ends_with('_test.v') || file.ends_with('_windows.v') || file.ends_with('_macos.v') { if file.ends_with('_test.v') || file.ends_with('_windows.v') || file.ends_with('_macos.v') {
continue continue
} }
file_ast := parser.parse_file(os.join_path(path,file), table, .skip_comments, &pref.Preferences{}) file_ast := parser.parse_file(os.join_path(path,file), table, .skip_comments, &pref.Preferences{}, &ast.Scope{parent: 0})
d.stmts << file_ast.stmts d.stmts << file_ast.stmts
} }
if d.stmts.len == 0 { if d.stmts.len == 0 {

View File

@ -142,7 +142,7 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
for i, field in it.fields { for i, field in it.fields {
name := field.name.after('.') name := field.name.after('.')
f.write('$name = ') f.write('$name = ')
f.expr(it.exprs[i]) f.expr(field.expr)
f.writeln('') f.writeln('')
} }
f.indent-- f.indent--

View File

@ -2,6 +2,7 @@ import (
os os
term term
benchmark benchmark
v.ast
v.fmt v.fmt
v.parser v.parser
v.table v.table
@ -46,7 +47,7 @@ fn test_fmt() {
continue continue
} }
table := table.new_table() table := table.new_table()
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}) file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{parent: 0})
result_ocontent := fmt.fmt(file_ast, table) result_ocontent := fmt.fmt(file_ast, table)
if expected_ocontent != result_ocontent { if expected_ocontent != result_ocontent {
fmt_bench.fail() fmt_bench.fail()

View File

@ -762,7 +762,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if name.starts_with('_op_') { if name.starts_with('_op_') {
name = op_to_fn_name(name) name = op_to_fn_name(name)
} }
// type_name := g.table.type_to_str(it.return_type) // type_name := g.table.Type_to_str(it.return_type)
type_name := g.typ(it.return_type) type_name := g.typ(it.return_type)
g.write('$type_name ${name}(') g.write('$type_name ${name}(')
g.definitions.write('$type_name ${name}(') g.definitions.write('$type_name ${name}(')
@ -834,7 +834,9 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
fn (g mut Gen) free_scope_vars(pos int) { fn (g mut Gen) free_scope_vars(pos int) {
scope := g.file.scope.innermost(pos) scope := g.file.scope.innermost(pos)
for _, var in scope.vars { for _, obj in scope.objects {
match obj {
ast.Var {
// println('//////') // println('//////')
// println(var.name) // println(var.name)
// println(var.typ) // println(var.typ)
@ -842,6 +844,7 @@ fn (g mut Gen) free_scope_vars(pos int) {
// // TODO why 0? // // TODO why 0?
// continue // continue
// } // }
var := *it
sym := g.table.get_type_symbol(var.typ) sym := g.table.get_type_symbol(var.typ)
if sym.kind == .array && !table.type_is_optional(var.typ) { if sym.kind == .array && !table.type_is_optional(var.typ) {
g.writeln('array_free($var.name); // autofreed') g.writeln('array_free($var.name); // autofreed')
@ -864,6 +867,9 @@ fn (g mut Gen) free_scope_vars(pos int) {
g.writeln('string_free($var.name); // autofreed') g.writeln('string_free($var.name); // autofreed')
} }
} }
else {}
}
}
} }
fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) { fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) {
@ -995,7 +1001,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.expr_with_cast(it.expr, it.expr_type, it.typ) g.expr_with_cast(it.expr, it.expr_type, it.typ)
} }
else { else {
// styp := g.table.type_to_str(it.typ) // styp := g.table.Type_to_str(it.typ)
styp := g.typ(it.typ) styp := g.typ(it.typ)
// g.write('($styp)(') // g.write('($styp)(')
g.write('(($styp)(') g.write('(($styp)(')
@ -1837,13 +1843,12 @@ fn (g mut Gen) return_statement(node ast.Return) {
fn (g mut Gen) const_decl(node ast.ConstDecl) { fn (g mut Gen) const_decl(node ast.ConstDecl) {
for i, field in node.fields { for i, field in node.fields {
name := c_name(field.name) name := c_name(field.name)
expr := node.exprs[i]
// TODO hack. Cut the generated value and paste it into definitions. // TODO hack. Cut the generated value and paste it into definitions.
pos := g.out.len pos := g.out.len
g.expr(expr) g.expr(field.expr)
val := g.out.after(pos) val := g.out.after(pos)
g.out.go_back(val.len) g.out.go_back(val.len)
match expr { match field.expr {
ast.CharLiteral, ast.IntegerLiteral { ast.CharLiteral, ast.IntegerLiteral {
// Simple expressions should use a #define // Simple expressions should use a #define
// so that we don't pollute the binary with unnecessary global vars // so that we don't pollute the binary with unnecessary global vars
@ -2155,15 +2160,15 @@ int typ;
} }
// sort structs by dependant fields // sort structs by dependant fields
fn (g &Gen) sort_structs(types []table.TypeSymbol) []table.TypeSymbol { fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
mut dep_graph := depgraph.new_dep_graph() mut dep_graph := depgraph.new_dep_graph()
// types name list // types name list
mut type_names := []string mut type_names := []string
for typ in types { for typ in typesa {
type_names << typ.name type_names << typ.name
} }
// loop over types // loop over types
for t in types { for t in typesa {
// create list of deps // create list of deps
mut field_deps := []string mut field_deps := []string
match t.info { match t.info {

View File

@ -18,7 +18,7 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr {
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.next() p.next()
p.open_scope() p.open_scope()
p.scope.register_var(ast.Var{ p.scope.register('err', ast.Var{
name: 'err' name: 'err'
typ: table.string_type typ: table.string_type
}) })
@ -29,7 +29,7 @@ pub fn (p mut Parser) call_expr(is_c bool, mod string) ast.CallExpr {
name: fn_name name: fn_name
args: args args: args
// tok: tok // tok: tok
mod: p.mod
pos: tok.position() pos: tok.position()
is_c: is_c is_c: is_c
or_block: ast.OrExpr{ or_block: ast.OrExpr{
@ -118,7 +118,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
args2,is_variadic := p.fn_args() args2,is_variadic := p.fn_args()
args << args2 args << args2
for arg in args { for arg in args {
p.scope.register_var(ast.Var{ p.scope.register(arg.name, ast.Var{
name: arg.name name: arg.name
typ: arg.typ typ: arg.typ
}) })

View File

@ -34,6 +34,7 @@ mut:
attr string attr string
expr_mod string expr_mod string
scope &ast.Scope scope &ast.Scope
global_scope &ast.Scope
imports map[string]string imports map[string]string
ast_imports []ast.Import ast_imports []ast.Import
is_amp bool is_amp bool
@ -50,14 +51,17 @@ pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt {
pref: &pref.Preferences{} pref: &pref.Preferences{}
scope: scope scope: scope
// scope: &ast.Scope{start_pos: 0, parent: 0} // scope: &ast.Scope{start_pos: 0, parent: 0}
global_scope: &ast.Scope{
start_pos: 0
parent: 0
}
} }
p.init_parse_fns() p.init_parse_fns()
p.read_first_token() p.read_first_token()
return p.stmt() return p.stmt()
} }
pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences) ast.File { pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences, global_scope &ast.Scope) ast.File {
// println('parse_file("$path")') // println('parse_file("$path")')
// text := os.read_file(path) or { // text := os.read_file(path) or {
// panic(err) // panic(err)
@ -74,11 +78,11 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
start_pos: 0 start_pos: 0
parent: 0 parent: 0
} }
global_scope: global_scope
// comments_mode: comments_mode // comments_mode: comments_mode
} }
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'
} } } }
@ -110,6 +114,7 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
imports: p.ast_imports imports: p.ast_imports
stmts: stmts stmts: stmts
scope: p.scope scope: p.scope
global_scope: p.global_scope
} }
} }
@ -141,7 +146,7 @@ fn (q mut Queue) run() {
*/ */
pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences) []ast.File { pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, global_scope &ast.Scope) []ast.File {
/* /*
println('\n\n\nparse_files()') println('\n\n\nparse_files()')
println(paths) println(paths)
@ -162,7 +167,7 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences) [
mut files := []ast.File mut files := []ast.File
for path in paths { for path in paths {
// println('parse_files $path') // println('parse_files $path')
files << parse_file(path, table, .skip_comments, pref) files << parse_file(path, table, .skip_comments, pref, global_scope)
} }
return files return files
} }
@ -530,16 +535,9 @@ pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
kind: .unresolved kind: .unresolved
name: name name: name
is_c: is_c is_c: is_c
mod: p.mod
pos: pos pos: pos
} }
// variable
if p.expr_mod.len == 0 {
if var := p.scope.find_var(name) {
ident.kind = .variable
ident.info = ast.IdentVar{}
}
}
// handle consts/fns in checker
return ident return ident
} }
@ -941,7 +939,7 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr {
} }
fn (p mut Parser) filter() { fn (p mut Parser) filter() {
p.scope.register_var(ast.Var{ p.scope.register('it', ast.Var{
name: 'it' name: 'it'
}) })
} }
@ -967,7 +965,7 @@ fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr {
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.next() p.next()
p.open_scope() p.open_scope()
p.scope.register_var(ast.Var{ p.scope.register('err', ast.Var{
name: 'err' name: 'err'
typ: table.string_type typ: table.string_type
}) })
@ -1112,7 +1110,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
p.check(.comma) p.check(.comma)
key_var_name = val_var_name key_var_name = val_var_name
val_var_name = p.check_name() val_var_name = p.check_name()
p.scope.register_var(ast.Var{ p.scope.register(key_var_name, ast.Var{
name: key_var_name name: key_var_name
typ: table.int_type typ: table.int_type
}) })
@ -1129,14 +1127,14 @@ fn (p mut Parser) for_statement() ast.Stmt {
is_range = true is_range = true
p.check(.dotdot) p.check(.dotdot)
high_expr = p.expr(0) high_expr = p.expr(0)
p.scope.register_var(ast.Var{ p.scope.register(val_var_name, ast.Var{
name: val_var_name name: val_var_name
typ: table.int_type typ: table.int_type
}) })
} }
else { else {
// this type will be set in checker // this type will be set in checker
p.scope.register_var(ast.Var{ p.scope.register(val_var_name, ast.Var{
name: val_var_name name: val_var_name
}) })
} }
@ -1197,7 +1195,7 @@ fn (p mut Parser) if_expr() ast.IfExpr {
var_name := p.check_name() var_name := p.check_name()
p.check(.decl_assign) p.check(.decl_assign)
expr := p.expr(0) expr := p.expr(0)
p.scope.register_var(ast.Var{ p.scope.register(var_name, ast.Var{
name: var_name name: var_name
expr: expr expr: expr
}) })
@ -1436,31 +1434,26 @@ fn (p mut Parser) const_decl() ast.ConstDecl {
pos := p.tok.position() pos := p.tok.position()
p.check(.key_const) p.check(.key_const)
p.check(.lpar) p.check(.lpar)
mut fields := []ast.Field mut fields := []ast.ConstField
mut exprs := []ast.Expr
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
name := p.prepend_mod(p.check_name()) name := p.prepend_mod(p.check_name())
// name := p.check_name()
// println('!!const: $name') // println('!!const: $name')
p.check(.assign) p.check(.assign)
expr := p.expr(0) expr := p.expr(0)
fields << ast.Field{ field := ast.ConstField{
name: name name: name
expr: expr
pos: p.tok.position() pos: p.tok.position()
// typ: typ
} }
exprs << expr fields << field
// TODO: once consts are fixed reg here & update in checker p.global_scope.register(field.name, field)
// p.table.register_const(table.Var{
// name: name
// // typ: typ
// })
} }
p.check(.rpar) p.check(.rpar)
return ast.ConstDecl{ return ast.ConstDecl{
pos : pos pos : pos
fields: fields fields: fields
exprs: exprs
is_pub: is_pub is_pub: is_pub
} }
} }
@ -1695,13 +1688,13 @@ fn (p mut Parser) assign_stmt() ast.Stmt {
p.error('redefinition of `$ident.name`') p.error('redefinition of `$ident.name`')
} }
if idents.len == exprs.len { if idents.len == exprs.len {
p.scope.register_var(ast.Var{ p.scope.register(ident.name, ast.Var{
name: ident.name name: ident.name
expr: exprs[i] expr: exprs[i]
}) })
} }
else { else {
p.scope.register_var(ast.Var{ p.scope.register(ident.name, ast.Var{
name: ident.name name: ident.name
}) })
} }
@ -1736,7 +1729,6 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
p.next() p.next()
p.expr(0) p.expr(0)
} }
p.table.register_global(name, typ)
// p.genln(p.table.cgen_name_type_pair(name, typ)) // p.genln(p.table.cgen_name_type_pair(name, typ))
/* /*
mut g := p.table.cgen_name_type_pair(name, typ) mut g := p.table.cgen_name_type_pair(name, typ)
@ -1753,10 +1745,12 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
} }
*/ */
return ast.GlobalDecl{ glob := ast.GlobalDecl{
name: name name: name
typ: typ typ: typ
} }
p.global_scope.register(name, glob)
return glob
} }
fn (p mut Parser) match_expr() ast.MatchExpr { fn (p mut Parser) match_expr() ast.MatchExpr {
@ -1793,7 +1787,7 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
mut expr := ast.Expr{} mut expr := ast.Expr{}
expr = x expr = x
exprs << expr exprs << expr
p.scope.register_var(ast.Var{ p.scope.register('it', ast.Var{
name: 'it' name: 'it'
typ: table.type_to_ptr(typ) typ: table.type_to_ptr(typ)
}) })

View File

@ -13,7 +13,6 @@ pub mut:
type_idxs map[string]int type_idxs map[string]int
// fns Hashmap // fns Hashmap
fns map[string]Fn fns map[string]Fn
consts map[string]Var
imports []string // List of all imports imports []string // List of all imports
modules []string // List of all modules registered by the application modules []string // List of all modules registered by the application
} }
@ -38,8 +37,6 @@ pub struct Var {
pub: pub:
name string name string
is_mut bool is_mut bool
is_const bool
is_global bool
mut: mut:
typ Type typ Type
} }
@ -50,23 +47,6 @@ pub fn new_table() &Table {
return t return t
} }
pub fn (t mut Table) register_const(v Var) {
t.consts[v.name] = v
}
pub fn (t mut Table) register_global(name string, typ Type) {
t.consts[name] = Var{
name: name
typ: typ
is_const: true
is_global: true
// mod: p.mod
// is_mut: true
// idx: -1
}
}
// used to compare fn's & for naming anon fn's // used to compare fn's & for naming anon fn's
pub fn (f &Fn) signature() string { pub fn (f &Fn) signature() string {
mut sig := '' mut sig := ''
@ -95,15 +75,6 @@ pub fn (t &Table) find_fn(name string) ?Fn {
return none return none
} }
pub fn (t &Table) find_const(name string) ?Var {
f := t.consts[name]
if f.name.str != 0 {
// TODO
return f
}
return none
}
pub fn (t mut Table) register_fn(new_fn Fn) { pub fn (t mut Table) register_fn(new_fn Fn) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len') // println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn

View File

@ -1,4 +1,5 @@
pub const ( pub const (
c = a
a = b a = b
c = a + b c = a + b
b = 1 b = 1
@ -13,5 +14,5 @@ struct Foo {
fn test_const() { fn test_const() {
assert a == 1 assert a == 1
assert d == 11 assert d == 11
// assert c == 1 // TODO: This will not build yet assert c == 1
} }