GAL / Backend /shared /ast_nodes.py
Clarkoer's picture
add comments ehehe
e6b283b
Raw
History Blame Contribute Delete
15.4 kB
"""AST node classes shared by the parser, semantic validator, and interpreter.
Each class represents one language construct after parsing, for example a
VariableDeclarationNode, BinaryOpNode, FunctionCallNode, or WhileLoopNode.
"""
# AUTO: Defines class `ASTNode`.
class ASTNode:
# AUTO: Defines function `__init__`.
def __init__(self, node_type, value=None, line=None):
# LINE: node_type tells semantic/interpreter what this AST node represents.
self.node_type = node_type
# LINE: value stores the node's main text/value, like an operator or name.
self.value = value
# LINE: children stores nested AST nodes under this node.
self.children = []
# LINE: parent points back to the surrounding AST node.
self.parent = None
# LINE: line stores the original source line for error messages.
self.line = line
# AUTO: Defines function `add_child`.
def add_child(self, child):
# GUIDE: Parent links let later stages know the surrounding construct,
# for example water() can see whether it belongs to an assignment.
# AUTO: Sets `child.parent`.
child.parent = self
# AUTO: Appends a value to a list.
self.children.append(child)
# AUTO: Defines function `print_tree`.
def print_tree(self, level=0):
# AUTO: Sets `indent`.
indent = ' ' * (level * 3)
# AUTO: Calls `print`.
print(f"{indent}╚═{self.node_type}: {self.value if self.value else ''}")
# AUTO: Starts a loop over these values.
for child in self.children:
# AUTO: Calls `child.print_tree`.
child.print_tree(level + 1)
# AUTO: Defines class `ProgramNode`.
class ProgramNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, line=None):
# LINE: ProgramNode is the root container for the whole AST.
super().__init__("Program", line=line)
# AUTO: Defines class `VariableDeclarationNode`.
class VariableDeclarationNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, var_type, var_name, value=None, line=None):
# LINE: VariableDeclaration represents code like seed x = 10;
super().__init__("VariableDeclaration", line=line)
# LINE: First child stores declared type.
self.add_child(ASTNode("Type", var_type, line=line))
# LINE: Second child stores variable name.
self.add_child(ASTNode("Identifier", var_name, line=line))
# AUTO: Checks this condition.
if value:
# LINE: Optional third child stores initializer expression.
self.add_child(value)
# AUTO: Defines class `AssignmentNode`.
class AssignmentNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, target, value, line=None):
# LINE: Assignment represents code like x = y + 1;
super().__init__("Assignment", line=line)
# AUTO: Checks this condition.
if isinstance(target, str):
# LINE: Simple target names are wrapped as Identifier nodes.
self.add_child(ASTNode("Identifier", target, line=line))
# AUTO: Runs when previous condition did not pass.
else:
# LINE: Complex targets are already AST nodes, like array/member access.
self.add_child(target)
# LINE: Second child stores the RHS expression/value.
self.add_child(value)
# AUTO: Defines class `BinaryOpNode`.
class BinaryOpNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, left, operator, right, line=None):
# LINE: BinaryOp stores operator in value with left/right children.
super().__init__("BinaryOp", operator, line=line)
# AUTO: Calls `self.add_child`.
self.add_child(left)
# AUTO: Calls `self.add_child`.
self.add_child(right)
# AUTO: Defines class `FunctionDeclarationNode`.
class FunctionDeclarationNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, return_type, name, params, line=None):
# LINE: FunctionDeclaration stores function name in value.
super().__init__("FunctionDeclaration", name, line=line)
# LINE: First child stores return type.
self.add_child(ASTNode("ReturnType", return_type, line=line))
# LINE: Second child stores parameters.
self.add_child(params)
# AUTO: Defines class `FunctionCallNode`.
class FunctionCallNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, name, args, line=None):
# LINE: FunctionCall stores called function name in value.
super().__init__("FunctionCall", name, line=line)
# LINE: Each argument becomes a child.
for arg in args:
# AUTO: Calls `self.add_child`.
self.add_child(arg)
# AUTO: Defines class `IfStatementNode`.
class IfStatementNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, condition, line=None):
# AUTO: Sets `super().__init__("IfStatement", line`.
super().__init__("IfStatement", line=line)
# AUTO: Calls `self.add_child`.
self.add_child(condition)
# AUTO: Defines class `ForLoopNode`.
class ForLoopNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, initialization, condition, update, line=None):
# AUTO: Sets `super().__init__("ForLoop", line`.
super().__init__("ForLoop", line=line)
# AUTO: Calls `self.add_child`.
self.add_child(initialization)
# AUTO: Calls `self.add_child`.
self.add_child(condition)
# AUTO: Calls `self.add_child`.
self.add_child(update)
# AUTO: Defines class `WhileLoopNode`.
class WhileLoopNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, condition, line=None):
# AUTO: Sets `super().__init__("WhileLoop", line`.
super().__init__("WhileLoop", line=line)
# AUTO: Calls `self.add_child`.
self.add_child(condition)
# AUTO: Defines class `DoWhileLoopNode`.
class DoWhileLoopNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, condition, line=None):
# AUTO: Sets `super().__init__("DoWhileLoop", line`.
super().__init__("DoWhileLoop", line=line)
# AUTO: Defines class `PrintNode`.
class PrintNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, args, line=None):
# AUTO: Sets `super().__init__("PrintStatement", line`.
super().__init__("PrintStatement", line=line)
# AUTO: Starts a loop over these values.
for arg in args:
# AUTO: Calls `self.add_child`.
self.add_child(arg)
# AUTO: Defines class `UnaryOpNode`.
class UnaryOpNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, operator, operand, position="pre", line=None):
# AUTO: Sets `super().__init__("UnaryOp", operator, line`.
super().__init__("UnaryOp", operator, line=line)
# AUTO: Sets `self.position`.
self.position = position
# AUTO: Calls `self.add_child`.
self.add_child(operand)
# AUTO: Defines class `FertileDeclarationNode`.
class FertileDeclarationNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, var_type, var_name, value, line=None):
# AUTO: Sets `super().__init__("SturdyDeclaration", line`.
super().__init__("SturdyDeclaration", line=line)
# AUTO: Sets `self.add_child(ASTNode("Type", var_type, line`.
self.add_child(ASTNode("Type", var_type, line=line))
# AUTO: Sets `self.add_child(ASTNode("Identifier", var_name, line`.
self.add_child(ASTNode("Identifier", var_name, line=line))
# AUTO: Calls `self.add_child`.
self.add_child(value)
# AUTO: Defines class `ReturnNode`.
class ReturnNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, return_value=None, line=None):
# AUTO: Sets `super().__init__("Return", line`.
super().__init__("Return", line=line)
# AUTO: Checks this condition.
if return_value:
# AUTO: Calls `self.add_child`.
self.add_child(return_value)
# AUTO: Defines class `UpdateNode`.
class UpdateNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, operator, operand, prefix = True, line=None):
# AUTO: Sets `super().__init__("Update", line`.
super().__init__("Update", line=line)
# AUTO: Sets `self.prefix`.
self.prefix = prefix
# AUTO: Calls `self.add_child`.
self.add_child(operand)
# AUTO: Calls `self.add_child`.
self.add_child(operator)
# AUTO: Defines class `SwitchNode`.
class SwitchNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, expression, cases, default_case, line=None):
# AUTO: Sets `super().__init__("Switch", line`.
super().__init__("Switch", line=line)
# AUTO: Calls `self.add_child`.
self.add_child(expression)
# AUTO: Starts a loop over these values.
for case in cases:
# AUTO: Calls `self.add_child`.
self.add_child(case)
# AUTO: Checks this condition.
if default_case is not None:
# AUTO: Calls `self.add_child`.
self.add_child(default_case)
# AUTO: Defines class `ContinueNode`.
class ContinueNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, line=None):
# AUTO: Sets `super().__init__("Continue", line`.
super().__init__("Continue", line=line)
# AUTO: Defines class `BreakNode`.
class BreakNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, line=None):
# AUTO: Sets `super().__init__("Break", line`.
super().__init__("Break", line=line)
# AUTO: Defines class `ListNode`.
class ListNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, line=None, elements=None):
# AUTO: Sets `super().__init__("List", line`.
super().__init__("List", line=line)
# AUTO: Sets `self.elements`.
self.elements = elements or []
# AUTO: Starts a loop over these values.
for element in self.elements:
# AUTO: Calls `self.add_child`.
self.add_child(element)
# AUTO: Defines class `SoilNode`.
class SoilNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, variable_name, line=None):
# AUTO: Sets `super().__init__("SoilFunction", line`.
super().__init__("SoilFunction", line=line)
# AUTO: Sets `self.add_child(ASTNode("Identifier", variable_name, line`.
self.add_child(ASTNode("Identifier", variable_name, line=line))
# AUTO: Defines class `BloomNode`.
class BloomNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, variable_name, line=None):
# AUTO: Sets `super().__init__("BloomFunction", line`.
super().__init__("BloomFunction", line=line)
# AUTO: Sets `self.add_child(ASTNode("Identifier", variable_name, line`.
self.add_child(ASTNode("Identifier", variable_name, line=line))
# AUTO: Defines class `AppendNode`.
class AppendNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, elements, line=None):
# AUTO: Sets `super().__init__("Append", line`.
super().__init__("Append", line=line)
# AUTO: Starts a loop over these values.
for elem in elements:
# AUTO: Calls `self.add_child`.
self.add_child(elem)
# AUTO: Defines class `InsertNode`.
class InsertNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, index, elements, line=None):
# AUTO: Sets `super().__init__("Insert", line`.
super().__init__("Insert", line=line)
# AUTO: Calls `self.add_child`.
self.add_child(index)
# AUTO: Starts a loop over these values.
for elem in elements:
# AUTO: Calls `self.add_child`.
self.add_child(elem)
# AUTO: Defines class `RemoveNode`.
class RemoveNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, value, index, line=None):
# AUTO: Sets `super().__init__("Remove", line`.
super().__init__("Remove", line=line)
# AUTO: Sets `self.add_child(ASTNode("Identifier", value, line`.
self.add_child(ASTNode("Identifier", value, line=line))
# AUTO: Calls `self.add_child`.
self.add_child(index)
# AUTO: Defines class `CastNode`.
class CastNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, target_type, expression, line=None):
# AUTO: Sets `super().__init__("TypeCast", line`.
super().__init__("TypeCast", line=line)
# AUTO: Sets `self.add_child(ASTNode("TargetType", target_type, line`.
self.add_child(ASTNode("TargetType", target_type, line=line))
# AUTO: Calls `self.add_child`.
self.add_child(expression)
# AUTO: Defines class `ListAccessNode`.
class ListAccessNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, list_name, index_expr, line=None):
# AUTO: Sets `super().__init__("ListAccess", line`.
super().__init__("ListAccess", line=line)
# AUTO: Sets `self.add_child(ASTNode("ListName", list_name, line`.
self.add_child(ASTNode("ListName", list_name, line=line))
# AUTO: Calls `self.add_child`.
self.add_child(index_expr)
# AUTO: Defines class `MemberAccessNode`.
class MemberAccessNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, object_name, member_name, line=None):
# AUTO: Sets `super().__init__("MemberAccess", line`.
super().__init__("MemberAccess", line=line)
# AUTO: Checks this condition.
if isinstance(object_name, ASTNode):
# AUTO: Calls `self.add_child`.
self.add_child(object_name)
# AUTO: Runs when previous condition did not pass.
else:
# AUTO: Sets `self.add_child(ASTNode("Object", object_name, line`.
self.add_child(ASTNode("Object", object_name, line=line))
# AUTO: Sets `self.add_child(ASTNode("Member", member_name, line`.
self.add_child(ASTNode("Member", member_name, line=line))
# AUTO: Defines class `ArrayMemberAccessNode`.
class ArrayMemberAccessNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, list_access_node, member_name, line=None):
# AUTO: Sets `super().__init__("ArrayMemberAccess", line`.
super().__init__("ArrayMemberAccess", line=line)
# AUTO: Calls `self.add_child`.
self.add_child(list_access_node)
# AUTO: Sets `self.add_child(ASTNode("Member", member_name, line`.
self.add_child(ASTNode("Member", member_name, line=line))
# AUTO: Defines class `BundleDefinitionNode`.
class BundleDefinitionNode(ASTNode):
# AUTO: Defines function `__init__`.
def __init__(self, bundle_name, members, line=None):
# AUTO: Sets `super().__init__("BundleDefinition", line`.
super().__init__("BundleDefinition", line=line)
# AUTO: Sets `self.bundle_name`.
self.bundle_name = bundle_name
# AUTO: Sets `self.members`.
self.members = members