Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: prepare introduction of package scopes #248

Merged
merged 9 commits into from
Nov 28, 2024
25 changes: 12 additions & 13 deletions lib/bait/ast/ast.bt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ package ast
import bait.token
import bait.errors

type Stmt := AssertStmt | AssignStmt | ConstDecl | EnumDecl | ExprStmt | ForLoop | ForClassicLoop | ForInLoop | FunDecl | GlobalDecl | InterfaceDecl | ReturnStmt | StructDecl | TypeDecl | LoopControlStmt | EmptyStmt | IfMatch
type Stmt := AssertStmt | AssignStmt | ConstDecl | EnumDecl | ExprStmt | ForLoop | ForClassicLoop | ForInLoop | FunDecl | GlobalDecl | InterfaceDecl | ReturnStmt | StructDecl | TypeDecl | LoopControlStmt | IfMatch | InvalidStmt

type Expr := AnonFun | ArrayInit | AsCast | BoolLiteral | CallExpr | CharLiteral | ComptimeVar | EnumVal | FloatLiteral | HashExpr | Ident | IfMatch | IndexExpr | InfixExpr | IntegerLiteral | MapInit | ParExpr | PrefixExpr | SelectorExpr | StringLiteral | StringInterLiteral | StructInit | TypeOf | Void | EmptyExpr
type Expr := AnonFun | ArrayInit | AsCast | BoolLiteral | CallExpr | CharLiteral | ComptimeVar | EnumVal | FloatLiteral | HashExpr | Ident | IfMatch | IndexExpr | InfixExpr | IntegerLiteral | MapInit | ParExpr | PrefixExpr | SelectorExpr | StringLiteral | StringInterLiteral | StructInit | TypeOf | Void | InvalidExpr

