Skip to content

Commit 38b33af

Browse files
committed
bsc: improve inline mod decl
1 parent 984cdc0 commit 38b33af

File tree

10 files changed

+138
-42
lines changed

10 files changed

+138
-42
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
__pycache__
2-
dist/
2+
bsc-out/

bsc/AST.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ def __init__(self, pkg_name, alias_name, pos):
3939
self.pkg_name = pkg_name
4040
self.alias_name = alias_name
4141
self.pos = pos
42+
self.sym = None
4243

4344
class ModDecl:
44-
def __init__(self, name, is_inline, decls, pos):
45+
def __init__(self, access_modifier, name, is_inline, decls, pos):
46+
self.access_modifier = access_modifier
4547
self.name = name
4648
self.is_inline = is_inline
4749
self.decls = decls
@@ -54,6 +56,7 @@ def __init__(self, access_modifier, name, fields, pos):
5456
self.name = name
5557
self.fields = fields
5658
self.pos = pos
59+
self.sym = None
5760

5861
class EnumField:
5962
def __init__(self, name, value):

bsc/__init__.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,18 @@ def parse_args(self):
5858
self.prefs.parse_args()
5959

6060
def compile(self):
61-
self.parse_file(self.prefs.pkg_name, self.prefs.input)
61+
self.parse_input()
6262
self.sema.check_files(self.source_files)
6363
self.codegen.gen_files(self.source_files)
6464

6565
def parse_input(self):
66-
self.parse_file(self.prefs.input)
66+
self.parse_file(
67+
self.prefs.pkg_name, self.prefs.input, is_pkg_root = True
68+
)
6769

68-
def parse_file(self, mod_name, file):
69-
self.source_files.append(self.astgen.parse_file(mod_name, file))
70+
def parse_file(
71+
self, mod_name, file, is_pkg_root = False, parent_mod = None
72+
):
73+
self.source_files.append(
74+
self.astgen.parse_file(mod_name, file, is_pkg_root, parent_mod)
75+
)

bsc/astgen.py

+16-8
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,24 @@ def __init__(self, ctx):
2121
self.file = ""
2222
self.source_file = None
2323

24-
def parse_file(self, mod_name, file):
24+
def parse_file(
25+
self, mod_name, file, is_pkg_root = False, parent_mod = None
26+
):
2527
self.file = file
2628
mod_sym = Module(
27-
AccessModifier.public, mod_name, Scope(self.ctx.universe)
29+
AccessModifier.public, mod_name, Scope(self.ctx.universe),
30+
is_pkg_root
2831
)
2932
self.source_file = SourceFile(
3033
self.file, self.transform(bs_parser.parse(open(file).read())),
3134
mod_sym
3235
)
3336
try:
34-
self.ctx.universe.add_sym(self.source_file.mod_sym)
37+
if is_pkg_root:
38+
self.ctx.universe.add_sym(self.source_file.mod_sym)
39+
else:
40+
assert parent_mod, f"parent_mod is None for `{mod_name}`"
41+
parent_mod.scope.add_sym(self.source_file.mod_sym)
3542
except utils.CompilerError as e:
3643
utils.error(e.args[0])
3744
return self.source_file
@@ -53,14 +60,15 @@ def extern_pkg(self, *nodes):
5360
return ExternPkg(pkg_name, alias_name, pos)
5461

5562
def mod_decl(self, *nodes):
63+
access_modifier = self.get_access_modifier(nodes)
5664
pos = self.mkpos(nodes[0] or nodes[1])
57-
is_inline = nodes[3] is None
65+
is_inline = nodes[3] != None
5866
decls = []
67+
if is_inline:
68+
decls = list(nodes[4:-1])
5969
if not is_inline:
60-
decls = list(nodes[4:-2])
61-
if not is_inline:
62-
pos += self.mkpos(nodes[-1])
63-
return ModDecl(nodes[2].name, is_inline, decls, pos)
70+
pos += nodes[2].pos
71+
return ModDecl(access_modifier, nodes[2].name, is_inline, decls, pos)
6472

6573
def enum_decl(self, *nodes):
6674
pos = self.mkpos(nodes[1])

bsc/codegen.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def __init__(self, ctx):
1111
self.ctx = ctx
1212
self.modules = []
1313
self.cur_module = None
14+
self.decls = []
1415

1516
def gen_files(self, source_files):
1617
for file in source_files:
@@ -21,19 +22,30 @@ def gen_files(self, source_files):
2122
def gen_file(self, file):
2223
self.cur_module = LuaModule(file.mod_sym.name)
2324
self.gen_decls(file.decls)
25+
self.cur_module.decls = self.decls
2426
self.modules.append(self.cur_module)
27+
self.decls = []
2528

2629
def gen_decls(self, decls):
2730
for decl in decls:
2831
self.gen_decl(decl)
2932

