Skip to content

Commit

Permalink
bsc: improve inline mod decl
Browse files Browse the repository at this point in the history
  • Loading branch information
StunxFS committed Jun 9, 2024
1 parent 984cdc0 commit 38b33af
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__pycache__
dist/
bsc-out/
5 changes: 4 additions & 1 deletion bsc/AST.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ def __init__(self, pkg_name, alias_name, pos):
self.pkg_name = pkg_name
self.alias_name = alias_name
self.pos = pos
self.sym = None

class ModDecl:
def __init__(self, name, is_inline, decls, pos):
def __init__(self, access_modifier, name, is_inline, decls, pos):
self.access_modifier = access_modifier
self.name = name
self.is_inline = is_inline
self.decls = decls
Expand All @@ -54,6 +56,7 @@ def __init__(self, access_modifier, name, fields, pos):
self.name = name
self.fields = fields
self.pos = pos
self.sym = None

class EnumField:
def __init__(self, name, value):
Expand Down
14 changes: 10 additions & 4 deletions bsc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@ def parse_args(self):
self.prefs.parse_args()

def compile(self):
self.parse_file(self.prefs.pkg_name, self.prefs.input)
self.parse_input()
self.sema.check_files(self.source_files)
self.codegen.gen_files(self.source_files)

def parse_input(self):
self.parse_file(self.prefs.input)
self.parse_file(
self.prefs.pkg_name, self.prefs.input, is_pkg_root = True
)

def parse_file(self, mod_name, file):
self.source_files.append(self.astgen.parse_file(mod_name, file))
def parse_file(
self, mod_name, file, is_pkg_root = False, parent_mod = None
):
self.source_files.append(
self.astgen.parse_file(mod_name, file, is_pkg_root, parent_mod)
)
24 changes: 16 additions & 8 deletions bsc/astgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,24 @@ def __init__(self, ctx):
self.file = ""
self.source_file = None

def parse_file(self, mod_name, file):
def parse_file(
self, mod_name, file, is_pkg_root = False, parent_mod = None
):
self.file = file
mod_sym = Module(
AccessModifier.public, mod_name, Scope(self.ctx.universe)
AccessModifier.public, mod_name, Scope(self.ctx.universe),
is_pkg_root
)
self.source_file = SourceFile(
self.file, self.transform(bs_parser.parse(open(file).read())),
mod_sym
)
try:
self.ctx.universe.add_sym(self.source_file.mod_sym)
if is_pkg_root:
self.ctx.universe.add_sym(self.source_file.mod_sym)
else:
assert parent_mod, f"parent_mod is None for `{mod_name}`"
parent_mod.scope.add_sym(self.source_file.mod_sym)
except utils.CompilerError as e:
utils.error(e.args[0])
return self.source_file
Expand All @@ -53,14 +60,15 @@ def extern_pkg(self, *nodes):
return ExternPkg(pkg_name, alias_name, pos)

def mod_decl(self, *nodes):
access_modifier = self.get_access_modifier(nodes)
pos = self.mkpos(nodes[0] or nodes[1])
is_inline = nodes[3] is None
is_inline = nodes[3] != None
decls = []
if is_inline:
decls = list(nodes[4:-1])
if not is_inline:
decls = list(nodes[4:-2])
if not is_inline:
pos += self.mkpos(nodes[-1])
return ModDecl(nodes[2].name, is_inline, decls, pos)
pos += nodes[2].pos
return ModDecl(access_modifier, nodes[2].name, is_inline, decls, pos)

def enum_decl(self, *nodes):
pos = self.mkpos(nodes[1])
Expand Down
18 changes: 15 additions & 3 deletions bsc/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def __init__(self, ctx):
self.ctx = ctx
self.modules = []
self.cur_module = None
self.decls = []

def gen_files(self, source_files):
for file in source_files:
Expand All @@ -21,19 +22,30 @@ def gen_files(self, source_files):
def gen_file(self, file):
self.cur_module = LuaModule(file.mod_sym.name)
self.gen_decls(file.decls)
self.cur_module.decls = self.decls
self.modules.append(self.cur_module)
self.decls = []

