1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

ast: const impl & global scope & objects

This commit is contained in:
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 (
os
os.cmdline
v.ast
v.pref
v.fmt
v.util
@ -160,7 +161,7 @@ fn (foptions &FormatOptions) format_file(file string) {
eprintln('vfmt2 running fmt.fmt over file: $file')
}
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)
file_name := os.file_name(file)
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 |
HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt |
LineComment | MultiLineComment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl
pub type ScopeObject = ConstField | GlobalDecl | Var
// pub type Type = StructType | ArrayType
// pub struct StructType {
// fields []Field
@ -110,12 +113,21 @@ mut:
// typ2 Type
}
pub struct ConstField {
pub:
name string
expr Expr
is_pub bool
pos token.Position
mut:
typ table.Type
}
pub struct ConstDecl {
pub:
pos token.Position
fields []Field
exprs []Expr
fields []ConstField
is_pub bool
pos token.Position
}
pub struct StructDecl {
@ -184,6 +196,7 @@ pub:
pos token.Position
left Expr // `user` in `user.register()`
is_method bool
mod string
mut:
name string
args []CallArg
@ -253,6 +266,8 @@ pub:
imports []Import
stmts []Stmt
scope &Scope
// TODO: consider parent instead of field
global_scope &Scope
}
pub struct IdentFn {
@ -275,6 +290,7 @@ pub enum IdentKind {
blank_ident
variable
constant
global
function
}
@ -284,6 +300,7 @@ pub:
value string
is_c bool
tok_kind token.Kind
mod string
pos token.Position
mut:
name string

View File

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

View File

@ -25,6 +25,7 @@ pub:
mut:
module_search_paths []string
parsed_files []ast.File
global_scope &ast.Scope
}
pub fn new_builder(pref &pref.Preferences) Builder {
@ -34,12 +35,15 @@ pub fn new_builder(pref &pref.Preferences) Builder {
pref: pref
table: table
checker: checker.new_checker(table, pref)
global_scope: &ast.Scope{
parent: 0
}
}
}
pub fn (b mut Builder) gen_c(v_files []string) string {
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()
t1 := time.ticks()
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) {
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()
t1 := time.ticks()
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")')
}
// 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 {
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

View File

@ -5,6 +5,7 @@ module checker
import (
v.ast
v.depgraph
v.table
v.token
v.pref
@ -25,8 +26,9 @@ mut:
error_lines []int // to avoid printing multiple errors for the same line
expected_type table.Type
fn_return_type table.Type // current function's return type
const_deps []string
// fn_decl ast.FnDecl
pref &pref.Preferences // Preferences shared from V struct
pref &pref.Preferences // Preferences shared from V struct
}
pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker {
@ -41,13 +43,6 @@ pub fn (c mut Checker) check(ast_file ast.File) {
for stmt in ast_file.stmts {
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 {
@ -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) {
// 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 {
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 found := false
// try prefix with current module as it would have never gotten prefixed
if !fn_name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) {
name_prefixed := '${c.file.mod.name}.$fn_name'
if !fn_name.contains('.') && !(call_expr.mod in ['builtin', 'main']) {
name_prefixed := '${call_expr.mod}.$fn_name'
if f1 := c.table.find_fn(name_prefixed) {
call_expr.name = name_prefixed
found = true
@ -435,7 +418,7 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
return
}
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)
}
for i, exp_typ in expected_types {
@ -589,66 +572,45 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.stmts(it.stmts)
}
ast.ConstDecl {
mut unresolved_num:= 0 // number of type-unresolved consts
mut ordered_exprs := []ast.Expr
mut ordered_fields := []ast.Field
for i, expr in it.exprs {
mut field := it.fields[i]
typ := c.expr(expr)
if typ == table.void_type {
unresolved_num++
mut field_names := []string
mut field_order := []int
for i, field in it.fields {
field_names << field.name
field_order << i
}
mut needs_order := false
mut done_fields := []int
for i, field in it.fields {
mut set_const := false
if c.const_deps.len == 0 {
set_const = true
}
else { // succeed in resolving type
c.table.register_const(table.Var{
name: field.name
typ: typ
})
field.typ = typ
it.fields[i] = field
ordered_exprs << expr
ordered_fields << field
if unresolved_num == 0 {
continue
}
for j, _expr in it.exprs[0..i]{
mut _field := it.fields[j]
_typ := c.expr(_expr)
if _field.typ == 0 && _typ != table.void_type {
// succeed in resolving type
c.table.register_const(table.Var{
name: _field.name
typ: _typ
})
unresolved_num--
_field.typ = _typ
it.fields[j] = _field
ordered_exprs << _expr
ordered_fields << _field
c.const_deps << field.name
typ := c.expr(field.expr)
it.fields[i].typ = typ
if set_const {
for cd in c.const_deps {
for j, f in it.fields {
if j != i && cd in field_names && cd == f.name && !(j in done_fields) {
needs_order = true
x := field_order[j]
field_order[j] = field_order[i]
field_order[i] = x
break
}
}
}
done_fields << i
c.const_deps = []
}
}
if unresolved_num != 0 {
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]
}
it.fields = ordered_fields
}
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
*/
}
ast.ExprStmt {
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 {
// 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 {
// println('===========================')
// c.scope.print_vars(0)
// println('===========================')
info := ident.info as ast.IdentVar
if info.typ != 0 {
return info.typ
}
return info.typ
}
else if ident.kind == .constant {
info := ident.info as ast.IdentVar
return info.typ
}
else if ident.kind == .function {
info := ident.info as ast.IdentFn
return info.typ
}
// first use
else if ident.kind == .unresolved {
start_scope := c.file.scope.innermost(ident.pos.pos)
mut found := true
mut var_scope,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 declarations part of those ast nodes
if var := start_scope.find_var(ident.name) {
mut typ := var.typ
// set var type on first use
if typ == 0 {
typ = c.expr(var.expr)
var_scope.update_var_type(var.name, typ)
}
// update ident
ident.kind = .variable
ident.info = ast.IdentVar{
typ: typ
@ -915,33 +885,35 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
}
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
mut name := ident.name
if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) {
name = '${c.file.mod.name}.$ident.name'
if !name.contains('.') && !(ident.mod in ['builtin', 'main']) {
name = '${ident.mod}.$ident.name'
}
// constant
if constant := c.table.find_const(name) {
ident.name = name
ident.kind = .constant
ident.info = ast.IdentVar{
typ: constant.typ
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)
}
ident.name = name
ident.kind = .constant
ident.info = ast.IdentVar{
typ: typ
}
it.typ = typ
return typ
}
else {}
}
return constant.typ
}
// Function object (not a call), e.g. `onclick(my_click)`
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') {
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
}
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 {
name := field.name.after('.')
f.write('$name = ')
f.expr(it.exprs[i])
f.expr(field.expr)
f.writeln('')
}
f.indent--

View File

@ -2,6 +2,7 @@ import (
os
term
benchmark
v.ast
v.fmt
v.parser
v.table
@ -46,7 +47,7 @@ fn test_fmt() {
continue
}
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)
if expected_ocontent != result_ocontent {
fmt_bench.fail()

View File

@ -762,7 +762,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if name.starts_with('_op_') {
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)
g.write('$type_name ${name}(')
g.definitions.write('$type_name ${name}(')
@ -834,34 +834,40 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
fn (g mut Gen) free_scope_vars(pos int) {
scope := g.file.scope.innermost(pos)
for _, var in scope.vars {
// println('//////')
// println(var.name)
// println(var.typ)
// if var.typ == 0 {
// // TODO why 0?
// continue
// }
sym := g.table.get_type_symbol(var.typ)
if sym.kind == .array && !table.type_is_optional(var.typ) {
g.writeln('array_free($var.name); // autofreed')
}
if sym.kind == .string && !table.type_is_optional(var.typ) {
// Don't free simple string literals.
t := typeof(var.expr)
match var.expr {
ast.StringLiteral {
g.writeln('// str literal')
continue
for _, obj in scope.objects {
match obj {
ast.Var {
// println('//////')
// println(var.name)
// println(var.typ)
// if var.typ == 0 {
// // TODO why 0?
// continue
// }
var := *it
sym := g.table.get_type_symbol(var.typ)
if sym.kind == .array && !table.type_is_optional(var.typ) {
g.writeln('array_free($var.name); // autofreed')
}
else {
// NOTE/TODO: assign_stmt multi returns variables have no expr
// since the type comes from the called fns return type
g.writeln('// other ' + t)
continue
if sym.kind == .string && !table.type_is_optional(var.typ) {
// Don't free simple string literals.
t := typeof(var.expr)
match var.expr {
ast.StringLiteral {
g.writeln('// str literal')
continue
}
else {
// NOTE/TODO: assign_stmt multi returns variables have no expr
// since the type comes from the called fns return type
g.writeln('// other ' + t)
continue
}
}
g.writeln('string_free($var.name); // autofreed')
}
}
g.writeln('string_free($var.name); // autofreed')
}
else {}
}
}
}
@ -995,7 +1001,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.expr_with_cast(it.expr, it.expr_type, it.typ)
}
else {
// styp := g.table.type_to_str(it.typ)
// styp := g.table.Type_to_str(it.typ)
styp := g.typ(it.typ)
// 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) {
for i, field in node.fields {
name := c_name(field.name)
expr := node.exprs[i]
// TODO hack. Cut the generated value and paste it into definitions.
pos := g.out.len
g.expr(expr)
g.expr(field.expr)
val := g.out.after(pos)
g.out.go_back(val.len)
match expr {
match field.expr {
ast.CharLiteral, ast.IntegerLiteral {
// Simple expressions should use a #define
// so that we don't pollute the binary with unnecessary global vars
@ -2155,15 +2160,15 @@ int typ;
}
// 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()
// types name list
mut type_names := []string
for typ in types {
for typ in typesa {
type_names << typ.name
}
// loop over types
for t in types {
for t in typesa {
// create list of deps
mut field_deps := []string
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 {
p.next()
p.open_scope()
p.scope.register_var(ast.Var{
p.scope.register('err', ast.Var{
name: 'err'
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
args: args
// tok: tok
mod: p.mod
pos: tok.position()
is_c: is_c
or_block: ast.OrExpr{
@ -118,7 +118,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
args2,is_variadic := p.fn_args()
args << args2
for arg in args {
p.scope.register_var(ast.Var{
p.scope.register(arg.name, ast.Var{
name: arg.name
typ: arg.typ
})

View File

@ -18,26 +18,27 @@ import (
)
struct Parser {
scanner &scanner.Scanner
file_name string
scanner &scanner.Scanner
file_name string
mut:
tok token.Token
peek_tok token.Token
tok token.Token
peek_tok token.Token
// vars []string
table &table.Table
is_c bool
table &table.Table
is_c bool
// prefix_parse_fns []PrefixParseFn
inside_if bool
pref &pref.Preferences // Preferences shared from V struct
builtin_mod bool
mod string
attr string
expr_mod string
scope &ast.Scope
imports map[string]string
ast_imports []ast.Import
is_amp bool
returns bool
inside_if bool
pref &pref.Preferences // Preferences shared from V struct
builtin_mod bool
mod string
attr string
expr_mod string
scope &ast.Scope
global_scope &ast.Scope
imports map[string]string
ast_imports []ast.Import
is_amp bool
returns bool
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
}
@ -50,14 +51,17 @@ pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt {
pref: &pref.Preferences{}
scope: scope
// scope: &ast.Scope{start_pos: 0, parent: 0}
global_scope: &ast.Scope{
start_pos: 0
parent: 0
}
}
p.init_parse_fns()
p.read_first_token()
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")')
// text := os.read_file(path) or {
// panic(err)
@ -74,11 +78,11 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
start_pos: 0
parent: 0
}
global_scope: global_scope
// comments_mode: comments_mode
}
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'
} }
@ -110,6 +114,7 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
imports: p.ast_imports
stmts: stmts
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(paths)
@ -162,7 +167,7 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences) [
mut files := []ast.File
for path in paths {
// println('parse_files $path')
files << parse_file(path, table, .skip_comments, pref)
files << parse_file(path, table, .skip_comments, pref, global_scope)
}
return files
}
@ -530,16 +535,9 @@ pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident {
kind: .unresolved
name: name
is_c: is_c
mod: p.mod
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
}
@ -941,7 +939,7 @@ fn (p mut Parser) index_expr(left ast.Expr) ast.IndexExpr {
}
fn (p mut Parser) filter() {
p.scope.register_var(ast.Var{
p.scope.register('it', ast.Var{
name: 'it'
})
}
@ -967,7 +965,7 @@ fn (p mut Parser) dot_expr(left ast.Expr) ast.Expr {
if p.tok.kind == .key_orelse {
p.next()
p.open_scope()
p.scope.register_var(ast.Var{
p.scope.register('err', ast.Var{
name: 'err'
typ: table.string_type
})
@ -1112,7 +1110,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
p.check(.comma)
key_var_name = val_var_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
typ: table.int_type
})
@ -1129,14 +1127,14 @@ fn (p mut Parser) for_statement() ast.Stmt {
is_range = true
p.check(.dotdot)
high_expr = p.expr(0)
p.scope.register_var(ast.Var{
p.scope.register(val_var_name, ast.Var{
name: val_var_name
typ: table.int_type
})
}
else {
// 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
})
}
@ -1197,7 +1195,7 @@ fn (p mut Parser) if_expr() ast.IfExpr {
var_name := p.check_name()
p.check(.decl_assign)
expr := p.expr(0)
p.scope.register_var(ast.Var{
p.scope.register(var_name, ast.Var{
name: var_name
expr: expr
})
@ -1436,31 +1434,26 @@ fn (p mut Parser) const_decl() ast.ConstDecl {
pos := p.tok.position()
p.check(.key_const)
p.check(.lpar)
mut fields := []ast.Field
mut exprs := []ast.Expr
mut fields := []ast.ConstField
for p.tok.kind != .rpar {
name := p.prepend_mod(p.check_name())
// name := p.check_name()
// println('!!const: $name')
p.check(.assign)
expr := p.expr(0)
fields << ast.Field{
field := ast.ConstField{
name: name
expr: expr
pos: p.tok.position()
// typ: typ
}
exprs << expr
// TODO: once consts are fixed reg here & update in checker
// p.table.register_const(table.Var{
// name: name
// // typ: typ
// })
fields << field
p.global_scope.register(field.name, field)
}
p.check(.rpar)
return ast.ConstDecl{
pos : pos
fields: fields
exprs: exprs
is_pub: is_pub
}
}
@ -1695,13 +1688,13 @@ fn (p mut Parser) assign_stmt() ast.Stmt {
p.error('redefinition of `$ident.name`')
}
if idents.len == exprs.len {
p.scope.register_var(ast.Var{
p.scope.register(ident.name, ast.Var{
name: ident.name
expr: exprs[i]
})
}
else {
p.scope.register_var(ast.Var{
p.scope.register(ident.name, ast.Var{
name: ident.name
})
}
@ -1736,27 +1729,28 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
p.next()
p.expr(0)
}
p.table.register_global(name, typ)
// p.genln(p.table.cgen_name_type_pair(name, typ))
/*
mut g := p.table.cgen_name_type_pair(name, typ)
if p.tok == .assign {
p.next()
g += ' = '
_,expr := p.tmp_expr()
g += expr
}
// p.genln('; // global')
g += '; // global'
if !p.cgen.nogen {
p.cgen.consts << g
}
*/
mut g := p.table.cgen_name_type_pair(name, typ)
if p.tok == .assign {
p.next()
g += ' = '
_,expr := p.tmp_expr()
g += expr
}
// p.genln('; // global')
g += '; // global'
if !p.cgen.nogen {
p.cgen.consts << g
}
*/
return ast.GlobalDecl{
glob := ast.GlobalDecl{
name: name
typ: typ
}
p.global_scope.register(name, glob)
return glob
}
fn (p mut Parser) match_expr() ast.MatchExpr {
@ -1793,7 +1787,7 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
mut expr := ast.Expr{}
expr = x
exprs << expr
p.scope.register_var(ast.Var{
p.scope.register('it', ast.Var{
name: 'it'
typ: table.type_to_ptr(typ)
})

View File

@ -13,7 +13,6 @@ pub mut:
type_idxs map[string]int
// fns Hashmap
fns map[string]Fn
consts map[string]Var
imports []string // List of all imports
modules []string // List of all modules registered by the application
}
@ -38,8 +37,6 @@ pub struct Var {
pub:
name string
is_mut bool
is_const bool
is_global bool
mut:
typ Type
}
@ -50,23 +47,6 @@ pub fn new_table() &Table {
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
pub fn (f &Fn) signature() string {
mut sig := ''
@ -95,15 +75,6 @@ pub fn (t &Table) find_fn(name string) ?Fn {
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) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn

View File

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