pub struct AssertStmt {
pub expr Expr
Expand All @@ -25,7 +25,9 @@ pub struct AssignStmt {

pub struct ConstDecl {
pub name string
pub expr Expr
pub pkg string
pub reg_name string
pub expr Expr := InvalidExpr{}
pub pos token.Pos
pub lang Language
global typ Type
Expand Down Expand Up @@ -113,6 +115,7 @@ pub struct LoopControlStmt {
pub struct GlobalDecl {
global typ Type
pub name string
pub pkg string
pub expr Expr
pub pos token.Pos
}
Expand Down Expand Up @@ -144,7 +147,7 @@ pub struct StructDecl {
pub struct StructField {
pub name string
pub typ Type
pub expr Expr := EmptyExpr{}
pub expr Expr := InvalidExpr{}
pub pos token.Pos
pub is_mut bool
pub is_pub bool
Expand All @@ -164,8 +167,8 @@ pub struct ArrayInit {
global typ Type
global elem_type Type
pub exprs []Expr
pub length_expr Expr := EmptyExpr{}
pub cap_expr Expr := EmptyExpr{}
pub length_expr Expr := InvalidExpr{}
pub cap_expr Expr := InvalidExpr{}
pub pos token.Pos
}

Expand All @@ -186,7 +189,7 @@ pub struct CallExpr {
global name string
global return_type Type
global left_type Type
global left Expr := EmptyExpr{}
global left Expr := InvalidExpr{}
global concrete_types []Type
global is_field bool
global noreturn bool
Expand Down Expand Up @@ -352,15 +355,11 @@ pub struct TypeOf {

pub struct Void {}

pub struct EmptyExpr {
pub struct InvalidExpr {
pub pos token.Pos
}

pub fun empty_expr() Expr {
return EmptyExpr{}
}

pub struct EmptyStmt {
pub struct InvalidStmt {
pub pos token.Pos
}

Expand Down
2 changes: 1 addition & 1 deletion lib/bait/ast/repr.bt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fun (e Expr) repr() string {
StructInit { e.name + '{..}'} // TODO fields
TypeOf { 'typeof ' + e.expr.repr() }
Void { 'void' }
EmptyExpr { 'EmptyExpr' }
InvalidExpr { 'InvalidExpr' }
}
}

Expand Down
22 changes: 20 additions & 2 deletions lib/bait/ast/scope.bt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package ast

pub struct Scope {
pub parent Scope
pub parent &Scope
pub objects map[string]ScopeObject
}

Expand All @@ -13,7 +13,7 @@ pub struct ScopeObject{
pub mut is_pub bool
pub mut is_mut bool
pub mut pkg string
pub mut expr Expr := EmptyExpr{} // Only for constants. Allows resolving their type early
pub mut expr Expr := InvalidExpr{} // Only for constants. Allows resolving their type early
}

pub enum ObjectKind {
Expand All @@ -26,6 +26,24 @@ pub enum ObjectKind {
label
}

pub fun (mut t Table) preregister_scopes(pkg_name string) &Scope {
builtin_scope := t.get_pkg_scope("builtin", 0 as any)
pkg_scope := t.get_pkg_scope(pkg_name, builtin_scope)
return pkg_scope
}

pub fun (mut t Table) get_pkg_scope(pkg string, parent &Scope) &Scope {
if t.scopes.contains(pkg) {
return t.scopes[pkg]
}

s := &Scope{
parent = parent
}
t.scopes[pkg] = s
return s
}

pub fun (s Scope) register(name string, obj ScopeObject) {
if s.objects.contains(name) {
return
Expand Down
7 changes: 6 additions & 1 deletion lib/bait/ast/table.bt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package ast

pub struct Table {
pub mut global_scope Scope
pub mut global_scope &Scope // TODO SCOPES entirely replace by scopes
pub mut ffi_scope &Scope // Contains the C or JS declarations depending on the backend
pub mut scopes map[string]&Scope
pub mut fun_decls map[string]FunDecl
pub mut type_idxs map[string]Type
pub mut type_symbols []TypeSymbol
Expand All @@ -18,6 +20,9 @@ pub fun new_table() Table {
global_scope = Scope{
parent = 0 as any
}
ffi_scope = Scope{
parent = 0 as any
}
}
t.register_builtins()
return t
Expand Down
2 changes: 1 addition & 1 deletion lib/bait/checker/attribute.bt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fun (c Checker) check_struct_field_attrs(node ast.StructDecl){
continue
}

if attr.name == 'required' and not (field.expr is ast.EmptyExpr) {
if attr.name == 'required' and not (field.expr is ast.InvalidExpr) {
c.error('@required on field with default value is redundant', attr.pos)
}
}
Expand Down
1 change: 0 additions & 1 deletion lib/bait/checker/checker.bt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ fun (mut c Checker) change_file(file ast.File) {
c.pkg = file.pkg_name

c.scope = ast.Scope{
// TODO how to handle recursive sturct inits?
parent = c.table.global_scope
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/bait/checker/comptime.bt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fun (mut c Checker) comptime_if_condition(node ast.Expr) bool {
}
}
} else {
c.error('invalid $if condition', (node as ast.EmptyExpr).pos)
c.error('invalid $if condition', (node as ast.InvalidExpr).pos)
}
return false
}
31 changes: 25 additions & 6 deletions lib/bait/checker/expr.bt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fun (mut c Checker) expr(mut expr ast.Expr) ast.Type {
ast.StructInit { c.struct_init(mut expr) }
ast.TypeOf { c.type_of(mut expr) }
ast.Void { ast.VOID_TYPE }
ast.EmptyExpr { panic('unexpected EmptyExpr at ${expr.pos}') }
ast.InvalidExpr { panic('unexpected InvalidExpr at ${expr.pos}') }
}
c.expected_type = expected_save
return t
Expand All @@ -52,13 +52,13 @@ fun (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
}

// Validate fields if present
if not (node.length_expr is ast.EmptyExpr) {
if not (node.length_expr is ast.InvalidExpr) {
typ := c.expr(node.length_expr)
if not c.check_types(typ, ast.I32_TYPE) {
c.error('expected i32, got ${c.table.type_name(typ)}', node.pos)
}
}
if not (node.cap_expr is ast.EmptyExpr) {
if not (node.cap_expr is ast.InvalidExpr) {
typ := c.expr(node.cap_expr)
if not c.check_types(typ, ast.I32_TYPE) {
c.error('expected i32, got ${c.table.type_name(typ)}', node.pos)
Expand All @@ -76,7 +76,7 @@ fun (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
c.expected_type = typ
}
if not c.check_types(typ, node.elem_type) {
pos := (e as ast.EmptyExpr).pos
pos := (e as ast.InvalidExpr).pos
c.error('expected element type ${c.table.type_name(node.elem_type)}, got ${c.table.type_name(typ)}', pos)
}
}
Expand Down Expand Up @@ -149,13 +149,32 @@ fun (mut c Checker) hash_expr(node ast.HashExpr) ast.Type {
return ast.VOID_TYPE
}

// TODO SCOPES cleanup and add comments
fun (mut c Checker) ident(mut node ast.Ident) ast.Type {
mut obj := c.scope.get(node.name)

if obj.kind == .constant and not obj.is_pub and obj.pkg != c.pkg {
c.error('const ${node.name} is private', node.pos)
}

if obj.typ == ast.PLACEHOLDER_TYPE {
obj = c.table.scopes[node.pkg].get(node.name)
}

if obj.kind == .constant or obj.kind == .global_ {
if not node.name.contains('.') {
if obj.pkg == "" {
node.name = node.pkg + '.' + node.name
} else {
node.name = obj.pkg + '.' + node.name
}
}
}

if obj.typ == ast.PLACEHOLDER_TYPE and node.lang != .bait {
obj = c.table.ffi_scope.get(node.name)
}

if obj.typ != ast.PLACEHOLDER_TYPE {
node.is_mut = obj.is_mut
return obj.typ
Expand Down Expand Up @@ -231,11 +250,11 @@ fun (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
node.val_type = val_type
} else {
if not c.check_types(key_type, node.key_type) {
key_expr := key as ast.EmptyExpr
key_expr := key as ast.InvalidExpr
c.error('expected key type ${c.table.type_name(node.key_type)}, got ${c.table.type_name(key_type)}', key_expr.pos)
}
if not c.check_types(val_type, node.val_type) {
val_expr := node.vals[i] as ast.EmptyExpr
val_expr := node.vals[i] as ast.InvalidExpr
c.error('expected value type ${c.table.type_name(node.val_type)}, got ${c.table.type_name(val_type)}', val_expr.pos)
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/bait/checker/redefinition.bt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fun (mut c Checker) check_redefinitions(redefs_list []string, kind RedefKind, fi
if stmt_is_redef(stmt, name, kind) {
redefinitions.push(Redefinition{
path = file.path
pos = (stmt as ast.EmptyStmt).pos
pos = (stmt as ast.InvalidStmt).pos
name = name
signature = c.stmt_signature(stmt)
})
Expand Down
10 changes: 5 additions & 5 deletions lib/bait/checker/stmt.bt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fun (mut c Checker) stmt(mut stmt ast.Stmt){
ast.StructDecl { c.struct_decl(stmt) }
ast.TypeDecl { c.type_decl(stmt) }
else {
s := stmt as ast.EmptyStmt
s := stmt as ast.InvalidStmt
c.error('unexpected stmt: ${s}', s.pos)
}
}
Expand All @@ -51,7 +51,7 @@ fun (mut c Checker) const_decl(mut node ast.ConstDecl) {
}

node.typ = c.expr(node.expr)
c.table.global_scope.update_type(node.name, node.typ)
c.table.global_scope.update_type(node.reg_name, node.typ)
}

fun (mut c Checker) expr_stmt(mut node ast.ExprStmt) {
Expand All @@ -62,7 +62,7 @@ fun (mut c Checker) expr_stmt(mut node ast.ExprStmt) {
if c.is_if_match_expr or c.is_or_block or expr is ast.CallExpr or expr is ast.IfMatch or expr is ast.HashExpr {
return
}
e := expr as ast.EmptyExpr
e := expr as ast.InvalidExpr
c.error('expression evaluated but not used', e.pos)
}

Expand All @@ -85,7 +85,7 @@ fun (c Checker) enum_decl(node ast.EnumDecl) {
}
}

if field.expr is ast.EmptyExpr {
if field.expr is ast.InvalidExpr {
field.expr = ast.IntegerLiteral{ val = '${cur_val}' }
cur_val += 1
continue
Expand Down Expand Up @@ -181,7 +181,7 @@ fun (mut c Checker) for_in_loop(mut node ast.ForInLoop) {

fun (mut c Checker) global_decl(mut node ast.GlobalDecl){
node.typ = c.expr(node.expr)
c.table.global_scope.update_type(node.name, node.typ)
c.table.scopes[node.pkg].update_type(node.name, node.typ)
}

fun (c Checker) interface_decl(node ast.InterfaceDecl){
Expand Down
6 changes: 3 additions & 3 deletions lib/bait/checker/struct.bt
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ fun (mut c Checker) struct_decl(node ast.StructDecl) {
}

// Check the default value if present
if field.expr is ast.EmptyExpr {
if field.expr is ast.InvalidExpr {
continue
}
typ := c.expr(field.expr)
if not c.check_types(typ, field.typ) {
c.error('default value not matches field type ${c.table.type_name(field.typ)}', (field.expr as ast.EmptyExpr).pos)
c.error('default value not matches field type ${c.table.type_name(field.typ)}', (field.expr as ast.InvalidExpr).pos)
}
}

Expand Down Expand Up @@ -108,7 +108,7 @@ fun (c Checker) check_init_field_values(init ast.StructInit, info ast.StructInfo
continue
}

if not (def_field.expr is ast.EmptyExpr) {
if not (def_field.expr is ast.InvalidExpr) {
continue
}

Expand Down
10 changes: 5 additions & 5 deletions lib/bait/gen/c/assert.bt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ fun (mut g Gen) assert_stmt(node ast.AssertStmt) {
g.write('if (')
g.expr(node.expr)
g.writeln(') {')
g.writeln('\tTestRunner_assert_pass(&test_runner);')
g.writeln('\tTestRunner_assert_pass(&builtin__test_runner);')
g.writeln('} else {')
if node.expr is ast.InfixExpr {
expr := node.expr as ast.InfixExpr
g.write('\tTestRunner_set_assert_info(&test_runner, ${node.pos.line}, from_c_string("assert ')
g.write('\tTestRunner_set_assert_info(&builtin__test_runner, ${node.pos.line}, from_c_string("assert ')
g.assert_side_expr(expr.left)
g.write(' ${expr.op.js_repr()} ')
g.assert_side_expr(expr.right)
Expand All @@ -31,12 +31,12 @@ fun (mut g Gen) assert_stmt(node ast.AssertStmt) {
g.write(', ')
g.expr_to_string(expr.right, expr.right_type)
g.writeln(');')
g.writeln('\tTestRunner_assert_fail_infix(&test_runner);')
g.writeln('\tTestRunner_assert_fail_infix(&builtin__test_runner);')
} else {
g.write('\tTestRunner_set_assert_info(&test_runner, ${node.pos.line}, from_c_string("assert ')
g.write('\tTestRunner_set_assert_info(&builtin__test_runner, ${node.pos.line}, from_c_string("assert ')
g.assert_side_expr(node.expr)
g.writeln('"), from_c_string(""), from_c_string(""));')
g.writeln('\tTestRunner_assert_fail(&test_runner);')
g.writeln('\tTestRunner_assert_fail(&builtin__test_runner);')
}
g.writeln('}')
}
Expand Down
4 changes: 2 additions & 2 deletions lib/bait/gen/c/auto_str.bt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const LB := if os.platform() == 'windows' { '\\r\\n' } else { '\\n' }
fun (mut g Gen) get_str_fun(typ ast.Type) string {
g.table.needed_str_funs.push(typ)
sym := g.table.get_sym(typ)
return c_name('${sym.name}_str')
return c_esc('${sym.name}_str')
}

fun (mut g Gen) generate_str_fun(typ ast.Type) {
Expand All @@ -26,7 +26,7 @@ fun (mut g Gen) generate_str_fun(typ ast.Type) {

g.generated_str_funs.push(typ)

sname := c_name(sym.name)
sname := c_esc(sym.name)
fname := sname + '_str'

if sym.kind == .struct_ {
Expand Down
Loading
Loading