def gen_decls(self, decls):
for decl in decls:
self.gen_decl(decl)

def gen_decl(self, decl):
if isinstance(decl, AST.FnDecl):
if isinstance(decl, AST.ModDecl):
self.gen_inline_mod(decl)
elif isinstance(decl, AST.FnDecl):
self.gen_fn_decl(decl)

def gen_inline_mod(self, decl):
old_decls = self.decls
self.decls = []
self.gen_decls(decl.decls)
old_decls.append(LuaModule(decl.sym.qualname("."), self.decls))
self.decls = old_decls

def gen_fn_decl(self, decl):
args = []
for arg in decl.args:
args.append(LuaIdent(arg.name))
luafn = LuaFunction(decl.name, args)
self.cur_module.decls.append(luafn)
luafn = LuaFunction(decl.sym.qualname("."), args)
self.decls.append(luafn)
10 changes: 8 additions & 2 deletions bsc/lua_ast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
# LICENSE file.

class LuaModule:
def __init__(self, name):
def __init__(self, name, decls = []):
self.name = name
self.decls = []
self.decls = decls

class LuaTableField:
def __init__(self, name, value):
Expand All @@ -28,6 +28,12 @@ class LuaBlock:
def __init__(self):
self.chunk = []

class LuaAssignment:
def __init__(self, lefts, op, rights):
self.lefts = lefts
self.op = op
self.rights = rights

class LuaIdent:
def __init__(self, name):
self.name = name
Expand Down
52 changes: 39 additions & 13 deletions bsc/lua_ast/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,39 @@
from bsc import sym, utils
from bsc.lua_ast import *

BSC_OUT_DIR = "bsc-out"

class LuaRender:
def __init__(self, ctx, modules):
self.ctx = ctx

self.modules = modules
self.cur_module = None

self.indent = 0
self.empty_line = True
self.lua_file = utils.Builder()

def render_modules(self):
if not os.path.exists("dist"):
os.mkdir("dist/")
if not os.path.exists(BSC_OUT_DIR):
os.mkdir(BSC_OUT_DIR)
for module in self.modules:
self.cur_module = module
self.render_module(module)

