diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/common.c | 6 | ||||
| -rw-r--r-- | boot/lex.c | 36 | ||||
| -rw-r--r-- | boot/parse.c | 309 | ||||
| -rw-r--r-- | boot/tree.c | 296 |
4 files changed, 581 insertions, 66 deletions
diff --git a/boot/common.c b/boot/common.c index 65dc780..6851312 100644 --- a/boot/common.c +++ b/boot/common.c @@ -121,6 +121,12 @@ string_empty() }; } +bool +string_is_empty(struct String s) +{ + return s.data == nil || s.length == 0; +} + // allocates a new string in the global string region, // taking the data from a null-terminated C string. struct String diff --git a/boot/lex.c b/boot/lex.c index 6b6badc..52760e9 100644 --- a/boot/lex.c +++ b/boot/lex.c @@ -98,6 +98,8 @@ enum Token_Kind TOKEN_WORD_RETURN, TOKEN_WORD_VAR, TOKEN_WORD_TYPE, + TOKEN_WORD_VARIANT, + TOKEN_WORD_CLASS, TOKEN_WORD_TRUE, TOKEN_WORD_FALSE, @@ -200,6 +202,10 @@ token_kind_to_string(enum Token_Kind kind) return "WORD_VAR"; case TOKEN_WORD_TYPE: return "WORD_TYPE"; + case TOKEN_WORD_VARIANT: + return "WORD_VARIANT"; + case TOKEN_WORD_CLASS: + return "WORD_CLASS"; case TOKEN_WORD_TRUE: return "WORD_TRUE"; case TOKEN_WORD_FALSE: @@ -375,6 +381,32 @@ token_ends_statement(const struct Token* t) } bool +token_can_begin_type(const struct Token* t) +{ + switch (t->kind) { + // named type reference + case TOKEN_NAME: + + // keyword that introduces a type + case TOKEN_WORD_TYPE: + case TOKEN_WORD_VARIANT: + case TOKEN_WORD_CLASS: + case TOKEN_WORD_FUN: + + // arrays, tuples, maps and inline structures + case TOKEN_CURLY_OPEN: + case TOKEN_SQUARE_OPEN: + case TOKEN_ROUND_OPEN: + + // references + case TOKEN_AMPERSAND: + return true; + default: + return false; + } +} + +bool ascii_in_range(ascii c, ascii from, ascii to) { return c >= from && c <= to; @@ -763,6 +795,10 @@ lexer_word_from_name(struct Lexer* l, struct String word_or_name) return TOKEN_WORD_VAR; case 91700392: // "type" return TOKEN_WORD_TYPE; + case 3267162257: // "variant" + return TOKEN_WORD_VARIANT; + case 2938290531: // "class" + return TOKEN_WORD_CLASS; case 2588936279: // "true" return TOKEN_WORD_TRUE; case 1548710142: // "false" diff --git a/boot/parse.c b/boot/parse.c index 94b1e91..a0dd12c 100644 --- a/boot/parse.c +++ b/boot/parse.c @@ -166,6 +166,19 @@ parser_probe(struct Parser* p, enum Token_Kind kind) return token_is(&token, kind); } +// skip all consecutive newlines and other non-interrupting +// tokens in the token stream. +// necessary for parsing statements and expressions that are +// split-able over multiple lines. +// TODO: this needs to be used in many more places and +// is currently mostly redundant, due to only skipping newlines, +// acting mostly as a marking for `the tokens don't have to follow precisely`. +void +parser_unglue(struct Parser* p) +{ + while (parser_probe(p, TOKEN_NEWLINE)) parser_next(p); +} + struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error); struct Expression* parser_expression(struct Parser* p, struct Parser_Error* error); @@ -180,6 +193,7 @@ parser_end_statement(struct Parser* p, struct Parser_Error* error) parser_next(p); } +// checks if the next 2 tokens could begin a variable declaration. bool parser_could_be_variable_declaration(struct Parser* p) { @@ -189,11 +203,13 @@ parser_could_be_variable_declaration(struct Parser* p) // otherwise without a type, it is instead counted as an assignment: // a = "hi!" + // NOTE: maybe move this into `lex.c`? + // or change the API a bit, this isn't really a parser method. struct Token first = parser_peek(p); struct Token second = parser_peek_further(p); bool first_matches = token_is(&first, TOKEN_NAME); - bool second_matches = token_is(&second, TOKEN_COMMA) || token_is(&second, TOKEN_NAME); + bool second_matches = token_is(&second, TOKEN_COMMA) || token_can_begin_type(&second); return first_matches && second_matches; } @@ -203,6 +219,8 @@ parser_block_node(struct Parser* p, struct Parser_Error* error) struct Token start_token = CHECK_RETURN(parser_need(p, TOKEN_CURLY_OPEN, error), struct Block_Node); + parser_unglue(p); + struct Statement* head = nil; struct Statement* current = nil; @@ -229,24 +247,237 @@ parser_block_node(struct Parser* p, struct Parser_Error* error) }; } -struct Type_Node +struct Type_Node* parser_node_type(struct Parser* p, struct Parser_Error* error); + +struct Function_Header_Node +parser_function_header_node(struct Parser* p, struct Parser_Error* error) +{ + struct Token open_parameters_token = + CHECK_RETURN(parser_need(p, TOKEN_ROUND_OPEN, error), struct Function_Header_Node); + + struct Function_Header_Node header = { 0 }; + while (!parser_probe(p, TOKEN_ROUND_CLOSE)) { + struct Token name_token = + CHECK_RETURN(parser_need(p, TOKEN_NAME, error), struct Function_Header_Node); + struct String name = name_token.value.name; + + struct Type_Node* type; + if (!parser_probe(p, TOKEN_ROUND_CLOSE) && !parser_probe(p, TOKEN_COMMA)) { + type = CHECK_RETURN(parser_node_type(p, error), struct Function_Header_Node); + } else { + type = type_node_none(name_token.span, name_token.location); + } + + type->value_name = name; + if (!header.parameters_type_and_name) + header.parameters_type_and_name = type; + else + header.parameters_type_and_name->next = type; + + if (parser_probe(p, TOKEN_COMMA)) parser_next(p); + } + struct Token close_parameters_token = parser_next(p); + + header.span = span_merge(open_parameters_token.span, close_parameters_token.span); + + struct Token next = parser_peek(p); + if (token_can_begin_type(&next)) { + header.return_type = CHECK_RETURN(parser_node_type(p, error), struct Function_Header_Node); + header.span = span_merge(header.span, header.return_type->span); + } + + return header; +} + +struct Type_Node* +parser_node_type_name(struct Parser* p, struct Parser_Error* error) +{ + struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error)); + return type_node_new( + TYPE_NODE_NAME, (union Type_Node_Value){ .name = { name_token.value.name } }, + name_token.span, name_token.location); +} + +struct Type_Node* +parser_node_type_structure(struct Parser* p, struct Parser_Error* error) +{ + struct Token open_token = CHECK(parser_need(p, TOKEN_CURLY_OPEN, error)); + + parser_unglue(p); + + struct Type_Node* head = nil; + struct Type_Node* current = nil; + while (!parser_probe(p, TOKEN_CURLY_CLOSE)) { + struct Token field_name_token = CHECK(parser_need(p, TOKEN_NAME, error)); + + struct Type_Node* field_type = CHECK(parser_node_type(p, error)); + if (!field_type) { + *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); + return nil; + } + field_type->value_name = field_name_token.value.name; + + if (!head) + head = field_type; + else + current->next = field_type; + current = field_type; + + if (parser_probe(p, TOKEN_COMMA) || parser_probe(p, TOKEN_NEWLINE)) parser_next(p); + } + + parser_unglue(p); + + struct Token close_token = CHECK(parser_need(p, TOKEN_CURLY_CLOSE, error)); + struct Span span = span_merge(open_token.span, close_token.span); + + return type_node_new( + TYPE_NODE_STRUCTURE, (union Type_Node_Value){ .structure = { head } }, span, + open_token.location); +} + +struct Type_Node* +parser_node_type_variant(struct Parser* p, struct Parser_Error* error) +{ + // TODO + return nil; +} + +struct Type_Node* +parser_node_type_function(struct Parser* p, struct Parser_Error* error) +{ + struct Token fun_token = CHECK(parser_need(p, TOKEN_WORD_FUN, error)); + struct Function_Header_Node header = CHECK(parser_function_header_node(p, error)); + + struct Span span = span_merge(fun_token.span, header.span); + return type_node_new( + TYPE_NODE_FUNCTION, (union Type_Node_Value){ .function = { header } }, span, + fun_token.location); +} + +struct Type_Node* +parser_node_type_class(struct Parser* p, struct Parser_Error* error) +{ + // TODO + return nil; +} + +struct Type_Node* +parser_node_type_tuple(struct Parser* p, struct Parser_Error* error) +{ + struct Token open_token = CHECK(parser_need(p, TOKEN_ROUND_OPEN, error)); + + struct Type_Node* head = nil; + struct Type_Node* current = nil; + while (!parser_probe(p, TOKEN_ROUND_CLOSE)) { + struct Type_Node* type = CHECK(parser_node_type(p, error)); + if (!type) { + *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); + return nil; + } + + if (!head) + head = type; + else + current->next = type; + current = type; + + if (parser_probe(p, TOKEN_COMMA)) + parser_next(p); + else + break; + } + + struct Token close_token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error)); + struct Span span = span_merge(open_token.span, close_token.span); + return type_node_new( + TYPE_NODE_TUPLE, (union Type_Node_Value){ .tuple = { head } }, span, open_token.location); +} + +struct Type_Node* +parser_node_type_array_or_map(struct Parser* p, struct Parser_Error* error) +{ + struct Token open_token = CHECK(parser_need(p, TOKEN_SQUARE_OPEN, error)); + + struct Type_Node* element_or_key_type = CHECK(parser_node_type(p, error)); + if (!element_or_key_type) { + *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); + return nil; + } + + enum Type_Node_Type type; + union Type_Node_Value value; + if (parser_probe(p, TOKEN_ASSIGN)) { + // this is a map type, e.g. `[string = int]` + parser_next(p); // consume the assignment token + + struct Type_Node* key_type = element_or_key_type; + struct Type_Node* value_type = CHECK(parser_node_type(p, error)); + if (!value_type) { + *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); + return nil; + } + + type = TYPE_NODE_MAP; + value.map = (struct Type_Node_Map){ + .key_type = key_type, + .value_type = value_type, + }; + } else { + // this is an array type, e.g. `[int]` + type = TYPE_NODE_ARRAY; + value.array = (struct Type_Node_Array){ .element_type = element_or_key_type }; + } + + struct Token close_token = CHECK(parser_need(p, TOKEN_SQUARE_CLOSE, error)); + + struct Span span = span_merge(open_token.span, close_token.span); + return type_node_new(type, value, span, open_token.location); +} + +struct Type_Node* +parser_node_type_reference(struct Parser* p, struct Parser_Error* error) +{ + struct Token ampersand_token = CHECK(parser_need(p, TOKEN_AMPERSAND, error)); + + struct Type_Node* referenced_type = CHECK(parser_node_type(p, error)); + if (!referenced_type) { + *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); + return nil; + } + + struct Span span = span_merge(ampersand_token.span, referenced_type->span); + return type_node_new( + TYPE_NODE_REFERENCE, (union Type_Node_Value){ .reference = { referenced_type } }, span, + ampersand_token.location); +} + +struct Type_Node* parser_node_type(struct Parser* p, struct Parser_Error* error) { - struct Token token = parser_need(p, TOKEN_NAME, error); - if (token_is_empty(&token)) { + // TODO: maybe, variant, class + struct Token token = parser_peek(p); + switch (token.kind) { + case TOKEN_NAME: + return parser_node_type_name(p, error); + case TOKEN_WORD_VARIANT: + return parser_node_type_variant(p, error); + case TOKEN_WORD_CLASS: + return parser_node_type_class(p, error); + case TOKEN_WORD_FUN: + return parser_node_type_function(p, error); + case TOKEN_CURLY_OPEN: + return parser_node_type_structure(p, error); + case TOKEN_ROUND_OPEN: + return parser_node_type_tuple(p, error); + case TOKEN_SQUARE_OPEN: + return parser_node_type_array_or_map(p, error); + case TOKEN_AMPERSAND: + return parser_node_type_reference(p, error); + default: *error = parser_error(PARSER_ERROR_EXPECTED_TYPE); - return (struct Type_Node){ 0 }; + return nil; } - struct String type_name = token.value.name; - - // 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, - }; } struct Expression* @@ -308,31 +539,9 @@ 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.header = CHECK(parser_function_header_node(p, error)); fun.body = CHECK(parser_block_node(p, error)); return expression_new( @@ -603,7 +812,7 @@ parser_statement_declaration(struct Parser* p, struct Parser_Error* error) } // for now, type is always required. - struct Type_Node type = CHECK(parser_node_type(p, error)); + struct Type_Node* type = CHECK(parser_node_type(p, error)); CHECK(parser_need(p, TOKEN_ASSIGN, error)); struct Expression* initializer = CHECK(parser_expression(p, error)); @@ -771,6 +980,23 @@ parser_statement_defer(struct Parser* p, struct Parser_Error* error) } struct Statement* +parser_statement_type(struct Parser* p, struct Parser_Error* error) +{ + struct Token type_token = CHECK(parser_need(p, TOKEN_WORD_TYPE, error)); + + // TODO: parse type paths, i.e. `Thing.SubType` + struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error)); + CHECK(parser_need(p, TOKEN_ASSIGN, error)); + struct String name = name_token.value.name; + + struct Type_Node* type = CHECK(parser_node_type(p, error)); + + struct Span span = span_merge(type_token.span, type->span); + union Statement_Value value = { .type = { type, name } }; + return statement_new(STATEMENT_TYPE, value, span, type_token.location); +} + +struct Statement* parser_statement(struct Parser* p, struct Parser_Error* error) { struct Token token = parser_peek(p); @@ -798,7 +1024,10 @@ parser_statement(struct Parser* p, struct Parser_Error* error) return parser_statement_continue(p, error); case TOKEN_WORD_DEFER: return parser_statement_defer(p, error); - default: break; + case TOKEN_WORD_TYPE: + return parser_statement_type(p, error); + default: + break; } struct Expression* expression = CHECK(parser_expression(p, error)); 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 = ®ion_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(¤t->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; |
