Skip to content

Commit

Permalink
sema: check AST.PathExpr
Browse files Browse the repository at this point in the history
  • Loading branch information
StunxFS committed Jul 4, 2024
1 parent c0a70b1 commit 8d09fa8
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 18 deletions.
File renamed without changes.
2 changes: 2 additions & 0 deletions bsc/astgen/AST.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ def __init__(self, left, name, pos):
self.left = left
self.name = name
self.pos = pos
self.left_sym = None
self.sym = None
self.typ = None

def __str__(self):
Expand Down
4 changes: 3 additions & 1 deletion bsc/astgen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,18 @@ def fn_decl(self, *nodes):
args = []
ret_type = nodes[6]
is_result = isinstance(ret_type, Token) and str(ret_type) == "!"
body_idx = 8
if is_result:
ret_type = nodes[7]
if isinstance(ret_type,
BlockExpr) or isinstance(ret_type,
Token) or (not ret_type):
body_idx += 1
ret_type = self.ctx.void_type
if is_result:
ret_type = ResultType(ret_type, self.mkpos(nodes[6]))
stmts = []
if len(nodes) == 8:
if len(nodes) == body_idx:
stmts = nodes[-1]
else:
stmts = None
Expand Down
36 changes: 34 additions & 2 deletions bsc/sema.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,18 @@ def check_expr(self, expr):
expr.typ = sym.typ
else:
report.error(
f"expected value, found {sym.typeof()} `{sym.name}`",
f"expected value, found {sym.kind_of()} `{sym.name}`",
expr.pos
)
elif isinstance(expr, PathExpr):
expr.typ = self.ctx.void_type
self.check_path_expr(expr)
if expr.sym != None:
if isinstance(expr.sym, (Object, Const)):
expr.typ = expr.sym.typ
else:
report.error(
f"expected value, found {expr.sym.kind_of()} `{expr.sym.name}`",
expr.pos
)
elif isinstance(expr, BlockExpr):
Expand Down Expand Up @@ -299,6 +310,27 @@ def check_expr(self, expr):
expr.typ = self.ctx.void_type # tmp
return expr.typ

def check_path_expr(self, expr: PathExpr):
if isinstance(expr.left, Ident):
expr.left_sym = self.check_symbol(expr.left.name, expr.pos)
elif isinstance(expr.left, PathExpr):
expr.left_sym = self.check_path_expr(expr.left)
else:
report.error(
"invalid expression on left side of path", expr.left.pos
)

if expr.left_sym == None:
return

if path_sym := expr.left_sym.scope.find(expr.name):
expr.sym = path_sym
else:
report.error(
f"{expr.left_sym.kind_of()} `{expr.left_sym}` does not contain a symbol named `{expr.name}`",
expr.pos
)

## === Symbols ======================================

def check_symbol(self, name, pos):
Expand All @@ -313,7 +345,7 @@ def check_symbol(self, name, pos):
report.error(f"cannot find symbol `{name}` in this scope", pos)
if ret_sym != None and ret_sym.pos != None and ret_sym.pos.line > pos.line:
report.error(
f"{ret_sym.typeof()} `{ret_sym.name}` is used before its declaration",
f"{ret_sym.kind_of()} `{ret_sym.name}` is used before its declaration",
pos
)
return ret_sym
Expand Down
23 changes: 14 additions & 9 deletions bsc/sym.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ def __init__(self, access_modifier, name, pos = None):
self.name = name
self.pos = pos

def typeof(self):
def kind_of(self):
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()
return self.kind_of()
elif isinstance(self, Function):
return "function"
elif isinstance(self, Object):
Expand Down Expand Up @@ -181,7 +181,7 @@ def __init__(
scope.owner = self
self.scope = scope

def type_kind(self):
def kind_of(self):
return str(self.kind)

class Module(Sym):
Expand Down Expand Up @@ -225,12 +225,17 @@ def __init__(
self.detached_from_parent = detach_from_parent
self.is_universe = is_universe

def find(self, name):
for sym in self.syms:
if sym.name == name:
return sym
return None

def lookup(self, name):
sc = self
while True:
for sym in sc.syms:
if sym.name == name:
return sym
if sym := sc.find(name):
return sym
if sc.dont_lookup_scope():
break
sc = sc.parent
Expand All @@ -242,7 +247,7 @@ def dont_lookup_scope(self):
def add_sym(self, sym):
if duplicate := self.lookup(sym.name):
if self.owner:
errmsg = f"duplicate symbol `{sym.name}` in {self.owner.typeof()} `{self.owner}`"
errmsg = f"duplicate symbol `{sym.name}` in {self.owner.kind_of()} `{self.owner}`"
else:
errmsg = f"duplicate symbol `{sym.name}` in global namespace"
if duplicate.__class__ == sym.__class__:
Expand All @@ -251,9 +256,9 @@ def add_sym(self, sym):
) and duplicate.level == ObjectLevel.argument:
note = f"another argument with the same name was already declared previously"
else:
note = f"another {duplicate.typeof()} with the same name was defined before"
note = f"another {duplicate.kind_of()} with the same name was defined before"
else:
note = f"a {duplicate.typeof()} with the same name has already been defined"
note = f"a {duplicate.kind_of()} with the same name has already been defined"
raise CompilerError(errmsg, note)
sym.parent = self.owner
self.syms.append(sym)
11 changes: 11 additions & 0 deletions tests/invalid_code/path_expr.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mod my_mod {
const XXX = 1;

enum Afk { a }
}

fn main() {
const ABC = my_mod::XXX; // ok
const DEF = my_mod::Afk; // error
const GHI = my_mod::unown; // error
}
2 changes: 2 additions & 0 deletions tests/invalid_code/path_expr.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tests/invalid_code/path_expr.bs:9:25: error: expected value, found enum `Afk`
tests/invalid_code/path_expr.bs:10:25: error: module `path_expr::my_mod` does not contain a symbol named `unown`
16 changes: 10 additions & 6 deletions tests/main.bs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
mod syntax;

const dec_num = 616;
const hex_num = 0xFFFF;
const bin_num = 0b10101;
const octal_num = 0o666;
const float_num = 0.5e4;
mod consts {
const dec_num = 616;
const hex_num = 0xFFFF;
const bin_num = 0b10101;
const octal_num = 0o666;
const float_num = 0.5e4;

fn main() {}
}

const f = 1.0 / 2.0;
const i = 1 / 2;

fn main() void {
print("hello");
const XXX = dec_num;
const XXX = consts::main;
}

pub(pkg) fn my_fn(a: float) {}
Expand Down

0 comments on commit 8d09fa8

Please sign in to comment.