Skip to content

Commit

Permalink
astgen: fix VarDecl
Browse files Browse the repository at this point in the history
  • Loading branch information
StunxFS committed Jun 11, 2024
1 parent bd25ef7 commit 18764bf
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/compiler_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:
run: |
sudo pip3 install lark
python3 bsc examples/hello_world.bs
python3 bsc tests/sema.bs
python3 bsc tests/main.bs
28 changes: 15 additions & 13 deletions bsc/AST.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ def __init__(self, name, type, default_value):
self.type = type
self.default_value = default_value

class VarDecl:
def __init__(self, access_modifier, lefts, right, pos):
self.access_modifier = access_modifier
self.lefts = lefts
self.right = right
self.pos = pos

class VarIdent:
def __init__(self, name, typ, pos):
self.name = name
self.typ = typ
self.pos = pos

# Statements

class OpAssign(IntEnum):
Expand Down Expand Up @@ -122,17 +135,6 @@ def __str__(self):
return "^="
assert False # unreachable

class VarIdent:
def __init__(self, name, typ, pos):
self.name = name
self.typ = typ
self.pos = pos

class VarDecl:
def __init__(self, lefts, right):
self.lefts = lefts
self.right = right

class AssignStmt:
def __init__(self, lefts, op, right, pos):
self.lefts = lefts
Expand Down Expand Up @@ -579,7 +581,7 @@ def __eq__(self, other):
if isinstance(other, SumType):
if len(self.types) != len(other.types):
return False
for i,t in enumerate(self.types):
for i, t in enumerate(self.types):
if t != other.types[i]:
return False
return True
Expand All @@ -600,7 +602,7 @@ def __eq__(self, other):
if isinstance(other, TupleType):
if len(self.types) != len(other.types):
return False
for i,t in enumerate(self.types):
for i, t in enumerate(self.types):
if t != other.types[i]:
return False
return True
Expand Down
22 changes: 11 additions & 11 deletions bsc/astgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ def __init__(self, ctx):
def parse_file(self, mod_name, file, is_pkg = False, parent_mod = None):
self.file = file
self.mod_sym = Module(
AccessModifier.public, mod_name, Scope(self.ctx.universe), is_pkg
AccessModifier.public, mod_name, Scope(self.ctx.universe, True),
is_pkg
)
self.source_file = SourceFile(
self.file, self.transform(bs_parser.parse(open(file).read())),
Expand Down Expand Up @@ -67,8 +68,8 @@ def mod_decl(self, *nodes):
if not is_inline:
pos += nodes[2].pos
mod_sym = Module(
access_modifier, nodes[2].name, Scope(self.mod_sym, True), False,
is_inline
access_modifier, nodes[2].name, Scope(self.mod_sym.scope, True),
False, is_inline
)
return ModDecl(
access_modifier, nodes[2].name, is_inline, decls, pos, mod_sym
Expand Down Expand Up @@ -108,7 +109,7 @@ def fn_decl(self, *nodes):
ret_type = self.ctx.void_type
stmts = []
if nodes[-1] == None:
stmts = None
stmts = None
else:
stmts = nodes[-1]
return FnDecl(
Expand All @@ -129,15 +130,12 @@ def fn_body(self, *nodes):
stmts = list(nodes[1:-1])
return stmts

# Statements
def var_decl(self, *nodes):
lefts = [nodes[1]]
if len(nodes) != 4:
lefts += list(
filter(lambda n: not isinstance(n, Token), nodes[2:-2])
)
pos = self.mkpos(nodes[1])
access_modifier = self.get_access_modifier(nodes[0])
lefts = list(filter(lambda n: isinstance(n, VarIdent), nodes[2:-2]))
right = nodes[-1]
return VarDecl(lefts, right)
return VarDecl(access_modifier, lefts, right, pos)

def var_ident(self, *nodes):
typ = None
Expand All @@ -148,6 +146,8 @@ def var_ident(self, *nodes):
pos += self.mkpos(nodes[2])
return VarIdent(nodes[0].name, typ, pos)

# Statements

def assignment(self, *nodes):
lefts = []
op_assign = ""
Expand Down
13 changes: 13 additions & 0 deletions bsc/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,16 @@ def error(msg, pos):

def warn(msg, pos):
utils.eprint(_format(pos, "warning:", utils.yellow, msg))

def notes(notes):
for i, note in enumerate(notes):
_char = "└" if i == len(notes) - 1 else "├"
utils.eprint(utils.bold(utils.cyan(f" {_char} note: ")) + note)

def error_from_ce(ce, pos):
error(ce.args[0], pos)
notes(ce.args[1:])

def warn_from_ce(ce, pos):
warn(ce.args[0], pos)
notes(ce.args[1:])
44 changes: 29 additions & 15 deletions bsc/sema.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ def __init__(self, ctx):
self.first_pass = True

self.cur_file = None
self.cur_pkg = None
self.cur_mod = None
self.cur_pkg = None # is used for the expression `pkg::`
self.cur_mod = None # is used for the expression `self::`

self.cur_sym = None
self.cur_scope = self.ctx.universe
self.old_scope = None
Expand Down Expand Up @@ -51,15 +52,18 @@ def check_decl(self, decl):

def check_mod_decl(self, decl):
old_sym = self.cur_sym
old_mod = self.cur_mod
if self.first_pass:
decl.sym.parent = self.cur_sym
if decl.is_inline:
self.add_sym(decl.sym, decl.pos)
self.cur_sym = decl.sym
self.cur_scope = decl.sym.scope
self.check_decls(decl.decls)
self.close_scope()
self.cur_sym = old_sym
self.cur_mod = decl.sym
self.cur_sym = decl.sym
self.cur_scope = decl.sym.scope
self.check_decls(decl.decls)
self.cur_sym = old_sym
self.cur_mod = old_mod
self.close_scope()
return
self.check_decls(decl.decls)

Expand All @@ -79,28 +83,38 @@ def check_enum_decl(self, decl):
report.error(f"enum `{decl.name}` cannot be empty", decl.pos)

def check_fn_decl(self, decl):
old_sym = self.cur_sym
if self.first_pass:
decl.sym = Function(
decl.access_modifier, decl.name, [], self.open_scope()
)
self.add_sym(decl.sym, decl.pos)
if decl.has_body:
self.cur_sym = decl.sym
self.cur_scope = decl.sym.scope
self.check_stmts(decl.stmts)
self.close_scope()
self.cur_sym = old_sym
self.close_scope()
return
if decl.has_body:
if decl.has_body:
self.check_stmts(decl.stmts)

def check_var_decl(self, stmt):
for left in stmt.lefts:
print(left)

if self.first_pass:
for left in stmt.lefts:
self.add_sym(
Object(
stmt.access_modifier, left.name, ObjectLevel.local,
left.typ, self.cur_scope
), left.pos
)

## === Statements ===================================

def check_stmts(self, stmts):
for stmt in stmts:
self.check_stmt(stmt)

def check_stmt(self, stmt):
if isinstance(stmt, VarDecl):
self.check_var_decl(stmt)
Expand All @@ -111,7 +125,7 @@ def add_sym(self, sym, pos):
try:
self.cur_sym.scope.add_sym(sym)
except utils.CompilerError as e:
report.error(e.args[0], pos)
report.error_from_ce(e, pos)

def open_scope(self, detach_from_parent = False):
self.cur_scope = Scope(self.cur_scope, detach_from_parent)
Expand Down
23 changes: 15 additions & 8 deletions bsc/sym.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ def __init__(self, access_modifier, name):
self.name = name

def typeof(self):
if isinstance(self, Object):
return "variable"
if isinstance(self, Module):
return "package" if self.is_pkg else "module"
elif isinstance(self, Const):
return "constant"
elif isinstance(self, TypeSym):
return self.type_kind()
elif isinstance(self, Module):
return "package" if self.is_pkg else "module"
elif isinstance(self, Function):
return "function"
elif isinstance(self, Object):
return "variable"
return "symbol"

def qualname(self, sep = "::"):
Expand Down Expand Up @@ -83,7 +85,6 @@ def __init__(self, access_modifier, name, level, typ, scope):
super().__init__(access_modifier, name)
self.level = level
self.typ = typ
scope.owner = self
self.scope = scope

def is_local(self):
Expand All @@ -94,7 +95,6 @@ def __init__(self, access_modifier, name, typ, expr, scope):
super().__init__(access_modifier, name)
self.typ = typ
self.expr = expr
scope.owner = self
self.scope = scope

class TypeKind(IntEnum):
Expand Down Expand Up @@ -179,6 +179,9 @@ class Scope:
def __init__(
self, parent = None, detach_from_parent = False, is_universe = False
):
assert parent == None or isinstance(
parent, Scope
), f"parent is {parent}"
self.parent = parent
self.owner = None
self.syms = []
Expand All @@ -201,11 +204,15 @@ def dont_lookup_scope(self):
return self.parent == None or self.detached_from_parent

def add_sym(self, sym):
if _ := self.lookup(sym.name):
if duplicate := self.lookup(sym.name):
if self.owner:
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)
if duplicate.__class__ == sym.__class__:
note = f"another {duplicate.typeof()} with the same name was defined before"
else:
note = f"a {duplicate.typeof()} with the same name has already been defined"
raise CompilerError(errmsg, note)
sym.parent = self.owner
self.syms.append(sym)
13 changes: 0 additions & 13 deletions tests/sema.bs

This file was deleted.

0 comments on commit 18764bf

Please sign in to comment.