diff --git a/bsc/AST.py b/bsc/AST.py index c663da7..d14b07b 100644 --- a/bsc/AST.py +++ b/bsc/AST.py @@ -147,13 +147,17 @@ def __str__(self): return f"{', '.join([str(left) for left in self.lefts])} {self.op} {str(self.right)}" class WhileStmt: - def __init__(self, cond, stmt, pos): + def __init__(self, cond, stmts, pos): self.cond = cond - self.stmt = stmt + self.stmts = stmts self.pos = pos def __str__(self): - return f"while ({self.cond}) {self.stmt}" + res = f"while {self.cond} {{\n" + for stmt in self.stmts: + res += f" {stmt}\n" + res += "}" + return res class BlockStmt: def __init__(self, stmts, pos): @@ -439,21 +443,27 @@ def __str__(self): s = "" for i, branch in enumerate(self.branches): if branch.is_else: - s += f"else {branch.stmt}" + s += " else {\n" + for stmt in branch.stmts: + s += f" {stmt}\n" + s += "}" break if i > 0: - s += "else " - s += f"if ({branch.cond}) {branch.stmt}" + "\n" + s += " else " + s += f"if {branch.cond} {{\n" + for stmt in branch.stmts: + s += f" {stmt}\n" + s += "}" return s def __repr__(self): return str(self) class IfBranch: - def __init__(self, cond, is_else, stmt, pos): + def __init__(self, cond, is_else, stmts, pos): self.cond = cond self.is_else = is_else - self.stmt = stmt + self.stmts = stmts self.pos = pos class MatchExpr: @@ -464,7 +474,7 @@ def __init__(self, expr, branches, pos): def __str__(self): if self.expr: - s = f"match ({self.expr}) {{\n" + s = f"match {self.expr} {{\n" else: s = "match {\n" for i, branch in enumerate(self.branches): diff --git a/bsc/astgen.py b/bsc/astgen.py index 0fea830..ae7c0cf 100644 --- a/bsc/astgen.py +++ b/bsc/astgen.py @@ -111,10 +111,10 @@ def fn_decl(self, *nodes): ) or isinstance(ret_type, Token) or not ret_type: ret_type = self.ctx.void_type stmts = [] - if nodes[-1] == None: - stmts = None - else: + if nodes[-1]: stmts = nodes[-1] + else: + stmts = None return FnDecl( access_modifier, name, args, is_method, ret_type, stmts, name == "main" and self.file == self.ctx.prefs.input, pos @@ -127,12 +127,6 @@ def fn_args(self, *nodes): def fn_arg(self, *nodes): return FnArg(nodes[0].name, nodes[2], nodes[-1]) - def fn_body(self, *nodes): - stmts = [] - if len(nodes) != 2: - stmts = list(nodes[1:-1]) - return stmts - def var_decl(self, *nodes): pos = self.mkpos(nodes[1]) access_modifier = self.get_access_modifier(nodes[0]) @@ -189,14 +183,14 @@ def op_assign(self, *nodes): return op_assign def block(self, *nodes): + return list(nodes[1:-1]) + + def block_stmt(self, *nodes): stmts = list(nodes[1:-1]) return BlockStmt(stmts, self.mkpos(nodes[0]) + self.mkpos(nodes[-1])) def while_stmt(self, *nodes): - return WhileStmt( - nodes[1], nodes[3], - self.mkpos(nodes[0]) + nodes[-1].pos - ) + return WhileStmt(nodes[1], nodes[2], self.mkpos(nodes[0])) # Expressions def par_expr(self, *nodes): @@ -438,29 +432,19 @@ def if_expr(self, *nodes): return IfExpr(list(nodes), nodes[0].pos + nodes[-1].pos) def if_header(self, *nodes): - cond = nodes[2] - stmt = nodes[4] - return IfBranch(cond, False, stmt, self.mkpos(nodes[0]) + nodes[-1].pos) + return IfBranch(nodes[1], False, nodes[2], self.mkpos(nodes[0])) def else_if_expr(self, *nodes): - cond = nodes[3] - stmt = nodes[5] - return IfBranch(cond, False, stmt, self.mkpos(nodes[0]) + nodes[-1].pos) + return IfBranch(nodes[2], False, nodes[3], self.mkpos(nodes[0])) def else_stmt(self, *nodes): - return IfBranch( - None, True, nodes[1], - self.mkpos(nodes[0]) + nodes[-1].pos - ) + return IfBranch(None, True, nodes[1], self.mkpos(nodes[0])) def match_expr(self, *nodes): expr = None if nodes[1]: - expr = nodes[2] - return MatchExpr( - expr, nodes[5], - self.mkpos(nodes[0]) + self.mkpos(nodes[-1]) - ) + expr = nodes[1] + return MatchExpr(expr, nodes[3], self.mkpos(nodes[0])) def match_branches(self, *nodes): branches = [] @@ -481,7 +465,7 @@ def match_branch(self, *nodes): for case in nodes: if str(case) == ",": continue - if str(case) == "->": + if str(case) == "=>": break cases.append(case) stmt = nodes[-1] diff --git a/bsc/grammar.lark b/bsc/grammar.lark index 53573f8..ca279aa 100644 --- a/bsc/grammar.lark +++ b/bsc/grammar.lark @@ -39,16 +39,15 @@ var_ident: NAME [COLON type] const_decl: [access_modifier] KW_CONST NAME [COLON type] OP_ASSIGN expr -enum_decl: [access_modifier] KW_ENUM NAME LBRACE (enum_field)* RBRACE +enum_decl: [access_modifier] KW_ENUM NAME LBRACE enum_field* decl* RBRACE enum_field: NAME [OP_ASSIGN expr] class_decl: [access_modifier] KW_CLASS NAME LBRACE (class_field | decl)* RBRACE class_field: [access_modifier] NAME COLON type [OP_ASSIGN expr] -fn_decl: [access_modifier] KW_FN NAME LPAREN [fn_args] RPAREN [BANG | type] [fn_body] +fn_decl: [access_modifier] KW_FN NAME LPAREN [fn_args] RPAREN [BANG | type] [block] fn_args: (KW_SELF | fn_arg) (COMMA fn_arg)* fn_arg: NAME COLON type [OP_ASSIGN expr] -fn_body: LBRACE stmt* RBRACE access_modifier: KW_PUB [LPAREN KW_PKG RPAREN] | KW_PROT @@ -72,10 +71,12 @@ primitive_type: "any" | var_decl | const_decl | assignment - | block - | KW_WHILE LPAREN expr RPAREN stmt -> while_stmt + | block_stmt + | KW_WHILE expr block -> while_stmt + +block: LBRACE stmt* RBRACE // returns array of stmts in AstGen +block_stmt: LBRACE stmt* RBRACE // returns BlockStmt in AstGen -block: LBRACE stmt* RBRACE assignment: expr (COMMA expr)* op_assign expr op_assign: OP_ASSIGN | OP_ASSIGN @@ -124,11 +125,11 @@ par_expr: LPAREN expr RPAREN path_expr: NAME (DOUBLE_COLON NAME)* if_expr: if_header else_if_expr* else_stmt? -if_header: KW_IF LPAREN expr RPAREN stmt -else_if_expr: KW_ELSE KW_IF LPAREN expr RPAREN stmt -else_stmt: KW_ELSE stmt +if_header: KW_IF expr block +else_if_expr: KW_ELSE KW_IF expr block +else_stmt: KW_ELSE block -match_expr: KW_MATCH [LPAREN expr RPAREN] LBRACE match_branches RBRACE +match_expr: KW_MATCH [expr] LBRACE match_branches RBRACE match_branches: match_branch (COMMA match_branch)* match_branch: expr (COMMA expr)* ARROW stmt | KW_ELSE ARROW stmt @@ -155,7 +156,7 @@ DIV: "/" MOD: "%" AT: "@" SLASH: "/" -ARROW: "->" +ARROW: "=>" COMMA: "," DOT: "." DOUBLE_COLON: "::" diff --git a/bsc/lua_ast/render.py b/bsc/lua_ast/render.py index 8b0e6e3..de58fd4 100644 --- a/bsc/lua_ast/render.py +++ b/bsc/lua_ast/render.py @@ -61,7 +61,7 @@ def render_mod(self, decl): self.writeln(f"-- end module `{decl.name}`\n") else: self.writeln( - f"{decl.name} = require(\"bsc-out.{decl.lua_filename}\") -- load module file\n" + f"{decl.name} = require(\"{BSC_OUT_DIR}.{decl.lua_filename}\") -- load module file\n" ) def render_table(self, decl): diff --git a/tests/syntax.bs b/tests/syntax.bs index 5e99393..6718a49 100644 --- a/tests/syntax.bs +++ b/tests/syntax.bs @@ -35,6 +35,15 @@ enum WorldLevel { midgard underworld undefined = 0xFF + + fn from_string(s: string) Self { + return match s { + "overworld" => .overworld, + "midgard" => .midgard, + "underworld" => .underworld, + else => .undefined + } + } } class Person { @@ -72,24 +81,28 @@ fn init() { println("Hello World!") _ = math.pow(2) std.my_func() - if (true) q = 3 - if (false) { - s = if (true) { + if true { + q = 3 + } + if false { + s = if true { 99 - } else if (99) { + } else if 99 { 99 } else { 100 } } - while (nil) m += 4 - match (name) { - "holaa" -> m = 99, - "wb", "js" -> m = 1000, - else -> exit + while nil { + m += 4 + } + match name { + "holaa" => m = 99, + "wb", "js" => m = 1000, + else => exit } match { - true -> true, - false -> false + true => true, + false => false } }