about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--boot/parse.c40
-rw-r--r--boot/tree.c52
2 files changed, 85 insertions, 7 deletions
diff --git a/boot/parse.c b/boot/parse.c
index ed00f94..3870e6c 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -225,6 +225,7 @@ parser_node_type(struct Parser* p, struct Parser_Error* error)
     // for now, we only support a single type name.
     // in the future, we might want to support more complex types.
     return (struct Type_Node){
+        .type = TYPE_NAME,
         .name = type_name,
         .span = token.span,
         .location = token.location,
@@ -287,6 +288,42 @@ parser_expression_primary_group(struct Parser* p, struct Parser_Error* error)
 }
 
 struct Expression*
+parser_expression_function(struct Parser* p, struct Parser_Error* error)
+{
+    struct Token fun_token = CHECK(parser_need(p, TOKEN_WORD_FUN, error));
+    CHECK(parser_need(p, TOKEN_ROUND_OPEN, error));
+
+    struct Expression_Function fun = { 0 };
+    while (!parser_probe(p, TOKEN_ROUND_CLOSE)) {
+        struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error));
+        struct String name = name_token.value.name;
+
+        struct Type_Node type = { 0 };
+
+        struct Token next = parser_peek(p);
+        if (!token_is(&next, TOKEN_ROUND_CLOSE) && !token_is(&next, TOKEN_COMMA))
+            type = CHECK(parser_node_type(p, error));
+
+        if (parser_probe(p, TOKEN_COMMA)) parser_next(p);
+
+        check(fun.parameter_count < EXPRESSION_FUNCTION_MAX_PARAMS, "too many function parameters");
+        fun.parameters[fun.parameter_count++] = (struct Expression_Function_Parameter){
+            .name = name,
+            .type = type,
+        };
+    }
+    parser_next(p);
+
+    if (!parser_probe(p, TOKEN_CURLY_OPEN)) fun.return_type = CHECK(parser_node_type(p, error));
+
+    fun.body = CHECK(parser_block_node(p, error));
+
+    return expression_new(
+        EXPRESSION_FUNCTION, (union Expression_Value){ .function = fun },
+        span_merge(fun_token.span, fun.body.span), fun_token.location);
+}
+
+struct Expression*
 parser_expression_primary(struct Parser* p, struct Parser_Error* error)
 {
     struct Token token = parser_peek(p);
@@ -304,6 +341,8 @@ parser_expression_primary(struct Parser* p, struct Parser_Error* error)
         return parser_expression_primary_boolean(p, error);
     case TOKEN_ROUND_OPEN:
         return parser_expression_primary_group(p, error);
+    case TOKEN_WORD_FUN:
+        return parser_expression_function(p, error);
     default:
         *error = parser_error(PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION);
         return nil;
@@ -522,7 +561,6 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error)
     union Statement_Value value = {
         .declaration = {
             .names = names,
-            .has_type = true,
             .type = type,
             .initializer = initializer,
         },
diff --git a/boot/tree.c b/boot/tree.c
index dcda4da..64eb23b 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -335,10 +335,20 @@ struct Block_Node
     struct Cursor location;
 };
 
+void block_node_print(const struct Block_Node* block);
+
+enum Type_Type
+{
+    TYPE_NONE,
+    TYPE_NAME,
+};
+
 // a type node represents a type in the syntax tree.
 // currently, we only support types that are simple names.
+// or null types.
 struct Type_Node
 {
+    enum Type_Type type;
     // note: we could also just include the token here i think?
     struct String name;
     struct Span span;
@@ -362,6 +372,8 @@ enum Expression_Kind
     EXPRESSION_CALL,
     EXPRESSION_SUBSCRIPT,
     EXPRESSION_MEMBER,
+
+    EXPRESSION_FUNCTION,
 };
 
 struct Expression_Integer_Literal
@@ -425,6 +437,21 @@ struct Expression_Member
     struct String name;
 };
 
+#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 Block_Node body;
+};
+
 union Expression_Value
 {
     struct Expression_Integer_Literal integer_literal;
@@ -438,6 +465,7 @@ union Expression_Value
     struct Expression_Call call;
     struct Expression_Subscript subscript;
     struct Expression_Member member;
+    struct Expression_Function function;
 };
 
 struct Expression
@@ -535,6 +563,20 @@ expression_print(const struct Expression* expression)
         expression_print(expression->value.member.subject);
         printf(")");
         break;
+    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(" ");
+        block_node_print(&fun->body);
+        printf(")");
+        break;
+    }
     default:
         failure("unexpected expression kind passed to `expression_print`");
         break;
@@ -559,11 +601,9 @@ struct Statement_Value_Expression
 
 struct Statement_Value_Declaration
 {
-    struct String_Array names;      // the names of the variables being declared.
-    struct Expression* initializer; // the expression to initialize the variable with.
-
-    bool has_type;         // whether the declaration has a type.
-    struct Type_Node type; // the type of the variable, if any.
+    struct String_Array names;
+    struct Expression* initializer;
+    struct Type_Node type;
 };
 
 struct Statement_Value_Block
@@ -657,7 +697,7 @@ statement_print(const struct Statement* statement)
         {
             printf("%s ", name.data);
         }
-        if (statement->value.declaration.has_type) {
+        if (statement->value.declaration.type.type != TYPE_NONE) {
             printf("(type %s) ", statement->value.declaration.type.name.data);
         }
         if (statement->value.declaration.initializer) {