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

fix: register functions in package scope #291

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading