Compare commits

...

3 Commits

Author SHA1 Message Date
Kyler 52225d49df Started code generation 2024-07-09 02:47:20 -06:00
Kyler b950ff80a2 Small changes 2024-07-09 01:03:02 -06:00
Kyler d9b891216d Added Semantical Analysis of Enums 2024-07-09 00:23:00 -06:00
7 changed files with 436 additions and 173 deletions

View File

@ -107,6 +107,10 @@ loop:
## High Level Language: *DuoDeca-Script* ## High Level Language: *DuoDeca-Script*
![DuoDeca-Script Logo](./docs/DuoDeca-Script_Logo_Small.png) ![DuoDeca-Script Logo](./docs/DuoDeca-Script_Logo_Small.png)
<br/><small>
Yes, you may cringe that I used Comic Sans in my logo.
I do when others do so. &lt;3 Kyler
</small>
### About ### About
- Name: DuoDeca-Script - Name: DuoDeca-Script

View File

@ -12,7 +12,7 @@ struct Point {
random: @int random: @int
} }
enum Colors { RED, GREEN, BLUE = 7 } enum Colors { RED, GREEN, BLUE = 5 , PINK, VIOLET = 3, PURPLE = 3, INDIGO, GREY }
fn test_func(arg1: int, arg2: unsigned = 10) -> fixed { fn test_func(arg1: int, arg2: unsigned = 10) -> fixed {
let var1: float; let var1: float;

21
examples/test_fib.duox Normal file
View File

@ -0,0 +1,21 @@
// Kyler Olsen
// Source Code Test 3
// Fibonacci
// DuoDeca-Script Test
fn unused_func() -> int {unused_func = 0;}
fn main() -> int {
main = 0;
let a: unsigned = 0;
let b: unsigned = 0;
let c: unsigned = 0;
let out: @unsigned = 0x7FD;
while (True) {
$out = a;
c = b;
b = a;
a = b + c;
}
}

View File

@ -0,0 +1,157 @@
# Kyler Olsen
# Jul 2024
from datetime import datetime
from .compiler_types import CompilerError
from . import syntactical_analyzer as sya
from . import semantical_analyzer as sma
CODE = (0x000, 0x6ff)
IO = (0x700, 0x7ff)
RAM = (0x800, 0xfff)
class CodeGenerationError(Exception): pass
class CodeGenerationNotImplemented(CompilerError):
_compiler_error_type = "Code Generation"
class _State:
memory: dict[sma.Symbol, int]
local: dict[sma.Symbol, int]
registers: dict[str, sma.Symbol | None]
_register_rotation: int
def __init__(self):
self.memory = dict()
self.local = dict()
self.registers = {
'D0': None,
'D1': None,
'D2': None,
'D3': None,
}
self._register_rotation = 0
@property
def register_rotation(self) -> str:
for reg in self.registers:
if self.registers[reg] is None:
return reg
else:
try: return f"D{self._register_rotation}"
finally:
self._register_rotation += 1
self._register_rotation %= 4
def store_symbol(self, reg: str) -> str:
code = ""
symbol = self.registers[reg]
if symbol in self.local:
code += f"ldi {self.local[symbol]}\n"
code += "add MP SP MP\n"
code += f"str {reg}\n"
elif symbol in self.memory:
code += f"ldi {self.memory[symbol]}\n"
code += f"str {reg}\n"
return code
def load_symbol(self, symbol: sma.Symbol, reg: str | None = None) -> str:
code = ""
if reg is None:
reg = self.register_rotation
if self.registers[reg] is not None:
self.store_symbol(reg)
if symbol in self.local:
code += f"ldi {self.local[symbol]}\n"
code += "add MP SP MP\n"
code += f"lod {reg}\n"
elif symbol in self.memory:
code += f"ldi {self.memory[symbol]}\n"
code += f"lod {reg}\n"
else: raise CodeGenerationError(
f"Can not find memory of symbol: {symbol.name} ({hash(symbol)})")
return code
def gen_binary_exprs(self, expression: sya.BinaryExpression) -> str:
pass
def gen_block(self, block: sma.CodeBlock) -> str:
code = ""
# for statement in block.code:
# if isinstance(statement, sya.BinaryExpression):
# code += self.gen_binary_exprs(statement)
return code
def gen_while(self, func: sma.WhileBlock) -> str:
pass
def gen_func(self, func: sma.FunctionBlock) -> str:
self.local = dict()
memory = 0
for symbol in func.symbol_table.symbols:
self.local[symbol] = memory
memory += 1
code = f"{func.identifier.content}:\n"
code += f"\n; Initializing stack for function:"
code += f" {func.identifier.content}\nldi {memory}\n"
code += "sub SP SP MP\n\n"
for symbol in func.symbol_table.symbols:
if (
isinstance(symbol.definition, sya.LetStatement) and
symbol.definition.assignment is not None
):
if isinstance(symbol.definition.assignment, sya.StringLiteral):
raise CodeGenerationNotImplemented(
"Code Generation not yet implemented for "
"loading string literals",
symbol.definition.assignment.file_info,
)
else:
code += f"; Loading initial value for {symbol.name}\n"
code += f"ldi {symbol.definition.assignment.value}\n"
code += "sub SP SP MP\n"
code += self.gen_block(func.code)
code += "\n; Uninitializing stack for function:"
code += f" {func.identifier.content}\nldi {memory}\n"
code += "add SP SP MP\n"
return code
def code_generator(self, syntax_tree: sma.File, entry_name: str) -> str:
memory = RAM[0]
for symbol in syntax_tree.symbol_table.symbols:
if symbol.symbol_type == sma.SymbolType.variable:
self.memory[symbol] = memory
memory += 1 #symbol.definition.size
code = "; Generated by `pytd12dk` compiler\n"
code += f"; {datetime.now().isoformat()}\n"
code += "; Global variables use "
code += f"{memory - RAM[0]}/{RAM[1] - RAM[0]} bytes\n"
code += "\n.0x0\n"
code += f"ldi {RAM[1]}\nor SP MP ZR\n"
code += f"ldi :{entry_name}\nor PC MP ZR\n"
for child in syntax_tree.children:
if isinstance(child, sma.FunctionBlock):
code += f"\n{self.gen_func(child)}\n"
else:
raise CodeGenerationNotImplemented(
"Code Generation not yet implemented for: "
f"{child.__class__.__name__}.",
child.file_info,
)
return code
def code_generator(syntax_tree: sma.File, entry_name: str = 'main') -> str:
return _State().code_generator(syntax_tree, entry_name)

View File

@ -8,7 +8,7 @@ from .compiler_types import CompilerError
from .lexer import lexer from .lexer import lexer
from .syntactical_analyzer import syntactical_analyzer from .syntactical_analyzer import syntactical_analyzer
from .semantical_analyzer import semantical_analyzer from .semantical_analyzer import semantical_analyzer
from .code_generator import code_generator
def _compile(args: argparse.Namespace): def _compile(args: argparse.Namespace):
tokens = lexer(args.input_file.read(), args.input_file.name) tokens = lexer(args.input_file.read(), args.input_file.name)
@ -27,6 +27,11 @@ def _compile(args: argparse.Namespace):
if args.annotated_file: if args.annotated_file:
args.annotated_file.write(annotated_syntax_tree.tree_str()) args.annotated_file.write(annotated_syntax_tree.tree_str())
assembly_code = code_generator(annotated_syntax_tree)
if args.assembly_file:
args.assembly_file.write(assembly_code)
def compile(args: argparse.Namespace): def compile(args: argparse.Namespace):
try: _compile(args) try: _compile(args)
except CompilerError as e: print(e.compiler_error()) except CompilerError as e: print(e.compiler_error())
@ -40,13 +45,15 @@ def compile(args: argparse.Namespace):
def parser(parser: argparse.ArgumentParser): def parser(parser: argparse.ArgumentParser):
parser.add_argument( parser.add_argument(
'input_file', type=argparse.FileType('r', encoding='utf-8')) 'input_file', type=argparse.FileType('r', encoding='utf-8'))
# parser.add_argument('-o', '--output_file', type=argparse.FileType('wb')) parser.add_argument('-o', '--output_file', type=argparse.FileType('wb'))
parser.add_argument( parser.add_argument(
'-t', '--token_file', type=argparse.FileType('w', encoding='utf-8')) '-t', '--token_file', type=argparse.FileType('w', encoding='utf-8'))
parser.add_argument( parser.add_argument(
'-x', '--syntax_file', type=argparse.FileType('w', encoding='utf-8')) '-x', '--syntax_file', type=argparse.FileType('w', encoding='utf-8'))
parser.add_argument( parser.add_argument(
'-n', '--annotated_file', type=argparse.FileType('w', encoding='utf-8')) '-n', '--annotated_file', type=argparse.FileType('w', encoding='utf-8'))
parser.add_argument(
'-a', '--assembly_file', type=argparse.FileType('w', encoding='utf-8'))
parser.set_defaults(func=compile) parser.set_defaults(func=compile)
def main(argv: Sequence[str] | None = None): def main(argv: Sequence[str] | None = None):

View File

@ -5,31 +5,31 @@ from enum import Enum
from typing import ClassVar from typing import ClassVar
from .compiler_types import CompilerError, FileInfo from .compiler_types import CompilerError, FileInfo
from . import syntactical_analyzer from . import syntactical_analyzer as sya
type SymbolDefinitionTypes = ( type SymbolDefinitionTypes = (
InternalDefinition | InternalDefinition |
syntactical_analyzer.FunctionParameter | sya.FunctionParameter |
syntactical_analyzer.LetStatement | sya.LetStatement |
ForPreDef | ForPreDef |
syntactical_analyzer.StructBlock | sya.StructBlock |
FunctionBlock | FunctionBlock |
syntactical_analyzer.EnumBlock | sya.EnumBlock |
FunctionReturnDefinition FunctionReturnDefinition
) )
type SymbolReferenceTypes = ( type SymbolReferenceTypes = (
syntactical_analyzer.Identifier | sya.Identifier |
syntactical_analyzer.StructBlock | sya.StructBlock |
FunctionBlock | FunctionBlock |
syntactical_analyzer.EnumBlock sya.EnumBlock
) )
type Identifier = ( type Identifier = (
syntactical_analyzer.Identifier | sya.Identifier |
CompoundIdentifier | CompoundIdentifier |
AddressOfIdentifier | AddressOfIdentifier |
DereferenceIdentifier DereferenceIdentifier
@ -40,19 +40,19 @@ type NestableCodeBlock = ForBlock | WhileBlock | DoBlock | IfBlock
type IntermediateStatement = ( type IntermediateStatement = (
syntactical_analyzer.Expression | sya.Expression |
syntactical_analyzer.LetStatement | sya.LetStatement |
syntactical_analyzer.LoopStatements | sya.LoopStatements |
syntactical_analyzer.NestableCodeBlock | sya.NestableCodeBlock |
InternalDefinition | InternalDefinition |
Identifier Identifier
) )
type Statement = ( type Statement = (
syntactical_analyzer.Expression | sya.Expression |
syntactical_analyzer.LetStatement | sya.LetStatement |
syntactical_analyzer.LoopStatements | sya.LoopStatements |
NestableCodeBlock | NestableCodeBlock |
InternalDefinition | InternalDefinition |
Identifier Identifier
@ -71,80 +71,80 @@ type BlockHolder = (
BaseValues: tuple[type, ...] = ( BaseValues: tuple[type, ...] = (
syntactical_analyzer.BuiltInConst, sya.BuiltInConst,
syntactical_analyzer.NumberLiteral, sya.NumberLiteral,
syntactical_analyzer.CharLiteral, sya.CharLiteral,
syntactical_analyzer.StringLiteral, sya.StringLiteral,
syntactical_analyzer.Identifier, sya.Identifier,
syntactical_analyzer.FunctionCall, sya.FunctionCall,
) )
NestableCodeBlocks: tuple[type, ...] = ( NestableCodeBlocks: tuple[type, ...] = (
syntactical_analyzer.ForBlock, sya.ForBlock,
syntactical_analyzer.WhileBlock, sya.WhileBlock,
syntactical_analyzer.DoBlock, sya.DoBlock,
syntactical_analyzer.IfBlock, sya.IfBlock,
) )
HasOperands: tuple[type, ...] = ( HasOperands: tuple[type, ...] = (
syntactical_analyzer.UnaryExpression, sya.UnaryExpression,
syntactical_analyzer.BinaryExpression, sya.BinaryExpression,
syntactical_analyzer.TernaryExpression, sya.TernaryExpression,
) )
AddRefTypes: tuple[type, ...] = ( AddRefTypes: tuple[type, ...] = (
syntactical_analyzer.UnaryExpression, sya.UnaryExpression,
syntactical_analyzer.BinaryExpression, sya.BinaryExpression,
syntactical_analyzer.TernaryExpression, sya.TernaryExpression,
syntactical_analyzer.FunctionCall, sya.FunctionCall,
syntactical_analyzer.Identifier, sya.Identifier,
) )
IncrementOperators: tuple[ IncrementOperators: tuple[
syntactical_analyzer.PostfixUnaryOperatorEnum | sya.PostfixUnaryOperatorEnum |
syntactical_analyzer.PrefixUnaryOperatorEnum, ... sya.PrefixUnaryOperatorEnum, ...
] = ( ] = (
syntactical_analyzer.PostfixUnaryOperatorEnum.Increment, sya.PostfixUnaryOperatorEnum.Increment,
syntactical_analyzer.PostfixUnaryOperatorEnum.Decrement, sya.PostfixUnaryOperatorEnum.Decrement,
syntactical_analyzer.PrefixUnaryOperatorEnum.Increment, sya.PrefixUnaryOperatorEnum.Increment,
syntactical_analyzer.PrefixUnaryOperatorEnum.Decrement, sya.PrefixUnaryOperatorEnum.Decrement,
) )
PointerOperators: tuple[syntactical_analyzer.PrefixUnaryOperatorEnum, ...] = ( PointerOperators: tuple[sya.PrefixUnaryOperatorEnum, ...] = (
syntactical_analyzer.PrefixUnaryOperatorEnum.AddressOf, sya.PrefixUnaryOperatorEnum.AddressOf,
syntactical_analyzer.PrefixUnaryOperatorEnum.Dereference, sya.PrefixUnaryOperatorEnum.Dereference,
) )
AssignmentOperators: tuple[syntactical_analyzer.BinaryOperatorEnum, ...] = ( AssignmentOperators: tuple[sya.BinaryOperatorEnum, ...] = (
syntactical_analyzer.BinaryOperatorEnum.Assignment, sya.BinaryOperatorEnum.Assignment,
syntactical_analyzer.BinaryOperatorEnum.AdditionAssignment, sya.BinaryOperatorEnum.AdditionAssignment,
syntactical_analyzer.BinaryOperatorEnum.SubtractionAssignment, sya.BinaryOperatorEnum.SubtractionAssignment,
syntactical_analyzer.BinaryOperatorEnum.MultiplicationAssignment, sya.BinaryOperatorEnum.MultiplicationAssignment,
syntactical_analyzer.BinaryOperatorEnum.DivisionAssignment, sya.BinaryOperatorEnum.DivisionAssignment,
syntactical_analyzer.BinaryOperatorEnum.ModulusAssignment, sya.BinaryOperatorEnum.ModulusAssignment,
syntactical_analyzer.BinaryOperatorEnum.BitwiseANDAssignment, sya.BinaryOperatorEnum.BitwiseANDAssignment,
syntactical_analyzer.BinaryOperatorEnum.BitwiseORAssignment, sya.BinaryOperatorEnum.BitwiseORAssignment,
syntactical_analyzer.BinaryOperatorEnum.BitwiseXORAssignment, sya.BinaryOperatorEnum.BitwiseXORAssignment,
syntactical_analyzer.BinaryOperatorEnum.LeftShiftAssignment, sya.BinaryOperatorEnum.LeftShiftAssignment,
syntactical_analyzer.BinaryOperatorEnum.RightShiftAssignment, sya.BinaryOperatorEnum.RightShiftAssignment,
) )
OperandKeys: tuple[str, ...] = ("operand","operand1","operand2","operand3",) OperandKeys: tuple[str, ...] = ("operand","operand1","operand2","operand3",)
class SyntaxError(CompilerError): class SemanticError(CompilerError):
_compiler_error_type = "Semantic" _compiler_error_type = "Semantic"
class VariableAlreadyDeclared(SyntaxError): class VariableAlreadyDeclared(SemanticError):
def __init__( def __init__(
self, self,
@ -158,11 +158,11 @@ class VariableAlreadyDeclared(SyntaxError):
super().__init__(message, new.file_info) # type: ignore super().__init__(message, new.file_info) # type: ignore
class UndeclaredVariable(SyntaxError): class UndeclaredVariable(SemanticError):
def __init__( def __init__(
self, self,
variable: syntactical_analyzer.Identifier, variable: sya.Identifier,
): ):
message = ( message = (
f"The variable '{variable.content}' is undeclared." f"The variable '{variable.content}' is undeclared."
@ -170,22 +170,22 @@ class UndeclaredVariable(SyntaxError):
super().__init__(message, variable.file_info) # type: ignore super().__init__(message, variable.file_info) # type: ignore
class InvalidOperand(SyntaxError): class InvalidOperand(SemanticError):
def __init__( def __init__(
self, self,
operator: ( operator: (
syntactical_analyzer.TernaryExpression | sya.TernaryExpression |
syntactical_analyzer.BinaryExpression | sya.BinaryExpression |
syntactical_analyzer.UnaryExpression | sya.UnaryExpression |
syntactical_analyzer.Operator sya.Operator
), ),
operand: IntermediateStatement | Statement, operand: IntermediateStatement | Statement,
): ):
if isinstance(operator, ( if isinstance(operator, (
syntactical_analyzer.TernaryExpression, sya.TernaryExpression,
syntactical_analyzer.BinaryExpression, sya.BinaryExpression,
syntactical_analyzer.UnaryExpression, sya.UnaryExpression,
)): )):
message = ( message = (
f"The operand at '{operand}' is invalid for the " f"The operand at '{operand}' is invalid for the "
@ -305,14 +305,14 @@ class InternalDefinition:
_index: ClassVar[int] = 0 _index: ClassVar[int] = 0
_identifier: syntactical_analyzer.Identifier _identifier: sya.Identifier
_operand: syntactical_analyzer.Expression _operand: sya.Expression
def __init__( def __init__(
self, self,
operand: syntactical_analyzer.Expression, operand: sya.Expression,
): ):
self._identifier = syntactical_analyzer.Identifier( self._identifier = sya.Identifier(
f"`{InternalDefinition._index}", f"`{InternalDefinition._index}",
FileInfo("",0,0,0,0) FileInfo("",0,0,0,0)
) )
@ -320,11 +320,11 @@ class InternalDefinition:
InternalDefinition._index += 1 InternalDefinition._index += 1
@property @property
def identifier(self) -> syntactical_analyzer.Identifier: def identifier(self) -> sya.Identifier:
return self._identifier return self._identifier
@property @property
def operand(self) -> syntactical_analyzer.Expression: def operand(self) -> sya.Expression:
return self._operand return self._operand
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
@ -360,6 +360,9 @@ class Symbol:
self._definition = definition self._definition = definition
self._references = [] self._references = []
def __hash__(self) -> int:
return id(self)
@property @property
def name(self) -> str: return self._name def name(self) -> str: return self._name
@ -392,6 +395,9 @@ class SymbolTable:
raise KeyError raise KeyError
self.set(value) self.set(value)
@property
def symbols(self) -> list[Symbol]: return self._symbols[:]
def get(self, key: str, symbol_type: SymbolType | None = None) -> Symbol: def get(self, key: str, symbol_type: SymbolType | None = None) -> Symbol:
for symbol in self._symbols: for symbol in self._symbols:
if symbol.name == key and symbol_type is None: if symbol.name == key and symbol_type is None:
@ -433,12 +439,12 @@ class SymbolTable:
name_width = max(len(i) for i in names) name_width = max(len(i) for i in names)
type_width = max(len(i.value) for i in types) type_width = max(len(i.value) for i in types)
count_width = max(len(str(i)) for i in counts) count_width = max(len(str(i)) for i in counts)
title_width = name_width + 2 + type_width + 3 + count_width title_width = name_width + 2 + type_width + 2 + count_width
s = f"{pre} o{title.center(title_width, '-')}o\n" s = f"{pre} o{title.center(title_width, '-')}o\n"
for i in range(len(self._symbols)): for i in range(len(self._symbols)):
s += f"{pre_cont} |{(names[i] + ':').ljust(name_width + 1)} " s += f"{pre_cont} |{(names[i] + ':').ljust(name_width + 1)} "
s += f"{types[i].value.ljust(type_width)} - " s += f"{types[i].value.ljust(type_width)}; "
s += f"{str(counts[i]).rjust(count_width)}|\n" s += f"{str(counts[i]).rjust(count_width)}|\n"
s += f"{pre_cont} o{'-' * title_width}o\n" s += f"{pre_cont} o{'-' * title_width}o\n"
@ -474,6 +480,9 @@ class CodeBlock:
def __init__(self, code: list[Statement]): def __init__(self, code: list[Statement]):
self._code = code[:] self._code = code[:]
@property
def code(self) -> list[Statement]: return self._code[:]
def tree_str( def tree_str(
self, self,
pre: str = "", pre: str = "",
@ -489,19 +498,19 @@ class CodeBlock:
@staticmethod @staticmethod
def _sa( def _sa(
code: list[syntactical_analyzer.Statement], code: list[sya.Statement],
symbol_table: SymbolTable, symbol_table: SymbolTable,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
) -> "CodeBlock": ) -> "CodeBlock":
def add_ref_if(statement: syntactical_analyzer.Expression): def add_ref_if(statement: sya.Expression):
if isinstance(statement, HasOperands): if isinstance(statement, HasOperands):
for key in OperandKeys: for key in OperandKeys:
if ( if (
hasattr(statement, key) and hasattr(statement, key) and
isinstance( isinstance(
getattr(statement, key), getattr(statement, key),
syntactical_analyzer.Identifier, sya.Identifier,
) )
): ):
try: try:
@ -515,7 +524,7 @@ class CodeBlock:
hasattr(statement, key) and hasattr(statement, key) and
isinstance( isinstance(
getattr(statement, key), getattr(statement, key),
syntactical_analyzer.FunctionCall, sya.FunctionCall,
) )
): ):
try: try:
@ -539,20 +548,20 @@ class CodeBlock:
elif ( elif (
isinstance( isinstance(
statement, statement,
syntactical_analyzer.BinaryExpression, sya.BinaryExpression,
) and ) and
( (
statement.operator == statement.operator ==
syntactical_analyzer.BinaryOperatorEnum.Assignment sya.BinaryOperatorEnum.Assignment
) and ) and
hasattr(statement, key) and hasattr(statement, key) and
isinstance( isinstance(
getattr(statement, key), getattr(statement, key),
syntactical_analyzer.BinaryExpression, sya.BinaryExpression,
) )
): ):
add_ref_if(getattr(statement, key)) add_ref_if(getattr(statement, key))
elif isinstance(statement, syntactical_analyzer.FunctionCall): elif isinstance(statement, sya.FunctionCall):
try: try:
symbol = symbol_table.get( symbol = symbol_table.get(
statement.identifier.content, SymbolType.function) statement.identifier.content, SymbolType.function)
@ -568,7 +577,7 @@ class CodeBlock:
raise UndeclaredVariable(arg.value) # type: ignore raise UndeclaredVariable(arg.value) # type: ignore
else: else:
symbol.add_reference(arg.value) # type: ignore symbol.add_reference(arg.value) # type: ignore
elif isinstance(statement, syntactical_analyzer.Identifier): elif isinstance(statement, sya.Identifier):
try: try:
symbol = symbol_table.get(statement.content) symbol = symbol_table.get(statement.content)
except KeyError: except KeyError:
@ -579,7 +588,7 @@ class CodeBlock:
code_out: list[Statement] = [] code_out: list[Statement] = []
for root_statement in code: for root_statement in code:
for statement in _flatten_statement(root_statement): for statement in _flatten_statement(root_statement):
if isinstance(statement, syntactical_analyzer.LetStatement): if isinstance(statement, sya.LetStatement):
try: try:
symbol_table.add(Symbol( symbol_table.add(Symbol(
statement.identifier.content, statement.identifier.content,
@ -608,16 +617,16 @@ class CodeBlock:
elif isinstance(statement, AddRefTypes): elif isinstance(statement, AddRefTypes):
add_ref_if(statement) # type: ignore add_ref_if(statement) # type: ignore
code_out.append(statement) # type: ignore code_out.append(statement) # type: ignore
elif isinstance(statement, syntactical_analyzer.IfBlock): elif isinstance(statement, sya.IfBlock):
code_out.append( code_out.append(
IfBlock._sa(statement, symbol_table, members)) IfBlock._sa(statement, symbol_table, members))
elif isinstance(statement, syntactical_analyzer.DoBlock): elif isinstance(statement, sya.DoBlock):
code_out.append( code_out.append(
DoBlock._sa(statement, symbol_table, members)) DoBlock._sa(statement, symbol_table, members))
elif isinstance(statement, syntactical_analyzer.WhileBlock): elif isinstance(statement, sya.WhileBlock):
code_out.append( code_out.append(
WhileBlock._sa(statement, symbol_table, members)) WhileBlock._sa(statement, symbol_table, members))
elif isinstance(statement, syntactical_analyzer.ForBlock): elif isinstance(statement, sya.ForBlock):
code_out.append( code_out.append(
ForBlock._sa(statement, symbol_table, members)) ForBlock._sa(statement, symbol_table, members))
else: else:
@ -647,9 +656,9 @@ class ElseBlock:
@staticmethod @staticmethod
def _sa( def _sa(
else_block: syntactical_analyzer.ElseBlock, else_block: sya.ElseBlock,
symbol_table: SymbolTable, symbol_table: SymbolTable,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
) -> "ElseBlock": ) -> "ElseBlock":
code = CodeBlock._sa(else_block.code, symbol_table, members) code = CodeBlock._sa(else_block.code, symbol_table, members)
@ -660,7 +669,7 @@ class ElseBlock:
class ForPreDef: class ForPreDef:
_identifier: Identifier _identifier: Identifier
_type: syntactical_analyzer.DataType _type: sya.DataType
_pointer: bool _pointer: bool
_assignment: CodeBlock | None _assignment: CodeBlock | None
_file_info: FileInfo _file_info: FileInfo
@ -668,7 +677,7 @@ class ForPreDef:
def __init__( def __init__(
self, self,
identifier: Identifier, identifier: Identifier,
type: syntactical_analyzer.DataType, type: sya.DataType,
pointer: bool, pointer: bool,
assignment: CodeBlock | None, assignment: CodeBlock | None,
file_info: FileInfo, file_info: FileInfo,
@ -743,12 +752,12 @@ class ForBlock:
@staticmethod @staticmethod
def _sa( def _sa(
for_block: syntactical_analyzer.ForBlock, for_block: sya.ForBlock,
parent_table: SymbolTable, parent_table: SymbolTable,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
) -> "ForBlock": ) -> "ForBlock":
symbol_table = ForSymbolTable(parent_table) symbol_table = ForSymbolTable(parent_table)
if isinstance(for_block.pre_statement, syntactical_analyzer.ForPreDef): if isinstance(for_block.pre_statement, sya.ForPreDef):
assignment = CodeBlock._sa(for_block.code, symbol_table, members) assignment = CodeBlock._sa(for_block.code, symbol_table, members)
pre_statement = ForPreDef( pre_statement = ForPreDef(
for_block.pre_statement.identifier, for_block.pre_statement.identifier,
@ -827,9 +836,9 @@ class WhileBlock:
@staticmethod @staticmethod
def _sa( def _sa(
while_block: syntactical_analyzer.WhileBlock, while_block: sya.WhileBlock,
symbol_table: SymbolTable, symbol_table: SymbolTable,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
) -> "WhileBlock": ) -> "WhileBlock":
condition = CodeBlock._sa( condition = CodeBlock._sa(
[while_block.condition], symbol_table, members) [while_block.condition], symbol_table, members)
@ -897,9 +906,9 @@ class DoBlock:
@staticmethod @staticmethod
def _sa( def _sa(
do_block: syntactical_analyzer.DoBlock, do_block: sya.DoBlock,
symbol_table: SymbolTable, symbol_table: SymbolTable,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
) -> "DoBlock": ) -> "DoBlock":
condition = CodeBlock._sa([do_block.condition], symbol_table, members) condition = CodeBlock._sa([do_block.condition], symbol_table, members)
first_code = CodeBlock._sa(do_block.first_code, symbol_table, members) first_code = CodeBlock._sa(do_block.first_code, symbol_table, members)
@ -957,9 +966,9 @@ class IfBlock:
@staticmethod @staticmethod
def _sa( def _sa(
if_block: syntactical_analyzer.IfBlock, if_block: sya.IfBlock,
symbol_table: SymbolTable, symbol_table: SymbolTable,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
) -> "IfBlock": ) -> "IfBlock":
condition = CodeBlock._sa([if_block.condition], symbol_table, members) condition = CodeBlock._sa([if_block.condition], symbol_table, members)
code = CodeBlock._sa(if_block.code, symbol_table, members) code = CodeBlock._sa(if_block.code, symbol_table, members)
@ -977,48 +986,48 @@ class IfBlock:
class FunctionReturnDefinition: class FunctionReturnDefinition:
_identifier: syntactical_analyzer.Identifier _identifier: sya.Identifier
_return_type_pointer: bool _return_type_pointer: bool
_return_type: syntactical_analyzer.DataType | None _return_type: sya.DataType | None
def __init__( def __init__(
self, self,
identifier: syntactical_analyzer.Identifier, identifier: sya.Identifier,
return_type_pointer: bool, return_type_pointer: bool,
return_type: syntactical_analyzer.DataType | None, return_type: sya.DataType | None,
): ):
self._identifier = identifier self._identifier = identifier
self._return_type_pointer = return_type_pointer self._return_type_pointer = return_type_pointer
self._return_type = return_type self._return_type = return_type
@property @property
def identifier(self) -> syntactical_analyzer.Identifier: def identifier(self) -> sya.Identifier:
return self._identifier return self._identifier
@property @property
def return_type_pointer(self) -> bool: return self._return_type_pointer def return_type_pointer(self) -> bool: return self._return_type_pointer
@property @property
def return_type(self) -> syntactical_analyzer.DataType | None: def return_type(self) -> sya.DataType | None:
return self._return_type return self._return_type
class FunctionBlock: class FunctionBlock:
_identifier: syntactical_analyzer.Identifier _identifier: sya.Identifier
_params: list[syntactical_analyzer.FunctionParameter] _params: list[sya.FunctionParameter]
_return_type: FunctionReturnDefinition _return_type: FunctionReturnDefinition
_members: list[syntactical_analyzer.LetStatement] _members: list[sya.LetStatement]
_code: CodeBlock _code: CodeBlock
_file_info: FileInfo _file_info: FileInfo
_symbol_table: SymbolTable _symbol_table: SymbolTable
def __init__( def __init__(
self, self,
identifier: syntactical_analyzer.Identifier, identifier: sya.Identifier,
params: list[syntactical_analyzer.FunctionParameter], params: list[sya.FunctionParameter],
return_type: FunctionReturnDefinition, return_type: FunctionReturnDefinition,
members: list[syntactical_analyzer.LetStatement], members: list[sya.LetStatement],
code: CodeBlock, code: CodeBlock,
file_info: FileInfo, file_info: FileInfo,
symbol_table: SymbolTable, symbol_table: SymbolTable,
@ -1032,18 +1041,18 @@ class FunctionBlock:
self._symbol_table = symbol_table self._symbol_table = symbol_table
@property @property
def identifier(self) -> syntactical_analyzer.Identifier: def identifier(self) -> sya.Identifier:
return self._identifier return self._identifier
@property @property
def params(self) -> list[syntactical_analyzer.FunctionParameter]: def params(self) -> list[sya.FunctionParameter]:
return self._params[:] return self._params[:]
@property @property
def return_type(self) -> FunctionReturnDefinition: return self._return_type def return_type(self) -> FunctionReturnDefinition: return self._return_type
@property @property
def members(self) -> list[syntactical_analyzer.LetStatement]: def members(self) -> list[sya.LetStatement]:
return self._members[:] return self._members[:]
@property @property
@ -1052,6 +1061,9 @@ class FunctionBlock:
@property @property
def file_info(self) -> FileInfo: return self._file_info def file_info(self) -> FileInfo: return self._file_info
@property
def symbol_table(self) -> SymbolTable: return self._symbol_table
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
s: str = f"{pre} Function: {self._identifier}\n" s: str = f"{pre} Function: {self._identifier}\n"
if ( if (
@ -1096,11 +1108,11 @@ class FunctionBlock:
@staticmethod @staticmethod
def _sa( def _sa(
func: syntactical_analyzer.FunctionBlock, func: sya.FunctionBlock,
parent_table: SymbolTable, parent_table: SymbolTable,
) -> "FunctionBlock": ) -> "FunctionBlock":
symbol_table = SymbolTable(parent_table) symbol_table = SymbolTable(parent_table)
members: list[syntactical_analyzer.LetStatement] = [] members: list[sya.LetStatement] = []
function_return = FunctionReturnDefinition( function_return = FunctionReturnDefinition(
func.identifier, func.return_type_pointer, func.return_type) func.identifier, func.return_type_pointer, func.return_type)
@ -1137,10 +1149,10 @@ class FunctionBlock:
class File: class File:
_children: list[ _children: list[
syntactical_analyzer.Directive | sya.Directive |
syntactical_analyzer.StructBlock | sya.StructBlock |
FunctionBlock | FunctionBlock |
syntactical_analyzer.EnumBlock sya.EnumBlock
] ]
_file_info: FileInfo _file_info: FileInfo
_symbol_table: SymbolTable _symbol_table: SymbolTable
@ -1148,10 +1160,10 @@ class File:
def __init__( def __init__(
self, self,
children: list[ children: list[
syntactical_analyzer.Directive | sya.Directive |
syntactical_analyzer.StructBlock | sya.StructBlock |
FunctionBlock | FunctionBlock |
syntactical_analyzer.EnumBlock sya.EnumBlock
], ],
file_info: FileInfo, file_info: FileInfo,
symbol_table: SymbolTable, symbol_table: SymbolTable,
@ -1160,9 +1172,20 @@ class File:
self._file_info = file_info self._file_info = file_info
self._symbol_table = symbol_table self._symbol_table = symbol_table
@property
def children(self) -> list[
sya.Directive |
sya.StructBlock |
FunctionBlock |
sya.EnumBlock
]: return self._children[:]
@property @property
def file_info(self) -> FileInfo: return self._file_info def file_info(self) -> FileInfo: return self._file_info
@property
def symbol_table(self) -> SymbolTable: return self._symbol_table
def tree_str(self) -> str: def tree_str(self) -> str:
s: str = " File\n" s: str = " File\n"
if self._children: if self._children:
@ -1175,29 +1198,29 @@ class File:
return s return s
@staticmethod @staticmethod
def _sa(syntax_tree: syntactical_analyzer.File) -> "File": def _sa(syntax_tree: sya.File) -> "File":
symbol_table = SymbolTable() symbol_table = SymbolTable()
children: list[ children: list[
syntactical_analyzer.Directive | sya.Directive |
syntactical_analyzer.StructBlock | sya.StructBlock |
FunctionBlock | FunctionBlock |
syntactical_analyzer.EnumBlock sya.EnumBlock
] = [] ] = []
for child in syntax_tree.children: for child in syntax_tree.children:
symbol: Symbol | None = None symbol: Symbol | None = None
if isinstance(child, syntactical_analyzer.StructBlock): if isinstance(child, sya.StructBlock):
symbol = Symbol( symbol = Symbol(
child.identifier.content, child.identifier.content,
SymbolType.struct, SymbolType.struct,
child, child,
) )
elif isinstance(child, syntactical_analyzer.FunctionBlock): elif isinstance(child, sya.FunctionBlock):
symbol = Symbol( symbol = Symbol(
child.identifier.content, child.identifier.content,
SymbolType.function, SymbolType.function,
child, # type: ignore child, # type: ignore
) )
elif isinstance(child, syntactical_analyzer.EnumBlock): elif isinstance(child, sya.EnumBlock):
symbol = Symbol( symbol = Symbol(
child.identifier.content, child.identifier.content,
SymbolType.enum, SymbolType.enum,
@ -1206,33 +1229,65 @@ class File:
if symbol is not None: if symbol is not None:
symbol_table.add(symbol) symbol_table.add(symbol)
for child in syntax_tree.children: for child in syntax_tree.children:
new_child: ( new_child: sya.StructBlock | FunctionBlock | sya.EnumBlock
syntactical_analyzer.Directive | if isinstance(child, sya.FunctionBlock):
syntactical_analyzer.StructBlock |
FunctionBlock |
syntactical_analyzer.EnumBlock
)
if isinstance(child, syntactical_analyzer.FunctionBlock):
new_child = FunctionBlock._sa(child, symbol_table) new_child = FunctionBlock._sa(child, symbol_table)
symbol_table.get( symbol_table.get(
child.identifier.content child.identifier.content
)._definition = new_child # type: ignore )._definition = new_child # type: ignore
# TODO: analyze structs # TODO: analyze structs
# TODO: analyze enums elif isinstance(child, sya.StructBlock):
else:
new_child = child new_child = child
elif isinstance(child, sya.EnumBlock):
new_child = _sa_enum(child)
elif isinstance(child, sya.Directive):
continue
children.append(new_child) children.append(new_child)
file = File(children, syntax_tree._file_info, symbol_table) file = File(children, syntax_tree._file_info, symbol_table)
return file return file
def _sa_enum(block: sya.EnumBlock) -> sya.EnumBlock:
members: list[sya.EnumMember] = []
used_numbers: set[int] = set()
for member in block.members:
if member.value is not None:
used_numbers.add(member.value.value)
i = 1
for member in block.members:
while i in used_numbers:
i += 1
if member.value is not None:
members.append(sya.EnumMember(
member.identifier,
member.value,
member.file_info
))
i = member.value.value + 1
else:
used_numbers.add(i)
members.append(sya.EnumMember(
member.identifier,
sya.NumberLiteral(str(i), member.file_info),
member.file_info
))
i += 1
return sya.EnumBlock(
block.identifier,
sorted(
sorted(members, key=lambda o: o.identifier.content),
key=lambda o: o.value.value # type: ignore
),
block.file_info,
)
def _compound_identifier( def _compound_identifier(
statement: syntactical_analyzer.BinaryExpression, statement: sya.BinaryExpression,
operator: syntactical_analyzer.Operator, operator: sya.Operator,
) -> CompoundIdentifier: ) -> CompoundIdentifier:
if ( if (
statement.operator.content == statement.operator.content ==
syntactical_analyzer.BinaryOperatorEnum.MemberOf sya.BinaryOperatorEnum.MemberOf
): return CompoundIdentifier( ): return CompoundIdentifier(
_assert_identifier(statement.operand1, statement.operator, True), _assert_identifier(statement.operand1, statement.operator, True),
_assert_identifier(statement.operand2, statement.operator, True), _assert_identifier(statement.operand2, statement.operator, True),
@ -1241,19 +1296,19 @@ def _compound_identifier(
else: raise InvalidOperand(operator, statement) else: raise InvalidOperand(operator, statement)
def _augment_identifier( def _augment_identifier(
statement: syntactical_analyzer.UnaryExpression, statement: sya.UnaryExpression,
operator: syntactical_analyzer.Operator, operator: sya.Operator,
) -> AddressOfIdentifier | DereferenceIdentifier: ) -> AddressOfIdentifier | DereferenceIdentifier:
if ( if (
statement.operator.content == statement.operator.content ==
syntactical_analyzer.PrefixUnaryOperatorEnum.AddressOf sya.PrefixUnaryOperatorEnum.AddressOf
): return AddressOfIdentifier( ): return AddressOfIdentifier(
_assert_identifier(statement.operand, statement.operator, True), _assert_identifier(statement.operand, statement.operator, True),
statement.file_info, statement.file_info,
) )
elif ( elif (
statement.operator.content == statement.operator.content ==
syntactical_analyzer.PrefixUnaryOperatorEnum.Dereference sya.PrefixUnaryOperatorEnum.Dereference
): return DereferenceIdentifier( ): return DereferenceIdentifier(
_assert_identifier(statement.operand, statement.operator, True), _assert_identifier(statement.operand, statement.operator, True),
statement.file_info, statement.file_info,
@ -1261,25 +1316,25 @@ def _augment_identifier(
else: raise InvalidOperand(operator, statement) else: raise InvalidOperand(operator, statement)
def _assert_identifier( def _assert_identifier(
statement: syntactical_analyzer.Statement, statement: sya.Statement,
operator: syntactical_analyzer.Operator, operator: sya.Operator,
harsh: bool = False harsh: bool = False
) -> Identifier: ) -> Identifier:
if isinstance(statement, syntactical_analyzer.Identifier): if isinstance(statement, sya.Identifier):
return statement return statement
elif isinstance(statement, syntactical_analyzer.UnaryExpression): elif isinstance(statement, sya.UnaryExpression):
if ( if (
isinstance(statement.operand, syntactical_analyzer.BinaryExpression) isinstance(statement.operand, sya.BinaryExpression)
and not harsh and not harsh
): ):
return statement # type: ignore return statement # type: ignore
return _augment_identifier(statement, operator) return _augment_identifier(statement, operator)
elif isinstance(statement, syntactical_analyzer.BinaryExpression): elif isinstance(statement, sya.BinaryExpression):
return _compound_identifier(statement, operator) return _compound_identifier(statement, operator)
else: raise InvalidOperand(operator, statement) else: raise InvalidOperand(operator, statement)
def _create_internal_definition( def _create_internal_definition(
statement: syntactical_analyzer.Expression, statement: sya.Expression,
) -> list[IntermediateStatement]: ) -> list[IntermediateStatement]:
flattened = _flatten_statement(statement) flattened = _flatten_statement(statement)
internal_definition = InternalDefinition( internal_definition = InternalDefinition(
@ -1288,12 +1343,12 @@ def _create_internal_definition(
internal_definition, internal_definition.identifier] internal_definition, internal_definition.identifier]
def _flatten_statement( def _flatten_statement(
statement: syntactical_analyzer.Statement, statement: sya.Statement,
) -> list[IntermediateStatement]: ) -> list[IntermediateStatement]:
if isinstance(statement, syntactical_analyzer.UnaryExpression): if isinstance(statement, sya.UnaryExpression):
if statement.operator.content in IncrementOperators: if statement.operator.content in IncrementOperators:
return [syntactical_analyzer.UnaryExpression( return [sya.UnaryExpression(
statement.operator, statement.operator,
_assert_identifier( # type: ignore _assert_identifier( # type: ignore
statement.operand, statement.operator), statement.operand, statement.operator),
@ -1306,17 +1361,17 @@ def _flatten_statement(
else: else:
flattened = _create_internal_definition(statement.operand) flattened = _create_internal_definition(statement.operand)
return flattened[:-1] + [ return flattened[:-1] + [
syntactical_analyzer.UnaryExpression( sya.UnaryExpression(
statement.operator, statement.operator,
flattened[-1], # type: ignore flattened[-1], # type: ignore
statement.file_info, statement.file_info,
) )
] ]
elif isinstance(statement, syntactical_analyzer.BinaryExpression): elif isinstance(statement, sya.BinaryExpression):
if ( if (
statement.operator.content == statement.operator.content ==
syntactical_analyzer.BinaryOperatorEnum.MemberOf sya.BinaryOperatorEnum.MemberOf
): return [CompoundIdentifier( ): return [CompoundIdentifier(
_assert_identifier(statement.operand1, statement.operator), _assert_identifier(statement.operand1, statement.operator),
_assert_identifier(statement.operand2, statement.operator), _assert_identifier(statement.operand2, statement.operator),
@ -1324,10 +1379,10 @@ def _flatten_statement(
)] )]
elif ( elif (
statement.operator.content == statement.operator.content ==
syntactical_analyzer.BinaryOperatorEnum.Assignment sya.BinaryOperatorEnum.Assignment
): ):
flattened = _flatten_statement(statement.operand2) flattened = _flatten_statement(statement.operand2)
return flattened[:-1] + [syntactical_analyzer.BinaryExpression( return flattened[:-1] + [sya.BinaryExpression(
statement.operator, statement.operator,
_assert_identifier( # type: ignore _assert_identifier( # type: ignore
statement.operand1, statement.operand1,
@ -1338,7 +1393,7 @@ def _flatten_statement(
)] )]
elif statement.operator.content in AssignmentOperators: elif statement.operator.content in AssignmentOperators:
if isinstance(statement.operand2, BaseValues): if isinstance(statement.operand2, BaseValues):
return [syntactical_analyzer.BinaryExpression( return [sya.BinaryExpression(
statement.operator, statement.operator,
_assert_identifier( # type: ignore _assert_identifier( # type: ignore
statement.operand1, statement.operand1,
@ -1349,7 +1404,7 @@ def _flatten_statement(
)] )]
else: else:
flattened = _create_internal_definition(statement.operand2) flattened = _create_internal_definition(statement.operand2)
return flattened[:-1] + [syntactical_analyzer.BinaryExpression( return flattened[:-1] + [sya.BinaryExpression(
statement.operator, statement.operator,
_assert_identifier( # type: ignore _assert_identifier( # type: ignore
statement.operand1, statement.operand1,
@ -1366,7 +1421,7 @@ def _flatten_statement(
flattened2 = [statement.operand2] flattened2 = [statement.operand2]
else: flattened2 = _create_internal_definition(statement.operand2) else: flattened2 = _create_internal_definition(statement.operand2)
return flattened1[:-1] + flattened2[:-1] + [ return flattened1[:-1] + flattened2[:-1] + [
syntactical_analyzer.BinaryExpression( sya.BinaryExpression(
statement.operator, statement.operator,
flattened1[-1], # type: ignore flattened1[-1], # type: ignore
flattened2[-1], # type: ignore flattened2[-1], # type: ignore
@ -1374,7 +1429,7 @@ def _flatten_statement(
) )
] ]
elif isinstance(statement, syntactical_analyzer.TernaryExpression): elif isinstance(statement, sya.TernaryExpression):
if isinstance(statement.operand1, BaseValues): if isinstance(statement.operand1, BaseValues):
flattened1 = [statement.operand1] flattened1 = [statement.operand1]
else: flattened1 = _create_internal_definition(statement.operand1) else: flattened1 = _create_internal_definition(statement.operand1)
@ -1385,7 +1440,7 @@ def _flatten_statement(
flattened3 = [statement.operand3] flattened3 = [statement.operand3]
else: flattened3 = _create_internal_definition(statement.operand3) else: flattened3 = _create_internal_definition(statement.operand3)
return flattened1[:-1] + flattened2[:-1] + flattened3[:-1] + [ return flattened1[:-1] + flattened2[:-1] + flattened3[:-1] + [
syntactical_analyzer.TernaryExpression( sya.TernaryExpression(
statement.operator, statement.operator,
flattened1[-1], # type: ignore flattened1[-1], # type: ignore
flattened2[-1], # type: ignore flattened2[-1], # type: ignore
@ -1396,5 +1451,5 @@ def _flatten_statement(
else: return [statement] else: return [statement]
def semantical_analyzer(syntax_tree: syntactical_analyzer.File) -> File: def semantical_analyzer(syntax_tree: sya.File) -> File:
return File._sa(syntax_tree) return File._sa(syntax_tree)

View File

@ -177,6 +177,13 @@ class BuiltInConst:
@property @property
def file_info(self) -> FileInfo: return self._file_info def file_info(self) -> FileInfo: return self._file_info
@property
def value(self) -> int:
match (self._content):
case BuiltInConstEnum.ConstTrue: return 1
case BuiltInConstEnum.ConstFalse: return 0
case BuiltInConstEnum.ConstNone: return 0
def __str__(self) -> str: return self._content.value def __str__(self) -> str: return self._content.value
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
@ -517,6 +524,9 @@ class CharLiteral:
@property @property
def content(self) -> str: return self._content def content(self) -> str: return self._content
@property
def value(self) -> int: return ord(self._content)
def __str__(self) -> str: return self._content def __str__(self) -> str: return self._content
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
@ -543,6 +553,9 @@ class NumberLiteral:
@property @property
def content(self) -> str: return self._content def content(self) -> str: return self._content
@property
def value(self) -> int: return int(self._content, base=0)
def __str__(self) -> str: return self._content def __str__(self) -> str: return self._content
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
@ -1472,6 +1485,9 @@ class EnumMember:
@property @property
def identifier(self) -> Identifier: return self._identifier def identifier(self) -> Identifier: return self._identifier
@property
def value(self) -> NumberLiteral | None: return self._value
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
s: str = f"{pre} Enum Member: {self._identifier}\n" s: str = f"{pre} Enum Member: {self._identifier}\n"
if self._value is not None: if self._value is not None:
@ -1501,6 +1517,9 @@ class EnumBlock:
@property @property
def identifier(self) -> Identifier: return self._identifier def identifier(self) -> Identifier: return self._identifier
@property
def members(self) -> list[EnumMember]: return self._members[:]
def tree_str(self, pre: str = "", pre_cont: str = "") -> str: def tree_str(self, pre: str = "", pre_cont: str = "") -> str:
s: str = f"{pre} Enum: {self._identifier}\n" s: str = f"{pre} Enum: {self._identifier}\n"
if self._members: if self._members: