about summary refs log tree commit diff
path: root/boot/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'boot/tree.c')
-rw-r--r--boot/tree.c296
1 files changed, 270 insertions, 26 deletions
diff --git a/boot/tree.c b/boot/tree.c
index 39a1de4..449f4e6 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -394,24 +394,247 @@ struct Block_Node
 
 void block_node_print(const struct Block_Node* block);
 
-enum Type_Type
+// a function header, describing the parameters and return type of function.
+// used both as a type and in full function definitions.
+struct Function_Header_Node
 {
-    TYPE_NONE,
-    TYPE_NAME,
+    // linked list of parameters.
+    // name, if given, is included in the type node.
+    struct Type_Node* parameters_type_and_name;
+    struct Type_Node* return_type;
+
+    struct Span span;
+};
+
+void function_header_node_print(const struct Function_Header_Node* header);
+
+enum Type_Node_Type
+{
+    TYPE_NODE_NONE,
+
+    TYPE_NODE_NAME,
+    TYPE_NODE_ARRAY,     // an array of a type, `[int]`.
+    TYPE_NODE_REFERENCE, // a reference to a type, `&int`.
+    TYPE_NODE_MAYBE,     // a type that may be null, `int?`.
+    TYPE_NODE_TUPLE,     // a tuple type, `(int string)`.
+    TYPE_NODE_MAP,       // a map type, `[string = int]`.
+
+    TYPE_NODE_FUNCTION,  // a function type, `fun (int) int`.
+    TYPE_NODE_STRUCTURE, // a struct, invoked either with `type` or with `{}` when a type is inline.
+    TYPE_NODE_VARIANT,   // a tagged union.
+    TYPE_NODE_CLASS,     // a class of types, a.k.a. an interface.
+};
+
+struct Type_Node_Name
+{
+    struct String name;
+};
+
+struct Type_Node_Array
+{
+    struct Type_Node* element_type;
+};
+
+struct Type_Node_Reference
+{
+    struct Type_Node* referenced_type;
+};
+
+struct Type_Node_Maybe
+{
+    struct Type_Node* inner_type;
+};
+
+struct Type_Node_Tuple
+{
+    struct Type_Node* head; // the first type in the tuple, if any.
+};
+
+struct Type_Node_Map
+{
+    struct Type_Node* key_type;
+    struct Type_Node* value_type;
+};
+
+struct Type_Node_Function
+{
+    struct Function_Header_Node header;
+};
+
+struct Type_Node_Structure
+{
+    // the fields of the structure, linked list of types and (required) names.
+    struct Type_Node* fields;
+};
+
+struct Type_Node_Variant
+{
+    // the variants of the tagged union, linked list of (required) variant names and backing types.
+    // if a variant has no backing type, it is TYPE_NODE_NONE.
+    struct Type_Node* variants;
+};
+
+struct Type_Node_Class
+{
+    // linked list of the types of methods required to implement the class.
+    // each node is required to have a name and be of TYPE_NODE_FUNCTION.
+    struct Type_Node* methods;
+};
+
+union Type_Node_Value
+{
+    struct Type_Node_Name name;
+    struct Type_Node_Array array;
+    struct Type_Node_Reference reference;
+    struct Type_Node_Maybe maybe;
+    struct Type_Node_Tuple tuple;
+    struct Type_Node_Map map;
+    struct Type_Node_Function function;
+    struct Type_Node_Structure structure;
+    struct Type_Node_Variant variant;
+    struct Type_Node_Class class;
 };
 
 // a type node represents a type in the syntax tree.
 // currently, we only support types that are simple names.
 // or null types.
+// also includes the name of the field, member, parameter, etc., for which
+// the type is defined.
 struct Type_Node
 {
-    enum Type_Type type;
+    enum Type_Node_Type type;
+    union Type_Node_Value value;
     // note: we could also just include the token here i think?
-    struct String name;
     struct Span span;
     struct Cursor location;
+
+    // usually a type is preceded by the name of the binding
+    // it is assigned to, e.g. `x int`, `string y`, etc.
+    // this is the name of that binding, for ease of listing.
+    struct String value_name;
+
+    // if type is within a group of multiple types,
+    // points to the next type within the group.
+    struct Type_Node* next;
 };
 
