Skip to content

Commit

Permalink
fix: register functions in package scope (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
serkonda7 authored Jan 20, 2025
1 parent 0b82a98 commit 3cb87e5
Show file tree
Hide file tree
Showing 12 changed files with 65 additions and 47 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ All notable changes are documented in this file.
- Check for import alias name conflicts
- Properly warn if FFI is used in a file intended for a different backend
- Improve various error messages and reduce noise
- Functions can no longer be shadowed by variables

### Other Changes
- fix: `static` visibility now controlled by `pub` keyword
- `static` visibility is now controlled by `pub` keyword
- lexer: Disallow floats with trailing decimal point
- fix(c): Prevent c error if blank identifier is used

Expand Down
9 changes: 8 additions & 1 deletion lib/bait/ast/ast.bt
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ pub struct FunDecl {
pub lang Language
pub name string
pub mix_name string // TMP
pub mix_pkg string // TMP and TODO make this completely obsolete
pub params []Param
pub return_type Type
pub is_test bool
Expand Down Expand Up @@ -215,6 +214,14 @@ pub struct CallExpr {
pub pos token.Pos
}

pub fun (node CallExpr) full_name() string {
if node.pkg.length == 0 {
return node.name
}

return node.pkg + "." + node.name
}

pub struct CallArg {
global typ Type
global expr Expr
Expand Down
19 changes: 11 additions & 8 deletions lib/bait/checker/fun.bt
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ fun (c Checker) fun_params(params []ast.Param){
if sym.kind == .fun_ {
info := sym.info as ast.FunInfo
c.table.fun_decls[p.name] = ast.FunDecl{
mix_pkg = c.pkg
return_type = info.return_type
params = info.to_params()
}
c.scope.register(p.name, context.ScopeObject{
typ = p.typ
kind = .function
pkg = c.pkg
})
} else {
c.scope.register(p.name, context.ScopeObject{
Expand Down Expand Up @@ -130,6 +130,12 @@ fun (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
}

fun (mut c Checker) fun_call(mut node ast.CallExpr) ast.Type {
obj := c.find_in_scope(node.name, node.pkg)
if obj.kind != .function {
c.error('unknown function ${node.mix_name}', node.pos)
return ast.ERROR_TYPE
}

mut found := c.table.fun_decls.contains(node.mix_name)
if not found and not node.mix_name.contains('.') and c.pkg != 'builtin' {
full_name := c.pkg + '.' + node.mix_name
Expand All @@ -138,16 +144,13 @@ fun (mut c Checker) fun_call(mut node ast.CallExpr) ast.Type {
found = true
}
}
if not found {
c.error('unknown function ${node.mix_name}', node.pos)
return ast.ERROR_TYPE
}

mut def := c.table.fun_decls[node.mix_name]
if not def.is_pub and def.mix_pkg != c.pkg {
c.error('function ${def.mix_name} is private', node.pos)
// Check visibility
if not obj.is_pub and obj.pkg != c.pkg {
c.error("function `${node.full_name()}` is private", node.pos)
}

mut def := c.table.fun_decls[node.mix_name]
node.noreturn = def.noreturn
node.return_type = def.return_type

Expand Down
2 changes: 1 addition & 1 deletion lib/bait/gen/js/comptime.bt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fun (mut g Gen) get_comptime_val(kind token.ComptimeVar, pos token.Pos) string {
line := g.get_comptime_val(.line, pos)
'${file}:${line}'
}
.fun_ { g.cur_fun.mix_name }
.fun_ { g.cur_fun.name }

// Cached
.baitexe { g.comptime_baitexe() }
Expand Down
4 changes: 2 additions & 2 deletions lib/bait/gen/js/expr.bt
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ fun (mut g Gen) infix_expr(node ast.InfixExpr){
if node.op == .ne {
g.write('!')
}
g.write(js_esc(lsym.name + '_' + overload.mix_name))
g.write(js_esc(lsym.name + '_' + overload.name))
g.write('(')
g.expr(node.left)
g.write(', ')
Expand Down Expand Up @@ -325,7 +325,7 @@ fun (mut g Gen) expr_to_string(expr ast.Expr, typ ast.Type) {
}

str_def := g.table.get_method(sym, 'str')
if str_def.mix_name.length > 0 {
if str_def.name.length > 0 {
final_sym := g.table.get_sym(str_def.params[0].typ)
mut name := js_esc(final_sym.name)
g.write('${name}_str(')
Expand Down
12 changes: 6 additions & 6 deletions lib/bait/gen/js/fun.bt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ package js
import bait.ast

fun (mut g Gen) fun_decl(node ast.FunDecl) {
if node.mix_name == 'testsuite_begin' {
if node.name == 'testsuite_begin' {
g.has_test_begin = true
} else if node.mix_name == 'testsuite_end' {
} else if node.name == 'testsuite_end' {
g.has_test_end = true
}

Expand All @@ -30,7 +30,7 @@ fun (mut g Gen) fun_decl(node ast.FunDecl) {
mut name := ''
if node.is_method {
sym := g.table.get_sym(node.params[0].typ)
name = js_esc(sym.name + '_' + node.mix_name)
name = js_esc(sym.name + '_' + node.name)
} else {
name = js_esc(node.mix_name)
}
Expand Down Expand Up @@ -98,7 +98,7 @@ fun (mut g Gen) call_expr(node ast.CallExpr) {
fun (mut g Gen) call_expr_no_or(node ast.CallExpr) {
if node.is_method and node.lang != .bait {
g.expr(node.left)
g.write('.' + node.mix_name + '(')
g.write('.' + node.name + '(')
g.call_args(node.args)
g.write(')')
return
Expand All @@ -107,7 +107,7 @@ fun (mut g Gen) call_expr_no_or(node ast.CallExpr) {
if node.is_field {
g.expr(node.left)
g.write('.')
g.write(node.mix_name)
g.write(node.name)
g.write('(')
g.call_args(node.args)
g.write(')')
Expand Down Expand Up @@ -139,7 +139,7 @@ fun (mut g Gen) call_expr_no_or(node ast.CallExpr) {

g.write(name)

if not node.is_method and ['println', 'eprintln', 'print', 'eprint'].contains(node.mix_name) {
if not node.is_method and ['println', 'eprintln', 'print', 'eprint'].contains(node.name) {
g.write('(')
g.expr_to_string(node.args[0].expr, node.args[0].typ)
g.write(')')
Expand Down
2 changes: 1 addition & 1 deletion lib/bait/gen/js/stmt.bt
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ fun (mut g Gen) assign_stmt(node ast.AssignStmt){
if lsym.overloads.contains(node.op.js_repr()) {
g.write(' = ')
overload := lsym.overloads[node.op.js_repr()]
g.write(js_esc(lsym.name + '_' + overload.mix_name))
g.write(js_esc(lsym.name + '_' + overload.name))
g.write('(')
g.expr(node.left)
g.write(', ')
Expand Down
21 changes: 14 additions & 7 deletions lib/bait/parser/fun.bt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ fun (mut p Parser) fun_decl() !ast.FunDecl{
is_pub = is_pub
name = name
mix_name = mix_name
mix_pkg = p.pkg_name
generic_names = generic_names
params = params
return_type = return_type
Expand All @@ -101,12 +100,20 @@ fun (mut p Parser) fun_decl() !ast.FunDecl{
}
node.typ = p.table.find_or_register_fun(param_types, return_type, false)

p.pkg_scope.register_unique(mix_name, context.ScopeObject{
kind = .function
typ = node.typ
pkg = p.pkg_name
is_pub = is_pub
})
if lang == .bait {
p.pkg_scope.register_unique(name, context.ScopeObject{
kind = .function
typ = node.typ
pkg = p.pkg_name
is_pub = is_pub
})
} else {
ffi_scope := p.sema_ctx.obtain_root_scope(ffi.pkg)
ffi_scope.register(name, context.ScopeObject{
kind = .function
is_pub = true
})
}
}

if lang == .bait {
Expand Down
6 changes: 3 additions & 3 deletions lib/os/os.bt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// SPDX-License-Identifier: MIT
package os

pub fun walk_ext(dir string, ext string) []string {
pub fun walk_ext(basedir string, ext string) []string {
mut ext_files := []string
all_files := ls(dir)
all_files := ls(basedir)
for file in all_files {
fpath := join_path(dir, [file])
fpath := join_path(basedir, [file])
if is_dir(fpath) {
tmp := walk_ext(fpath, ext)
ext_files.push_many(tmp)
Expand Down
4 changes: 2 additions & 2 deletions lib/os/os.c.bt
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ pub fun user_args() []string {
return ARGS.slice(1, ARGS.length)
}

pub fun ls(dir string) []string {
pub fun ls(d string) []string {
mut res := []string
#C.'struct dirent *pDirent;
DIR *pDir;

pDir = opendir(dir.str);
pDir = opendir(d.str);
while((pDirent = readdir(pDir)) != NULL) {
if (strcmp(pDirent->d_name, ".") != 0 && strcmp(pDirent->d_name, "..") != 0) {
Array_push(&res, (string[]){from_c_string(pDirent->d_name)});
Expand Down
28 changes: 14 additions & 14 deletions lib/os/os.js.bt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub fun user_args() []string {
return ARGS.slice(2, ARGS.length)
}

pub fun ls(dir string) []string {
return from_js_string_arr(#JS.fs.readdirSync(dir.str))
pub fun ls(d string) []string {
return from_js_string_arr(#JS.fs.readdirSync(d.str))
}

pub fun cp(src string, dest string) {
Expand Down Expand Up @@ -42,8 +42,8 @@ pub fun is_root(path string) bool {
return path == '/'
}

pub fun chdir(dir string) {
#JS.process.chdir(dir.str)
pub fun chdir(d string) {
#JS.process.chdir(d.str)
}

pub fun home_dir() string {
Expand All @@ -60,30 +60,30 @@ pub fun is_dir(path string) bool {
return #JS.'JS.fs.lstatSync(path.str).isDirectory()' as bool
}

pub fun mkdir(dir string) {
if exists(dir) {
pub fun mkdir(d string) {
if exists(d) {
return
}
#JS.fs.mkdirSync(dir.str)
#JS.fs.mkdirSync(d.str)
}

pub fun mkdir_all(dir string) {
if exists(dir) {
pub fun mkdir_all(d string) {
if exists(d) {
return
}
#JS.'JS.fs.mkdirSync(dir.str, { recursive: true })'
#JS.'JS.fs.mkdirSync(d.str, { recursive: true })'
}

pub fun rm(path string) {
#JS.fs.rmSync(path.str)
}

pub fun rmdir(dir string) {
#JS.fs.rmdirSync(dir.str)
pub fun rmdir(d string) {
#JS.fs.rmdirSync(d.str)
}

pub fun rmdir_all(dir string) {
#JS.'JS.fs.rmdirSync(dir.str, { recursive: true })'
pub fun rmdir_all(d string) {
#JS.'JS.fs.rmdirSync(d.str, { recursive: true })'
}

pub fun read_bytes(path string) []u8 {
Expand Down
2 changes: 1 addition & 1 deletion tests/out/error/other/is_private.out
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ tests/out/error/other/is_private.in.bt:10:14 error: enum bait.test_pkgs.pubpriv.
tests/out/error/other/is_private.in.bt:11:9 error: type bait.test_pkgs.pubpriv.PrivEnum is private
tests/out/error/other/is_private.in.bt:13:14 error: const `bait.test_pkgs.pubpriv.PRIV_CONST` is private
tests/out/error/other/is_private.in.bt:15:13 error: static `bait.test_pkgs.pubpriv.priv_static` is private
tests/out/error/other/is_private.in.bt:17:9 error: function bait.test_pkgs.pubpriv.priv_fun is private
tests/out/error/other/is_private.in.bt:17:9 error: function `bait.test_pkgs.pubpriv.priv_fun` is private
tests/out/error/other/is_private.in.bt:20:4 error: method priv_method is private

0 comments on commit 3cb87e5

Please sign in to comment.