def render_module(self, module):
self.lua_file.writeln(
self.writeln(
f"-- Autogenerated by the BlueScript compiler - {utils.full_version()}"
)
self.lua_file.writeln(
self.writeln(
"-- WARNING: DO NOT MODIFY MANUALLY! YOUR CHANGES WILL BE OVERWRITTEN --\n"
)

self.lua_file.writeln(f"local {module.name} = {{}}\n")
self.writeln(f"local {module.name} = {{}} -- package\n")
self.render_decls(module.decls)
self.lua_file.writeln(f"return {module.name}")
self.writeln(f"return {module.name}\n")

with open(f"dist/{module.name}.lua", "w") as f:
with open(f"{BSC_OUT_DIR}/{module.name}.lua", "w") as f:
f.write(str(self.lua_file))
self.lua_file.clear()

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

def render_decl(self, decl):
if isinstance(decl, LuaFunction):
if isinstance(decl, LuaModule):
self.render_inline_mod(decl)
elif isinstance(decl, LuaFunction):
self.render_fn_decl(decl)

def render_inline_mod(self, decl):
self.writeln(f"{decl.name} = {{}} -- inline module\n")
self.render_decls(decl.decls)

def render_fn_decl(self, decl):
self.lua_file.write(f"function {self.cur_module.name}.{decl.name}(")
self.write(f"function {decl.name}(")
for i, arg in enumerate(decl.args):
self.lua_file.write(arg.name)
self.write(arg.name)
if i < len(decl.args) - 1:
self.lua_file.write(", ")
self.lua_file.writeln(")")
self.lua_file.writeln("end\n")
self.write(", ")
self.writeln(")")
#self.indent += 1
#self.indent -= 1
self.writeln("end\n")

def write(self, s):
if self.indent > 0 and self.empty_line:
self.lua_file.write("\t" * self.indent)
self.lua_file.write(s)
self.empty_line = False

def writeln(self, s):
if self.indent > 0 and self.empty_line:
self.lua_file.write("\t" * self.indent)
self.lua_file.writeln(s)
self.empty_line = True
28 changes: 25 additions & 3 deletions bsc/sema.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def __init__(self, ctx):
self.first_pass = True

self.cur_file = None
self.cur_pkg = None
self.cur_mod = None
self.cur_sym = None
self.cur_scope = self.ctx.universe

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

def check_files_(self, files):
for file in files:
self.cur_file = file
self.cur_sym = file.mod_sym
self.check_file(file)

def check_file(self, file):
self.cur_file = file
if file.mod_sym.is_pkg_root:
self.cur_pkg = file.mod_sym
self.cur_mod = file.mod_sym
self.cur_sym = file.mod_sym
self.check_decls(file.decls)

def check_decls(self, decls):
for decl in decls:
self.check_decl(decl)

def check_decl(self, decl):
if isinstance(decl, EnumDecl):
if isinstance(decl, ModDecl):
self.check_mod_decl(decl)
elif isinstance(decl, EnumDecl):
self.check_enum_decl(decl)
elif isinstance(decl, FnDecl):
self.check_fn_decl(decl)

def check_mod_decl(self, decl):
old_sym = self.cur_sym
if self.first_pass and decl.is_inline:
decl.sym = Module(
decl.access_modifier, decl.name, self.open_scope(), False
)
self.add_sym(decl.sym, decl.pos)
self.cur_sym = decl.sym
self.check_decls(decl.decls)
self.close_scope()
self.cur_sym = old_sym
return

def check_enum_decl(self, decl):
if self.first_pass:
fields = []
Expand All @@ -51,6 +71,7 @@ def check_enum_decl(self, decl):
self.open_scope(), info = EnumInfo(fields)
)
self.add_sym(decl.sym, decl.pos)
self.close_scope()
return
if len(decl.fields) == 0:
report.error(f"enum `{decl.name}` cannot be empty", decl.pos)
Expand All @@ -61,6 +82,7 @@ def check_fn_decl(self, decl):
decl.access_modifier, decl.name, [], self.open_scope()
)
self.add_sym(decl.sym, decl.pos)
self.close_scope()
return

## === Utilities ====================================
Expand Down
19 changes: 13 additions & 6 deletions bsc/sym.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,20 @@ def typeof(self):
elif isinstance(self, TypeSym):
return self.type_kind()
elif isinstance(self, Module):
return "module"
return "package" if self.is_pkg_root else "module"
return "symbol"

def __str__(self):
def qualname(self, sep = "::"):
if self.parent and not self.parent.scope.is_universe:
return f"{self.parent}.{self.name}"
return f"{self.parent.qualname(sep)}{sep}{self.name}"
return self.name

def __repr__(self):
return str(self)

def __str__(self):
return self.qualname()

class ObjectLevel(IntEnum):
_global = auto()
argument = auto()
Expand Down Expand Up @@ -141,10 +147,11 @@ def type_kind(self):
return str(self.kind)

class Module(Sym):
def __init__(self, access_modifier, name, scope):
def __init__(self, access_modifier, name, scope, is_pkg_root):
super().__init__(access_modifier, name)
scope.owner = self
self.scope = scope
self.is_pkg_root = is_pkg_root

class Function(Sym):
def __init__(self, access_modifier, name, args, scope):
Expand Down Expand Up @@ -181,9 +188,9 @@ def dont_lookup_scope(self):
def add_sym(self, sym):
if _ := self.lookup(sym.name):
if self.owner:
errmsg = f"duplicate symbol `{sym.name}` in {self.owner.typeof()} `{self.owner.name}`"
errmsg = f"duplicate symbol `{sym.name}` in {self.owner.typeof()} `{self.owner}`"
else:
errmsg = f"duplicate symbol `{sym.name}` in global namespace"
raise CompilerError(errmsg)
sym.parent = self
sym.parent = self.owner
self.syms.append(sym)
8 changes: 7 additions & 1 deletion examples/sema.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ pub fn main() {
print("hello")
}

fn my_fn(a: number){}
fn my_fn(a: number) {}

mod my_module {
pub fn new_func() {}
pub fn other_func() {}
}

0 comments on commit 38b33af

Please sign in to comment.