+REGION(struct Type_Node, type_node)
+
+// allocates a new type node in the global type node region.
+struct Type_Node*
+type_node_new(
+    enum Type_Node_Type type, union Type_Node_Value value, struct Span span, struct Cursor location)
+{
+    check(region_type_node_cursor < REGION_SIZE, "out of type node memory");
+    struct Type_Node* type_node = &region_type_node[region_type_node_cursor++];
+    *type_node = (struct Type_Node){
+        .type = type,
+        .value = value,
+        .span = span,
+        .location = location,
+
+        .value_name = string_empty(),
+        .next = nil,
+    };
+    return type_node;
+}
+
+// allocates a new type node with no value, used for `none` types.
+// this is used for types that are not specified, note that it is still
+// fully allocated and can be used in the syntax tree.
+struct Type_Node*
+type_node_none(struct Span span, struct Cursor location)
+{
+    return type_node_new(TYPE_NODE_NONE, (union Type_Node_Value){ 0 }, span, location);
+}
+
+bool
+type_node_is_none(const struct Type_Node* type_node)
+{
+    return type_node->type == TYPE_NODE_NONE;
+}
+
+void
+type_node_print(const struct Type_Node* type_node)
+{
+    printf("(type ");
+    switch (type_node->type) {
+    case TYPE_NODE_NONE:
+        printf("none");
+        break;
+    case TYPE_NODE_NAME:
+        printf("name %s", type_node->value.name.name.data);
+        break;
+    case TYPE_NODE_ARRAY:
+        printf("array of ");
+        type_node_print(type_node->value.array.element_type);
+        break;
+    case TYPE_NODE_REFERENCE:
+        printf("reference to ");
+        type_node_print(type_node->value.reference.referenced_type);
+        break;
+    case TYPE_NODE_MAYBE:
+        printf("maybe ");
+        type_node_print(type_node->value.maybe.inner_type);
+        break;
+    case TYPE_NODE_TUPLE: {
+        printf("tuple");
+        FOR_EACH(struct Type_Node*, current, type_node->value.tuple.head)
+        {
+            printf(" ");
+            type_node_print(current);
+        }
+        break;
+    }
+    case TYPE_NODE_MAP:
+        printf("map ");
+        type_node_print(type_node->value.map.key_type);
+        printf(" = ");
+        type_node_print(type_node->value.map.value_type);
+        break;
+    case TYPE_NODE_FUNCTION: {
+        printf("function ");
+        function_header_node_print(&type_node->value.function.header);
+        break;
+    }
+    case TYPE_NODE_STRUCTURE: {
+        printf("structure");
+        FOR_EACH(struct Type_Node*, current, type_node->value.structure.fields)
+        {
+            printf(" (field %s) ", current->value_name.data);
+            type_node_print(current);
+        }
+        break;
+    }
+    case TYPE_NODE_VARIANT: {
+        printf("variant");
+        FOR_EACH(struct Type_Node*, current, type_node->value.variant.variants)
+        {
+            if (type_node_is_none(current)) {
+                printf(" (variant %s)", current->value_name.data);
+            } else {
+                printf(" (variant %s of ", current->value_name.data);
+                type_node_print(current);
+                printf(")");
+            }
+        }
+        break;
+    }
+    case TYPE_NODE_CLASS:
+        printf("class");
+        FOR_EACH(struct Type_Node*, current, type_node->value.class.methods)
+        {
+            check(current->type == TYPE_NODE_FUNCTION,
+                  "expected class method type node to be a function type");
+            printf(" (method %s ", current->value_name.data);
+            function_header_node_print(&current->value.function.header);
+            printf(")");
+        }
+        break;
+    }
+    printf(")");
+}
+
 enum Expression_Kind
 {
     EXPRESSION_NONE,
@@ -503,18 +726,9 @@ struct Expression_Increment_Decrement
     enum Increment_Decrement_Operation operation;
 };
 
-#define EXPRESSION_FUNCTION_MAX_PARAMS 32
-
 struct Expression_Function
 {
-    struct Expression_Function_Parameter
-    {
-        struct String name;
-        struct Type_Node type;
-    } parameters[EXPRESSION_FUNCTION_MAX_PARAMS];
-    uint parameter_count;
-
-    struct Type_Node return_type;
+    struct Function_Header_Node header;
     struct Block_Node body;
 };
 
@@ -568,6 +782,28 @@ expression_new(
 }
 
 void
+function_header_node_print(const struct Function_Header_Node* header)
+{
+    FOR_EACH(struct Type_Node*, current, header->parameters_type_and_name)
+    {
+        if (current != header->parameters_type_and_name) printf(" ");
+
+        if (!string_is_empty(current->value_name))
+            printf("(param %s) ", current->value_name.data);
+        else
+            printf("(param) ");
+
+        type_node_print(current);
+    }
+
+    if (header->return_type) {
+        printf(" (returns ");
+        type_node_print(header->return_type);
+        printf(")");
+    }
+}
+
+void
 expression_print(const struct Expression* expression)
 {
     printf("(expr ");
@@ -641,13 +877,8 @@ expression_print(const struct Expression* expression)
     }
     case EXPRESSION_FUNCTION: {
         const struct Expression_Function* fun = &expression->value.function;
-        printf("(function");
-        for (uint i = 0; i < fun->parameter_count; ++i) {
-            const struct Expression_Function_Parameter* param = &fun->parameters[i];
-            printf(" (param %s)", param->name.data);
-            if (param->type.type != TYPE_NONE) { printf(" (type %s)", param->type.name.data); }
-        }
-        if (fun->return_type.type != TYPE_NONE) printf(" (returns %s)", fun->return_type.name.data);
+        printf("(function ");
+        function_header_node_print(&fun->header);
         printf(" ");
         block_node_print(&fun->body);
         printf(")");
@@ -673,6 +904,7 @@ enum Statement_Kind
     STATEMENT_BREAK,
     STATEMENT_CONTINUE,
     STATEMENT_DEFER,
+    STATEMENT_TYPE,
 };
 
 struct Statement_Value_Expression
@@ -684,7 +916,7 @@ struct Statement_Value_Declaration
 {
     struct String_Array names;
     struct Expression* initializer;
-    struct Type_Node type;
+    struct Type_Node* type;
 };
 
 struct Statement_Value_Block
@@ -731,6 +963,12 @@ struct Statement_Value_Defer
     struct Block_Node block;
 };
 
+struct Statement_Value_Type
+{
+    struct Type_Node* type;
+    struct String name;
+};
+
 union Statement_Value
 {
     struct Statement_Value_Expression expression;
@@ -740,6 +978,7 @@ union Statement_Value
     struct Statement_Value_Loop loop;
     struct Statement_Value_Return return_value;
     struct Statement_Value_Defer defer;
+    struct Statement_Value_Type type;
 };
 
 struct Statement
@@ -807,9 +1046,9 @@ statement_print(const struct Statement* statement)
         {
             printf("%s ", name.data);
         }
-        if (statement->value.declaration.type.type != TYPE_NONE) {
-            printf("(type %s) ", statement->value.declaration.type.name.data);
-        }
+        if (type_node_is_none(statement->value.declaration.type))
+            type_node_print(statement->value.declaration.type);
+
         if (statement->value.declaration.initializer) {
             printf("(initializer ");
             expression_print(statement->value.declaration.initializer);
@@ -889,6 +1128,11 @@ statement_print(const struct Statement* statement)
         printf(")");
         break;
     }
+    case STATEMENT_TYPE: {
+        printf("(type name %s) ", statement->value.type.name.data);
+        type_node_print(statement->value.type.type);
+        break;
+    }
     default:
         failure("unexpected statement kind passed to `statement_print`");
         break;