init commit
This commit is contained in:
369
AST.jai
Normal file
369
AST.jai
Normal file
@@ -0,0 +1,369 @@
|
||||
/////////////////////////////////////
|
||||
//~ nbr: Node data structure
|
||||
//
|
||||
// [ ] Add a way to infer or get file path from a node
|
||||
|
||||
AST_Kind :: enum {
|
||||
Program;
|
||||
Function;
|
||||
Return;
|
||||
|
||||
// @Incomplete(nb): Should these three really be their own block types?
|
||||
// Maybe they at least shouldn't need to have their own tokens...
|
||||
Properties;
|
||||
Meta;
|
||||
Instance;
|
||||
//==
|
||||
|
||||
// Hint;
|
||||
// Type;
|
||||
// Operator;
|
||||
Call;
|
||||
Struct;
|
||||
FieldList;
|
||||
ArgList;
|
||||
Variable;
|
||||
Binary;
|
||||
Unary;
|
||||
Integer;
|
||||
Float;
|
||||
Expression_Statement;
|
||||
Field;
|
||||
Unnamed_Field;
|
||||
Block;
|
||||
Error;
|
||||
}
|
||||
|
||||
AST_Node :: struct {
|
||||
kind : AST_Kind;
|
||||
|
||||
// @Note(niels): Children nodes can be interpreted as anything useful.
|
||||
// for an if-statement we would have at most 2 children
|
||||
// a property block has a child node for each field declaration etc.
|
||||
children : [..]*AST_Node;
|
||||
parent : *AST_Node;
|
||||
|
||||
// @Note(niels): Every node can have a name, but most nodes don't. A function or field declaration has one,
|
||||
// but an if-statement does not
|
||||
name : string;
|
||||
|
||||
integer_value : int;
|
||||
float_value : float;
|
||||
|
||||
token : Token;
|
||||
|
||||
assignment : bool;
|
||||
|
||||
source_location : Source_Range;
|
||||
|
||||
type_variable : Type_Variable_Handle;
|
||||
|
||||
foreign_declaration : bool;
|
||||
|
||||
// @Incomplete(nb): Change this to just be children and a single token_data field,
|
||||
// then we can add new node types (hint, typespec, operator) and have them
|
||||
// as children instead.
|
||||
hint_tokens : [..]Token;
|
||||
|
||||
vertex_entry_point : bool;
|
||||
pixel_entry_point : bool;
|
||||
}
|
||||
|
||||
|
||||
// ===========================================================
|
||||
// Pretty printing
|
||||
pretty_print_call :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
append(builder, "(");
|
||||
append(builder, node.name);
|
||||
if node.children.count > 0 {
|
||||
append(builder, " ");
|
||||
pretty_print_children(node.children[0], indentation, builder, flags = 0);
|
||||
}
|
||||
append(builder, ")");
|
||||
}
|
||||
|
||||
pretty_print_arglist :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
append(builder, "[");
|
||||
|
||||
pretty_print_children(node, indentation + 1, builder, flags = .NewLine);
|
||||
|
||||
append(builder, "]");
|
||||
}
|
||||
|
||||
pretty_print_fieldlist :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
|
||||
append(builder, "[");
|
||||
pretty_print_children(node, indentation + 1, builder, flags = .NewLine);
|
||||
|
||||
append(builder, "]");
|
||||
}
|
||||
|
||||
pretty_print_field :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
print_to_builder(builder, tprint("(:= %", node.name));
|
||||
|
||||
if node.kind != .Unnamed_Field && node.token.ident_value.count > 0 {
|
||||
print_to_builder(builder, tprint(" %", node.token.ident_value));
|
||||
}
|
||||
|
||||
for hint : node.hint_tokens {
|
||||
if hint.string_value.count > 0 {
|
||||
print_to_builder(builder, " (@%)", hint.string_value);
|
||||
}
|
||||
}
|
||||
|
||||
if node.children.count > 0 {
|
||||
append(builder, " ");
|
||||
pretty_print_children(node, indentation, builder);
|
||||
}
|
||||
|
||||
append(builder, ")");
|
||||
}
|
||||
|
||||
Children_Print_Flags :: enum_flags {
|
||||
NewLine :: 1 << 0;
|
||||
Separator :: 1 << 1;
|
||||
Space :: 1 << 2;
|
||||
}
|
||||
|
||||
pretty_print_children :: (parent : *AST_Node, indentation : int, builder : *String_Builder, flags : Children_Print_Flags = .Separator) {
|
||||
if !parent {
|
||||
return;
|
||||
}
|
||||
|
||||
children := parent.children;
|
||||
for child : children {
|
||||
if it_index > 0 {
|
||||
indent(builder, indentation);
|
||||
}
|
||||
|
||||
if !child continue;
|
||||
pretty_print_node(child, 0, builder);
|
||||
|
||||
if it_index != children.count - 1 {
|
||||
if flags & .Separator {
|
||||
append(builder, ",");
|
||||
}
|
||||
|
||||
append(builder, " ");
|
||||
|
||||
if flags & .NewLine {
|
||||
append(builder, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
op_to_string :: (oper : Token) -> string {
|
||||
if oper.kind == {
|
||||
case .TOKEN_PLUS;
|
||||
return "+";
|
||||
case .TOKEN_MINUS;
|
||||
return "-";
|
||||
case .TOKEN_STAR;
|
||||
return "*";
|
||||
case .TOKEN_SLASH;
|
||||
return "/";
|
||||
case .TOKEN_ISEQUAL;
|
||||
return "==";
|
||||
case .TOKEN_ASSIGN;
|
||||
return "=";
|
||||
case .TOKEN_ISNOTEQUAL;
|
||||
return "!=";
|
||||
case .TOKEN_LOGICALOR;
|
||||
return "||";
|
||||
case .TOKEN_LOGICALAND;
|
||||
return "&&";
|
||||
case .TOKEN_LESS;
|
||||
return "<";
|
||||
case .TOKEN_LESSEQUALS;
|
||||
return "<=";
|
||||
case .TOKEN_GREATER;
|
||||
return ">";
|
||||
case .TOKEN_GREATEREQUALS;
|
||||
return ">=";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
pretty_print_binary :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
append(builder, "(");
|
||||
op := node.token;
|
||||
|
||||
print_to_builder(builder, op_to_string(op));
|
||||
append(builder, " ");
|
||||
|
||||
pretty_print_children(node, 0, builder, flags = 0);
|
||||
append(builder, ")");
|
||||
}
|
||||
|
||||
pretty_print_unary :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
|
||||
}
|
||||
|
||||
print_return_node :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
append(builder, "(return ");
|
||||
|
||||
pretty_print_children(node, 0, builder);
|
||||
|
||||
append(builder, ")");
|
||||
}
|
||||
|
||||
print_expression_statement :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
|
||||
if node.children[0] {
|
||||
pretty_print_node(node.children[0], indentation, builder);
|
||||
}
|
||||
}
|
||||
|
||||
pretty_print_node :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
if node.kind == {
|
||||
case .Return; {
|
||||
print_return_node(node, indentation, builder);
|
||||
}
|
||||
case .Struct;
|
||||
case .ArgList; {
|
||||
pretty_print_arglist(node, indentation + 2, builder);
|
||||
}
|
||||
case .FieldList; {
|
||||
pretty_print_fieldlist(node, indentation + 2, builder);
|
||||
}
|
||||
case .Field; {
|
||||
pretty_print_field(node, indentation, builder);
|
||||
}
|
||||
case .Unnamed_Field; {
|
||||
pretty_print_field(node, indentation, builder);
|
||||
}
|
||||
case .Block; {
|
||||
pretty_print_children(node, indentation + 2, builder, flags = .NewLine);
|
||||
}
|
||||
case .Binary; {
|
||||
pretty_print_binary(node, indentation, builder);
|
||||
}
|
||||
case .Unary; {
|
||||
pretty_print_unary(node, indentation, builder);
|
||||
}
|
||||
case .Variable; {
|
||||
pretty_print_variable(node, indentation, builder);
|
||||
}
|
||||
case .Expression_Statement; {
|
||||
print_expression_statement(node, indentation, builder);
|
||||
}
|
||||
case .Integer; {
|
||||
print_to_builder(builder, "%", node.integer_value);
|
||||
}
|
||||
case .Float; {
|
||||
print_to_builder(builder, "%", node.float_value);
|
||||
}
|
||||
case .Call; {
|
||||
pretty_print_call(node, indentation, builder);
|
||||
}
|
||||
case .Error; {
|
||||
print_to_builder(builder, "(error \"%\")", node.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pretty_print_variable :: (node : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
print_to_builder(builder, "%", node.name);
|
||||
for child : node.children {
|
||||
if child.kind == .Variable {
|
||||
append(builder, ".");
|
||||
pretty_print_variable(child, indentation, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pretty_print_declaration :: (declaration : *AST_Node, indentation : int, builder : *String_Builder) {
|
||||
indent(builder, indentation);
|
||||
append(builder, "(");
|
||||
|
||||
if declaration.foreign_declaration {
|
||||
append(builder, "foreign ");
|
||||
}
|
||||
|
||||
if declaration.kind == .Function {
|
||||
append(builder, "fun ");
|
||||
}
|
||||
|
||||
if declaration.vertex_entry_point {
|
||||
append(builder, "vertex ");
|
||||
}
|
||||
|
||||
if declaration.pixel_entry_point {
|
||||
append(builder, "pixel ");
|
||||
}
|
||||
|
||||
if declaration.kind == .Properties {
|
||||
append(builder, "properties");
|
||||
if declaration.name.count > 0 {
|
||||
print_to_builder(builder, " %", declaration.name);
|
||||
}
|
||||
} else if declaration.kind == .Instance {
|
||||
append(builder, "instance");
|
||||
} else if declaration.kind == .Meta {
|
||||
append(builder, "meta");
|
||||
}
|
||||
else {
|
||||
if declaration.kind == .Struct {
|
||||
append(builder, "struct ");
|
||||
}
|
||||
print_to_builder(builder, "%", declaration.name);
|
||||
}
|
||||
|
||||
if declaration.kind == .Function && declaration.token.kind == .TOKEN_IDENTIFIER{
|
||||
print_to_builder(builder, " -> %", declaration.token.ident_value);
|
||||
for hint : declaration.hint_tokens {
|
||||
if hint.string_value.count > 0 {
|
||||
print_to_builder(builder, " (@%)", hint.string_value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if declaration.children.count > 0 {
|
||||
print_to_builder(builder, "\n");
|
||||
pretty_print_children(declaration, indentation + 1, builder, flags = .NewLine);
|
||||
}
|
||||
|
||||
append(builder, ")");
|
||||
|
||||
}
|
||||
|
||||
pretty_print_ast :: (root : *AST_Node, allocator : Allocator) -> string {
|
||||
builder : String_Builder;
|
||||
init_string_builder(*builder,, allocator);
|
||||
|
||||
indentation := 0;
|
||||
|
||||
append(*builder, "(");
|
||||
append(*builder, "program\t\n");
|
||||
|
||||
indentation += 1;
|
||||
|
||||
declarations := root.children;
|
||||
|
||||
for declaration : declarations {
|
||||
pretty_print_declaration(declaration, indentation, *builder);
|
||||
|
||||
if it_index < declarations.count - 1 {
|
||||
append(*builder, "\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
append(*builder, ")");
|
||||
|
||||
return builder_to_string(*builder,, allocator);
|
||||
}
|
||||
|
||||
#scope_file
|
||||
indent :: (builder : *String_Builder, indentation : int) {
|
||||
for 0..indentation - 1 {
|
||||
append(builder, " ");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user