3033
def gen_decl(self, decl):
31-
if isinstance(decl, AST.FnDecl):
34+
if isinstance(decl, AST.ModDecl):
35+
self.gen_inline_mod(decl)
36+
elif isinstance(decl, AST.FnDecl):
3237
self.gen_fn_decl(decl)
3338

39+
def gen_inline_mod(self, decl):
40+
old_decls = self.decls
41+
self.decls = []
42+
self.gen_decls(decl.decls)
43+
old_decls.append(LuaModule(decl.sym.qualname("."), self.decls))
44+
self.decls = old_decls
45+
3446
def gen_fn_decl(self, decl):
3547
args = []
3648
for arg in decl.args:
3749
args.append(LuaIdent(arg.name))
38-
luafn = LuaFunction(decl.name, args)
39-
self.cur_module.decls.append(luafn)
50+
luafn = LuaFunction(decl.sym.qualname("."), args)
51+
self.decls.append(luafn)

bsc/lua_ast/__init__.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
# LICENSE file.
44

55
class LuaModule:
6-
def __init__(self, name):
6+
def __init__(self, name, decls = []):
77
self.name = name
8-
self.decls = []
8+
self.decls = decls
99

1010
class LuaTableField:
1111
def __init__(self, name, value):
@@ -28,6 +28,12 @@ class LuaBlock:
2828
def __init__(self):
2929
self.chunk = []
3030

31+
class LuaAssignment:
32+
def __init__(self, lefts, op, rights):
33+
self.lefts = lefts
34+
self.op = op
35+
self.rights = rights
36+
3137
class LuaIdent:
3238
def __init__(self, name):
3339
self.name = name

bsc/lua_ast/render.py

+39-13
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,39 @@
66
from bsc import sym, utils
77
from bsc.lua_ast import *
88

9+
BSC_OUT_DIR = "bsc-out"
10+
911
class LuaRender:
1012
def __init__(self, ctx, modules):
1113
self.ctx = ctx
14+
1215
self.modules = modules
1316
self.cur_module = None
17+
18+
self.indent = 0
19+
self.empty_line = True
1420
self.lua_file = utils.Builder()
1521

1622
def render_modules(self):
17-
if not os.path.exists("dist"):
18-
os.mkdir("dist/")
23+
if not os.path.exists(BSC_OUT_DIR):
24+
os.mkdir(BSC_OUT_DIR)
1925
for module in self.modules:
2026
self.cur_module = module
2127
self.render_module(module)
2228

