parseNode function
- YamlMap node
Recursively parses a YAML node representation into a concrete AST node.
This function is the core of the AST parsing system. It takes a YAML map representing a single AST node and converts it into the appropriate Node subclass based on the node type. The function handles the recursive nature of AST structures by parsing child nodes and assembling them into the appropriate parent node structure.
The parsing process involves:
- Extracting the node type from the YAML structure
- Recursively parsing all child nodes
- Extracting node-specific values (literals, identifiers, etc.)
- Constructing the appropriate Node subclass with correct parameters
Parameters:
node
: YAML map containing the node representation with 'type', 'value', and 'children' fields
Returns: A concrete Node instance of the appropriate subclass
Throws:
- Exception if the node type is not recognized or supported
- Various exceptions from individual node constructors if parameters are invalid
Supported node types include:
- Block, Identifier, Type, ArrayType, Declaration, Assignment
- Binary/unary operations, literals, function calls
- Control flow (If, While), I/O operations (Print, Scanf)
- Type casting and string handling
Implementation
Node parseNode(YamlMap node) {
var type = node["type"];
var childrenDict = node["children"];
final children = <Node>[];
if (childrenDict != null) {
for (var child in childrenDict) {
children.add(parseNode(child));
}
}
final value = node["value"];
switch (type) {
case "Block":
return BlockNode(children);
case "Identifier":
return IdentifierNode(value);
case "IndexedIdentifier":
return IndexedIdentifierNode(value, children[0] as Node<dynamic, LangVal>);
case "Type":
return TypeNode(PrimitiveType(PrimitiveTypes.fromString(value)));
case "ArrayType":
return ArrayTypeNode(children[0] as TypeNode, children[1] as ArraySpecification);
case "ArraySpecifier":
return ArraySpecification(children.firstOrNull as Node<dynamic, LangVal>?);
case "IntLiteral":
return IntVal(value);
case "FloatLiteral":
return FloatVal(value);
case "Declaration":
return DeclareNode(children[0] as Node<LangType,dynamic>, children[1] as IdentifierNode, children.length > 2 ? children[2] : null);
case "Assignment":
return AssignmentNode(children[0] as IdentifierNode, children[1]);
case "UnOp":
return UnOp(value, children[0] as Node<dynamic, LangVal>);
case "BinOp":
return BinOp(value, children[0] as Node<dynamic, LangVal>, children[1] as Node<dynamic, LangVal>);
case "Print":
return PrintNode(children[0] as StringLiteral, children.sublist(1).cast());
case "RelOp":
return RelOp(value, children[0] as Node<dynamic, LangVal>, children[1] as Node<dynamic, LangVal>);
case "BoolUnOp":
return BoolUnOp(value, children[0] as Node<dynamic, LangVal>);
case "BoolBinOp":
return BoolBinOp(value, children[0] as Node<dynamic, LangVal>, children[1] as Node<dynamic, LangVal>);
case "IfStatement":
return IfNode(children[0] as Node<dynamic, LangVal>, children[1] as BlockNode, children.length > 2 ? children[2] : null);
case "WhileStatement":
return WhileNode(children[0] as Node<dynamic, LangVal>, children[1] as BlockNode);
case "ParameterList":
return ParameterList(children.cast());
case "ArgumentList":
return ArgumentList(children.cast());
case "FunctionDeclaration":
return FuncDec(children[0] as TypeNode , children[1] as IdentifierNode, children[2] as ParameterList, children[3] as BlockNode);
case "FunctionCall":
return FuncCall(children[0] as IdentifierNode, children[1] as ArgumentList);
case "ReturnStatement":
return ReturnStatement(children[0] as Node<dynamic, LangVal>);
case "FunctionList":
return FunctionList(children.cast());
case "TypeCast":
return TypeCast(PrimitiveType(PrimitiveTypes.fromString(value)), children[0] as Node<dynamic, LangVal>);
case "StringLiteral":
return StringLiteral(value);
case "Scanf":
return ScanfNode(children[0] as StringLiteral, children.sublist(1).cast());
default:
throw Exception("Unknown node type: $type");
}
}