Skip to content

Commit

Permalink
grammar,astgen: support enum declaration
Browse files Browse the repository at this point in the history
  • Loading branch information
StunxFS committed Jun 7, 2024
1 parent e603125 commit f0ada88
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 42 deletions.
16 changes: 15 additions & 1 deletion bsc/AST.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,22 @@ def __init__(self, name, is_inline, decls, pos):
self.pos = pos
self.sym = None

class EnumDecl:
def __init__(self, access_modifier, name, fields, pos):
self.access_modifier = access_modifier
self.name = name
self.fields = fields
self.pos = pos

class EnumField:
def __init__(self, name, value):
self.name = name
self.value = value

class FnDecl:
def __init__(
self, access_modifier, name, args, is_method, ret_type, stmts, is_main
self, access_modifier, name, args, is_method, ret_type, stmts, is_main,
pos
):
self.access_modifier = access_modifier
self.name = name
Expand All @@ -60,6 +73,7 @@ def __init__(
self.stmts = stmts
self.is_main = is_main
self.sym = None
self.pos = pos

class FnArg:
def __init__(self, name, type, default_value):
Expand Down
24 changes: 19 additions & 5 deletions bsc/astgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,23 @@ def mod_decl(self, *nodes):
pos += self.mkpos(nodes[-1])
return ModDecl(nodes[2].name, is_inline, decls, pos)

def enum_decl(self, *nodes):
pos = self.mkpos(nodes[1])
access_modifier = self.get_access_modifier(nodes[0])
name = nodes[2].name
enum_fields = []
for node in nodes[4:]:
if str(node) == "}":
break
enum_fields.append(node)
return EnumDecl(access_modifier, name, enum_fields, pos)

def enum_field(self, *nodes):
return EnumField(nodes[0].name, nodes[-1])

def fn_decl(self, *nodes):
access_modifier = self.access_modifier(nodes[0])
pos = self.mkpos(nodes[1])
access_modifier = self.get_access_modifier(nodes[0])
name = nodes[2].name
args = nodes[4]
if isinstance(args, Token):
Expand All @@ -83,7 +98,7 @@ def fn_decl(self, *nodes):
stmts = None
return FnDecl(
access_modifier, name, args, is_method, ret_type, stmts,
name == "main" and self.file == self.ctx.prefs.input
name == "main" and self.file == self.ctx.prefs.input, pos
)

def fn_args(self, *nodes):
Expand Down Expand Up @@ -162,7 +177,7 @@ def block(self, *nodes):
def while_stmt(self, *nodes):
return WhileStmt(
nodes[1], nodes[3],
self.mkpos(nodes[0]) + self.mkpos(nodes[-1])
self.mkpos(nodes[0]) + nodes[-1].pos
)

# Expressions
Expand Down Expand Up @@ -438,7 +453,7 @@ def match_branch(self, *nodes):
is_else = str(nodes[0]) == "else"
cases = []
if is_else:
pos = nodes[0].pos
pos = self.mkpos(nodes[0])
stmt = nodes[2]
else:
pos = nodes[0].pos
Expand Down Expand Up @@ -505,7 +520,6 @@ def sum_type(self, *nodes):

# Utilities
def get_access_modifier(self, node):
print(node)
_access_modifier = AccessModifier.private
if isinstance(node, AccessModifier):
_access_modifier = node
Expand Down
51 changes: 28 additions & 23 deletions bsc/grammar.lark
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module: extern_pkg* decl*
| mod_decl
| var_decl
| const_decl
| enum_decl
| class_decl
| fn_decl

Expand All @@ -38,6 +39,9 @@ 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_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]

Expand Down Expand Up @@ -134,13 +138,13 @@ match_branch: expr (COMMA expr)* ARROW stmt
| KW_SELF
| NAME
bool_lit: KW_TRUE | KW_FALSE
number_lit: NUMBER | BIN_NUMBER | OCT_NUMBER | HEX_NUMBER
number_lit: BIN_NUMBER | OCT_NUMBER | HEX_NUMBER | NUMBER

// Tokens

BIN_NUMBER: /0b?[0-1]*l?/i
OCT_NUMBER: /0o?[0-7]*l?/i
HEX_NUMBER: /0x[\da-f]*l?/i
BIN_NUMBER.2: /0b[0-1]*l?/i
OCT_NUMBER.2: /0o[0-7]*l?/i
HEX_NUMBER.2: /0x[\da-f]*l?/i

PLUS: "+"
MINUS: "-"
Expand Down Expand Up @@ -189,23 +193,24 @@ OP_BIT_AND_ASSIGN: "&="
OP_BIT_OR_ASSIGN: "|="
OP_BIT_XOR_ASSIGN: "^="

KW_AS.10: "as"
KW_CLASS.10: "class"
KW_CONST.10: "const"
KW_ELSE.10: "else"
KW_EXTERN.10: "extern"
KW_FALSE.10: "false"
KW_FN.10: "fn"
KW_IF.10: "if"
KW_MATCH.10: "match"
KW_MOD.10: "mod"
KW_NIL.10: "nil"
KW_PKG.10: "pkg"
KW_PROT.10: "prot"
KW_PUB.10: "pub"
KW_SELF.10: "self"
KW_TRUE.10: "true"
KW_USE.10: "use"
KW_VAR.10: "var"
KW_WHILE.10: "while"
KW_AS.1: "as"
KW_CLASS.1: "class"
KW_CONST.1: "const"
KW_ELSE.1: "else"
KW_ENUM.1: "enum"
KW_EXTERN.1: "extern"
KW_FALSE.1: "false"
KW_FN.1: "fn"
KW_IF.1: "if"
KW_MATCH.1: "match"
KW_MOD.1: "mod"
KW_NIL.1: "nil"
KW_PKG.1: "pkg"
KW_PROT.1: "prot"
KW_PUB.1: "pub"
KW_SELF.1: "self"
KW_TRUE.1: "true"
KW_USE.1: "use"
KW_VAR.1: "var"
KW_WHILE.1: "while"