2329
def render_module(self, module):
24-
self.lua_file.writeln(
30+
self.writeln(
2531
f"-- Autogenerated by the BlueScript compiler - {utils.full_version()}"
2632
)
27-
self.lua_file.writeln(
33+
self.writeln(
2834
"-- WARNING: DO NOT MODIFY MANUALLY! YOUR CHANGES WILL BE OVERWRITTEN --\n"
2935
)
3036

31-
self.lua_file.writeln(f"local {module.name} = {{}}\n")
37+
self.writeln(f"local {module.name} = {{}} -- package\n")
3238
self.render_decls(module.decls)
33-
self.lua_file.writeln(f"return {module.name}")
39+
self.writeln(f"return {module.name}\n")
3440

35-
with open(f"dist/{module.name}.lua", "w") as f:
41+
with open(f"{BSC_OUT_DIR}/{module.name}.lua", "w") as f:
3642
f.write(str(self.lua_file))
3743
self.lua_file.clear()
3844

@@ -41,14 +47,34 @@ def render_decls(self, decls):
4147
self.render_decl(decl)
4248

4349
def render_decl(self, decl):
44-
if isinstance(decl, LuaFunction):
50+
if isinstance(decl, LuaModule):
51+
self.render_inline_mod(decl)
52+
elif isinstance(decl, LuaFunction):
4553
self.render_fn_decl(decl)
4654

55+
def render_inline_mod(self, decl):
56+
self.writeln(f"{decl.name} = {{}} -- inline module\n")
57+
self.render_decls(decl.decls)
58+
4759
def render_fn_decl(self, decl):
48-
self.lua_file.write(f"function {self.cur_module.name}.{decl.name}(")
60+
self.write(f"function {decl.name}(")
4961
for i, arg in enumerate(decl.args):
50-
self.lua_file.write(arg.name)
62+
self.write(arg.name)
5163
if i < len(decl.args) - 1:
52-
self.lua_file.write(", ")
53-
self.lua_file.writeln(")")
54-
self.lua_file.writeln("end\n")
64+
self.write(", ")
65+
self.writeln(")")
66+
#self.indent += 1
67+
#self.indent -= 1
68+
self.writeln("end\n")
69+
70+
def write(self, s):
71+
if self.indent > 0 and self.empty_line:
72+
self.lua_file.write("\t" * self.indent)
73+
self.lua_file.write(s)
74+
self.empty_line = False
75+
76+
def writeln(self, s):
77+
if self.indent > 0 and self.empty_line:
78+
self.lua_file.write("\t" * self.indent)
79+
self.lua_file.writeln(s)
80+
self.empty_line = True

bsc/sema.py

+25-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ def __init__(self, ctx):
1414
self.first_pass = True
1515

1616
self.cur_file = None
17+
self.cur_pkg = None
18+
self.cur_mod = None
1719
self.cur_sym = None
1820
self.cur_scope = self.ctx.universe
1921

@@ -24,23 +26,41 @@ def check_files(self, files):
2426

2527
def check_files_(self, files):
2628
for file in files:
27-
self.cur_file = file
28-
self.cur_sym = file.mod_sym
2929
self.check_file(file)
3030

3131
def check_file(self, file):
32+
self.cur_file = file
33+
if file.mod_sym.is_pkg_root:
34+
self.cur_pkg = file.mod_sym
35+
self.cur_mod = file.mod_sym
36+
self.cur_sym = file.mod_sym
3237
self.check_decls(file.decls)
3338

3439
def check_decls(self, decls):
3540
for decl in decls:
3641
self.check_decl(decl)
3742

3843
def check_decl(self, decl):
39-
if isinstance(decl, EnumDecl):
44+
if isinstance(decl, ModDecl):
45+
self.check_mod_decl(decl)
46+
elif isinstance(decl, EnumDecl):
4047
self.check_enum_decl(decl)
4148
elif isinstance(decl, FnDecl):
4249
self.check_fn_decl(decl)
4350

51+
def check_mod_decl(self, decl):
52+
old_sym = self.cur_sym
53+
if self.first_pass and decl.is_inline:
54+
decl.sym = Module(
55+
decl.access_modifier, decl.name, self.open_scope(), False
56+
)
57+
self.add_sym(decl.sym, decl.pos)
58+
self.cur_sym = decl.sym
59+
self.check_decls(decl.decls)
60+
self.close_scope()
61+
self.cur_sym = old_sym
62+
return
63+
4464
def check_enum_decl(self, decl):
4565
if self.first_pass:
4666
fields = []
@@ -51,6 +71,7 @@ def check_enum_decl(self, decl):
5171
self.open_scope(), info = EnumInfo(fields)
5272
)
5373
self.add_sym(decl.sym, decl.pos)
74+
self.close_scope()
5475
return
5576
if len(decl.fields) == 0:
5677
report.error(f"enum `{decl.name}` cannot be empty", decl.pos)
@@ -61,6 +82,7 @@ def check_fn_decl(self, decl):
6182
decl.access_modifier, decl.name, [], self.open_scope()
6283
)
6384
self.add_sym(decl.sym, decl.pos)
85+
self.close_scope()
6486
return
6587

6688
## === Utilities ====================================

bsc/sym.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,20 @@ def typeof(self):
4545
elif isinstance(self, TypeSym):
4646
return self.type_kind()
4747
elif isinstance(self, Module):
48-
return "module"
48+
return "package" if self.is_pkg_root else "module"
4949
return "symbol"
5050

51-
def __str__(self):
51+
def qualname(self, sep = "::"):
5252
if self.parent and not self.parent.scope.is_universe:
53-
return f"{self.parent}.{self.name}"
53+
return f"{self.parent.qualname(sep)}{sep}{self.name}"
5454
return self.name
5555

56+
def __repr__(self):
57+
return str(self)
58+
59+
def __str__(self):
60+
return self.qualname()
61+
5662
class ObjectLevel(IntEnum):
5763
_global = auto()
5864
argument = auto()
@@ -141,10 +147,11 @@ def type_kind(self):
141147
return str(self.kind)
142148

143149
class Module(Sym):
144-
def __init__(self, access_modifier, name, scope):
150+
def __init__(self, access_modifier, name, scope, is_pkg_root):
145151
super().__init__(access_modifier, name)
146152
scope.owner = self
147153
self.scope = scope
154+
self.is_pkg_root = is_pkg_root
148155

149156
class Function(Sym):
150157
def __init__(self, access_modifier, name, args, scope):
@@ -181,9 +188,9 @@ def dont_lookup_scope(self):
181188
def add_sym(self, sym):
182189
if _ := self.lookup(sym.name):
183190
if self.owner:
184-
errmsg = f"duplicate symbol `{sym.name}` in {self.owner.typeof()} `{self.owner.name}`"
191+
errmsg = f"duplicate symbol `{sym.name}` in {self.owner.typeof()} `{self.owner}`"
185192
else:
186193
errmsg = f"duplicate symbol `{sym.name}` in global namespace"
187194
raise CompilerError(errmsg)
188-
sym.parent = self
195+
sym.parent = self.owner
189196
self.syms.append(sym)

examples/sema.bs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@ pub fn main() {
22
print("hello")
33
}
44

5-
fn my_fn(a: number){}
5+
fn my_fn(a: number) {}
6+
7+
mod my_module {
8+
pub fn new_func() {}
9+
pub fn other_func() {}
10+
}
11+

0 commit comments

Comments
 (0)