18 changes: 16 additions & 2 deletions bsc/lua_ast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ def __init__(self, name):
self.name = name
self.decls = []

class LuaIdent:
def __init__(self, name):
class LuaTableField:
def __init__(self, name, value):
self.name = name
self.value = value

class LuaTable:
def __init__(self, is_local, name, fields):
self.is_local = is_local
self.name = name
self.fields = fields

class LuaFunction:
def __init__(self, name, args):
Expand All @@ -20,3 +27,10 @@ def __init__(self, name, args):
class LuaBlock:
def __init__(self):
self.chunk = []

class LuaIdent:
def __init__(self, name):
self.name = name

class LuaNil:
pass
2 changes: 1 addition & 1 deletion bsc/lua_ast/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# LICENSE file.

import os
from bsc import utils
from bsc import sym, utils
from bsc.lua_ast import *

class LuaRender:
Expand Down
17 changes: 17 additions & 0 deletions bsc/report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (C) 2024 Jose Mendoza. All rights reserved. Use of this
# source code is governed by an MIT license that can be found in the
# LICENSE file.

from bsc import utils

def _format(pos, kind, kindc, msg):
return "{}:{}:{}: {}".format(
pos.file, pos.line, pos.column,
kindc(kind) + msg
)

def error(msg, pos):
utils.eprint(_format(pos, "error: ", utils.red, msg))

def warn(msg, pos):
utils.eprint(_format(pos, "warning: ", utils.yellow, msg))
26 changes: 21 additions & 5 deletions bsc/sema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from bsc.AST import *
from bsc.sym import *
from bsc import utils
from bsc import utils, report

class Sema:
def __init__(self, ctx):
Expand Down Expand Up @@ -36,24 +36,40 @@ def check_decls(self, decls):
self.check_decl(decl)

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

def check_enum_decl(self, decl):
if self.first_pass:
fields = []
for i, field in enumerate(decl.fields):
fields.append((field.name, i))
decl.sym = TypeSym(
decl.access_modifier, TypeKind.enum, decl.name, [],
self.open_scope(), info = EnumInfo(fields)
)
self.add_sym(decl.sym, decl.pos)
return
if len(decl.fields) == 0:
report.error(f"enum `{decl.name}` cannot be empty", decl.pos)

def check_fn_decl(self, decl):
if self.first_pass:
decl.sym = Function(
decl.access_modifier, decl.name, [], self.open_scope()
)
self.add_sym(decl.sym)
self.add_sym(decl.sym, decl.pos)
return

## === Utilities ====================================

def add_sym(self, sym):
def add_sym(self, sym, pos):
try:
self.cur_sym.scope.add_sym(sym)
except utils.CompilerError as e:
utils.error(e.args[0])
report.error(e.args[0], pos)

def open_scope(self, detach_from_parent = False):
self.cur_scope = Scope(self.cur_scope, detach_from_parent)
Expand Down
16 changes: 15 additions & 1 deletion bsc/sym.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ class AccessModifier(IntEnum):
public = auto()
protected = auto()

def is_public(self):
self == AccessModifier.public

def is_private(self):
return self == AccessModifier.private or self == AccessModifier.protected

def __str__(self):
match self:
case AccessModifier.private:
Expand Down Expand Up @@ -81,6 +87,7 @@ class TypeKind(IntEnum):
map = auto()
tuple = auto()
sumtype = auto()
enum = auto()
_class = auto()

def __str__(self):
Expand All @@ -103,11 +110,17 @@ def __str__(self):
return "tuple"
case TypeKind.sumtype:
return "sumtype"
case TypeKind.enum:
return "enum"
case TypeKind._class:
return "class"
case _:
assert False # unreachable

class EnumInfo:
def __init__(self, fields):
self.fields = fields

class TypeField:
def __init__(self, access_modifier, name, typ, default_value):
self.access_modifier = access_modifier
Expand All @@ -116,9 +129,10 @@ def __init__(self, access_modifier, name, typ, default_value):
self.default_value = default_value

class TypeSym(Sym):
def __init__(self, access_modifier, kind, name, fields, scope):
def __init__(self, access_modifier, kind, name, fields, scope, info = None):
super().__init__(access_modifier, name)
self.kind = kind
self.info = info
self.fields = fields
scope.owner = self
self.scope = scope
Expand Down
5 changes: 1 addition & 4 deletions examples/syntax.bs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,12 @@ class Item {}

pub fn sumtype(x: number | string | Item) {}

/*
enum WorldLevel {
overworld
midgard
underworld
undefined = 0x0
undefined = 0xFF
}
*/

class Person {
name: string
Expand Down Expand Up @@ -92,4 +90,3 @@ fn main() {
false -> false
}
}

0 comments on commit f0ada88

Please sign in to comment.