aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/parse.c115
-rw-r--r--boot/tests/parse/postfix_chaining.cskt2
-rw-r--r--boot/tree.c35
-rw-r--r--boot/visit.c95
4 files changed, 177 insertions, 70 deletions
diff --git a/boot/parse.c b/boot/parse.c
index 6363379..4403024 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -30,6 +30,7 @@ enum Parser_Error_Kind
PARSER_ERROR_EXPECTED_STATEMENT_END,
PARSER_ERROR_EXPECTED_PRIMARY_EXPRESSION,
PARSER_ERROR_EXPECTED_TYPE,
+ PARSER_ERROR_EXPECTED_ARGUMENTS,
PARSER_ERROR_EXPECTED_PRAGMA,
PARSER_ERROR_EXPECTED_PRAGMA_ARGUMENT
};
@@ -50,6 +51,8 @@ parser_error_kind_to_string(enum Parser_Error_Kind error_kind)
return "expected primary expression";
case PARSER_ERROR_EXPECTED_TYPE:
return "expected type";
+ case PARSER_ERROR_EXPECTED_ARGUMENTS:
+ return "expected arguments";
case PARSER_ERROR_EXPECTED_PRAGMA:
return "expected pragma";
case PARSER_ERROR_EXPECTED_PRAGMA_ARGUMENT:
@@ -467,6 +470,45 @@ parser_function_header_node(struct Parser* p, struct Parser_Error* error)
return header;
}
+struct Argument_Group_Node
+parser_argument_group_node(struct Parser* p, struct Parser_Error* error)
+{
+ struct String_Array argument_names = string_array_new();
+ struct Expression *arguments_head = nil, *arguments_current = nil;
+ for (;;) {
+ // check if we have a named argument.
+ struct String name = string_empty();
+ struct Token name_token = parser_peek(p), next = parser_peek_further(p);
+ if (token_is(&name_token, TOKEN_NAME) && token_is(&next, TOKEN_ASSIGN)) {
+ parser_next(p);
+ parser_next(p);
+ name = name_token.value.name;
+ }
+
+ struct Expression* argument =
+ CHECK_RETURN(parser_expression(p, error), struct Argument_Group_Node);
+ if (!arguments_head)
+ arguments_head = argument;
+ else
+ arguments_current->next = argument;
+ arguments_current = argument;
+
+ // if we have a named argument, we need to add it to the names array,
+ // otherwise we just add an empty string.
+ string_array_add(&argument_names, name);
+
+ if (parser_probe(p, TOKEN_COMMA)) {
+ parser_next(p);
+ } else {
+ break;
+ }
+ }
+
+ return (struct Argument_Group_Node){
+ .arguments = arguments_head, .argument_names = argument_names
+ };
+}
+
struct Bare_Declaration_Node
parser_bare_declaration_node(struct Parser* p, struct Parser_Error* error)
{
@@ -990,46 +1032,46 @@ parser_expression_postfix_member(
}
struct Expression*
-parser_expression_postfix_call_or_construct(
+parser_expression_postfix_call(
struct Parser* p, struct Expression* subject, struct Parser_Error* error)
{
- // calls and constructs look identical in the parser.
- // * call: `meow_function(123, "hello")`
- // * construct: `Meow(num = 123, str = "hello")`
CHECK(parser_need(p, TOKEN_ROUND_OPEN, error));
+ parser_unglue(p);
- struct String_Array argument_names = string_array_new();
- struct Expression *arguments_head = nil, *arguments_current = nil;
- while (!parser_probe(p, TOKEN_ROUND_CLOSE)) {
- // check if we have a named argument.
- struct String name = string_empty();
- struct Token name_token = parser_peek(p), next = parser_peek_further(p);
- if (token_is(&name_token, TOKEN_NAME) && token_is(&next, TOKEN_ASSIGN)) {
- parser_next(p);
- parser_next(p);
- name = name_token.value.name;
- }
+ struct Argument_Group_Node argument_group = parser_argument_group_node(p, error);
+ if (!parser_error_is_none(error)) {
+ parser_error_wrap(error, PARSER_ERROR_EXPECTED_ARGUMENTS);
+ return nil;
+ }
- struct Expression* argument = CHECK(parser_expression(p, error));
- if (!arguments_head)
- arguments_head = argument;
- else
- arguments_current->next = argument;
- arguments_current = argument;
+ parser_unglue(p);
+ struct Token close_token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error));
- // if we have a named argument, we need to add it to the names array,
- // otherwise we just add an empty string.
- string_array_add(&argument_names, name);
+ struct Span span = span_merge(subject->span, close_token.span);
+ union Expression_Value value = { .call = { subject, argument_group } };
+ return expression_new(EXPRESSION_CALL, value, span, close_token.location);
+}
- if (parser_probe(p, TOKEN_COMMA)) parser_next(p);
+struct Expression*
+parser_expression_postfix_construct(
+ struct Parser* p, struct Expression* subject, struct Parser_Error* error)
+{
+ CHECK(parser_need(p, TOKEN_CURLY_OPEN, error));
+ parser_unglue(p);
+
+ struct Argument_Group_Node argument_group = parser_argument_group_node(p, error);
+ if (!parser_error_is_none(error)) {
+ parser_error_wrap(error, PARSER_ERROR_EXPECTED_ARGUMENTS);
+ return nil;
}
- struct Token token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error));
+ parser_unglue(p);
+ struct Token token = CHECK(parser_need(p, TOKEN_CURLY_CLOSE, error));
+
struct Span span = span_merge(subject->span, token.span);
- union Expression_Value value = {
- .call_or_construct = { subject, arguments_head, argument_names }
- };
- return expression_new(EXPRESSION_CALL_OR_CONSTRUCT, value, span, token.location);
+ // TODO: convert the `subject` expression to a type node? somehow?
+ union Expression_Value value = { .construct = { subject, argument_group } };
+ return expression_new(EXPRESSION_CONSTRUCT, value, span, token.location);
}
struct Expression*
@@ -1096,19 +1138,22 @@ parser_expression_postfix(struct Parser* p, struct Parser_Error* error)
struct Token token = parser_peek(p);
switch (token.kind) {
case TOKEN_ROUND_OPEN:
- expression = parser_expression_postfix_call_or_construct(p, expression, error);
+ expression = CHECK(parser_expression_postfix_call(p, expression, error));
+ continue;
+ case TOKEN_CURLY_OPEN:
+ expression = CHECK(parser_expression_postfix_construct(p, expression, error));
continue;
case TOKEN_SQUARE_OPEN:
- expression = parser_expression_postfix_subscript(p, expression, error);
+ expression = CHECK(parser_expression_postfix_subscript(p, expression, error));
continue;
case TOKEN_DOT:
- expression = parser_expression_postfix_member(p, expression, error);
+ expression = CHECK(parser_expression_postfix_member(p, expression, error));
continue;
case TOKEN_QUESTION:
- expression = parser_expression_postfix_try(p, expression, error);
+ expression = CHECK(parser_expression_postfix_try(p, expression, error));
continue;
case TOKEN_BANG:
- expression = parser_expression_postfix_must(p, expression, error);
+ expression = CHECK(parser_expression_postfix_must(p, expression, error));
continue;
default:;
}
diff --git a/boot/tests/parse/postfix_chaining.cskt b/boot/tests/parse/postfix_chaining.cskt
index c2267b4..cbc3072 100644
--- a/boot/tests/parse/postfix_chaining.cskt
+++ b/boot/tests/parse/postfix_chaining.cskt
@@ -10,4 +10,4 @@ a.b("hi")!?++--
>>>
(expr (subscript (expr (subscript (expr (subscript (expr (name a)) (expr 1))) (expr 2))) (expr 3)))
-(expr (increment/decrement -- postfix (expr (increment/decrement ++ postfix (expr (try (expr (must (expr (call/construct (expr (member of (expr (name a)) named b)) (arg (expr "hi")))))))))))) \ No newline at end of file
+(expr (increment/decrement -- postfix (expr (increment/decrement ++ postfix (expr (try (expr (must (expr (call (expr (member of (expr (name a)) named b)) (arg (expr "hi")))))))))))) \ No newline at end of file
diff --git a/boot/tree.c b/boot/tree.c
index 4320279..228bbd4 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -423,6 +423,19 @@ struct Function_Header_Node
struct Cursor location;
};
+// a group of arguments, used in function calls and
+// constructions.
+// styled as either `1, 2, 3` or, when optional names
+// are given `a = 1, b = 2, c = 3`.
+struct Argument_Group_Node
+{
+ // linked list of argument expressions.
+ struct Expression* arguments;
+ // names of the arguments, if given.
+ // an unnamed argument is represented as an empty string.
+ struct String_Array argument_names;
+};
+
// a declaration of a variable, constant, or other binding, without a mutability
// signifier, like `let` or `var`.
// the mutability is determined by some outside context, where
@@ -698,7 +711,8 @@ enum Expression_Kind
EXPRESSION_BINARY_OPERATION,
EXPRESSION_GROUP,
- EXPRESSION_CALL_OR_CONSTRUCT,
+ EXPRESSION_CONSTRUCT,
+ EXPRESSION_CALL,
EXPRESSION_SUBSCRIPT,
EXPRESSION_MEMBER,
EXPRESSION_INCREMENT_DECREMENT,
@@ -752,14 +766,18 @@ struct Expression_Group
struct Expression* inner_expression;
};
-struct Expression_Call_Or_Construct
+struct Expression_Call
{
struct Expression* subject;
- // linked list of argument expressions.
- struct Expression* arguments;
- // names of the arguments, if given.
- // an unnamed argument is represented as an empty string.
- struct String_Array argument_names;
+ struct Argument_Group_Node argument_group;
+};
+
+struct Expression_Construct
+{
+ // this should be the type to construct, e.g. `int` or `string` or a generic like `Maybe(X)`
+ // right now, we can't guarantee it fully.
+ struct Expression* subject;
+ struct Argument_Group_Node argument_group;
};
struct Expression_Subscript
@@ -813,7 +831,8 @@ union Expression_Value
struct Expression_Unary_Operator unary_operator;
struct Expression_Binary_Operator binary_operator;
struct Expression_Group group;
- struct Expression_Call_Or_Construct call_or_construct;
+ struct Expression_Call call;
+ struct Expression_Construct construct;
struct Expression_Subscript subscript;
struct Expression_Member member;
struct Expression_Increment_Decrement increment_decrement;
diff --git a/boot/visit.c b/boot/visit.c
index 68e95bf..fa49a7d 100644
--- a/boot/visit.c
+++ b/boot/visit.c
@@ -41,7 +41,8 @@ struct Visit_Table
void (*visit_expression_unary_operation)(struct Visit* visitor, struct Expression* expr);
void (*visit_expression_binary_operation)(struct Visit* visitor, struct Expression* expr);
void (*visit_expression_group)(struct Visit* visitor, struct Expression* expr);
- void (*visit_expression_call_or_construct)(struct Visit* visitor, struct Expression* expr);
+ void (*visit_expression_call)(struct Visit* visitor, struct Expression* expr);
+ void (*visit_expression_construct)(struct Visit* visitor, struct Expression* expr);
void (*visit_expression_subscript)(struct Visit* visitor, struct Expression* expr);
void (*visit_expression_member)(struct Visit* visitor, struct Expression* expr);
void (*visit_expression_increment_decrement)(struct Visit* visitor, struct Expression* expr);
@@ -64,6 +65,7 @@ struct Visit_Table
void (*visit_block_node)(struct Visit* visitor, struct Block_Node* node);
void (*visit_bare_declaration_node)(struct Visit* visitor, struct Bare_Declaration_Node* node);
void (*visit_function_header_node)(struct Visit* visitor, struct Function_Header_Node* header);
+ void (*visit_argument_group_node)(struct Visit* visitor, struct Argument_Group_Node* node);
void (*visit_pragma_node)(struct Visit* visitor, struct Pragma_Node* node);
};
@@ -209,8 +211,11 @@ walk_expression(struct Visit* visit, struct Expression* expression)
case EXPRESSION_GROUP:
VISIT(visit_expression_group, expression);
break;
- case EXPRESSION_CALL_OR_CONSTRUCT:
- VISIT(visit_expression_call_or_construct, expression);
+ case EXPRESSION_CALL:
+ VISIT(visit_expression_call, expression);
+ break;
+ case EXPRESSION_CONSTRUCT:
+ VISIT(visit_expression_construct, expression);
break;
case EXPRESSION_SUBSCRIPT:
VISIT(visit_expression_subscript, expression);
@@ -268,11 +273,19 @@ walk_expression_group(struct Visit* visit, struct Expression* expression)
}
void
-walk_expression_call_or_construct(struct Visit* visit, struct Expression* expression)
+walk_expression_call(struct Visit* visit, struct Expression* expression)
+{
+ struct Expression_Call* call = &expression->value.call;
+ VISIT(visit_expression, call->subject);
+ VISIT(visit_argument_group_node, &call->argument_group);
+}
+
+void
+walk_expression_construct(struct Visit* visit, struct Expression* expression)
{
- struct Expression_Call_Or_Construct* coc = &expression->value.call_or_construct;
- VISIT(visit_expression, coc->subject);
- FOR_EACH (struct Expression*, argument, coc->arguments) { VISIT(visit_expression, argument); }
+ struct Expression_Construct* construct = &expression->value.construct;
+ VISIT(visit_expression, construct->subject);
+ VISIT(visit_argument_group_node, &construct->argument_group);
}
void
@@ -434,6 +447,12 @@ walk_function_header_node(struct Visit* visit, struct Function_Header_Node* head
}
void
+walk_argument_group_node(struct Visit* visit, struct Argument_Group_Node* node)
+{
+ FOR_EACH (struct Expression*, argument, node->arguments) { VISIT(visit_expression, argument); }
+}
+
+void
walk_pragma_node(struct Visit* visit, struct Pragma_Node* node)
{
// visit each pragma node in the linked list.
@@ -461,7 +480,8 @@ struct Visit_Table walk_functions = {
.visit_expression_unary_operation = walk_expression_unary_operation,
.visit_expression_binary_operation = walk_expression_binary_operation,
.visit_expression_group = walk_expression_group,
- .visit_expression_call_or_construct = walk_expression_call_or_construct,
+ .visit_expression_call = walk_expression_call,
+ .visit_expression_construct = walk_expression_construct,
.visit_expression_subscript = walk_expression_subscript,
.visit_expression_member = walk_expression_member,
.visit_expression_increment_decrement = walk_expression_increment_decrement,
@@ -482,6 +502,7 @@ struct Visit_Table walk_functions = {
.visit_block_node = walk_block_node,
.visit_bare_declaration_node = walk_bare_declaration_node,
.visit_function_header_node = walk_function_header_node,
+ .visit_argument_group_node = walk_argument_group_node,
.visit_pragma_node = walk_pragma_node,
};
@@ -769,25 +790,28 @@ printer_visit_expression_group(struct Visit* visit, struct Expression* expr)
}
void
-printer_visit_expression_call_or_construct(struct Visit* visit, struct Expression* expr)
+printer_visit_expression_call(struct Visit* visit, struct Expression* expr)
{
TREE_PRINTER_PREAMBLE
- struct Expression_Call_Or_Construct* coc = &expr->value.call_or_construct;
- PRINT("(call/construct ");
- VISIT(visit_expression, coc->subject);
+ struct Expression_Call* call = &expr->value.call;
+ PRINT("(call ");
+ VISIT(visit_expression, call->subject);
+ VISIT(visit_argument_group_node, &call->argument_group);
+
+ PRINT(")");
+}
+
+void
+printer_visit_expression_construct(struct Visit* visit, struct Expression* expr)
+{
+ TREE_PRINTER_PREAMBLE
+
+ struct Expression_Construct* construct = &expr->value.construct;
+ PRINT("(construct ");
+ VISIT(visit_expression, construct->subject);
+ VISIT(visit_argument_group_node, &construct->argument_group);
- uint i = 0;
- FOR_EACH (struct Expression*, argument, coc->arguments) {
- struct String name = string_array_at(&coc->argument_names, i++);
- if (name.data && name.data[0] != '\0') {
- PRINT(" (named arg '%s' ", name.data);
- } else {
- PRINT(" (arg ");
- }
- VISIT(visit_expression, argument);
- PRINT(")");
- }
PRINT(")");
}
@@ -864,8 +888,7 @@ printer_visit_type_node(struct Visit* visit, struct Type_Node* node)
{
TREE_PRINTER_PREAMBLE
PRINT("(type ");
- if (node->variadic)
- PRINT("variadic ");
+ if (node->variadic) PRINT("variadic ");
walk_type_node(visit, node);
PRINT(")");
}
@@ -1077,6 +1100,24 @@ printer_visit_pragma_node(struct Visit* visit, struct Pragma_Node* node)
}
}
+void
+printer_visit_argument_group_node(struct Visit* visit, struct Argument_Group_Node* node)
+{
+ TREE_PRINTER_PREAMBLE
+
+ uint i = 0;
+ FOR_EACH (struct Expression*, argument, node->arguments) {
+ struct String name = string_array_at(&node->argument_names, i++);
+ if (name.data && name.data[0] != '\0') {
+ PRINT(" (named arg '%s' ", name.data);
+ } else {
+ PRINT(" (arg ");
+ }
+ VISIT(visit_expression, argument);
+ PRINT(")");
+ }
+}
+
struct Visit_Table printer_visit_functions = {
.visit_tree = printer_visit_tree,
@@ -1098,7 +1139,8 @@ struct Visit_Table printer_visit_functions = {
.visit_expression_unary_operation = printer_visit_expression_unary_operation,
.visit_expression_binary_operation = printer_visit_expression_binary_operation,
.visit_expression_group = printer_visit_expression_group,
- .visit_expression_call_or_construct = printer_visit_expression_call_or_construct,
+ .visit_expression_call = printer_visit_expression_call,
+ .visit_expression_construct = printer_visit_expression_construct,
.visit_expression_subscript = printer_visit_expression_subscript,
.visit_expression_member = printer_visit_expression_member,
.visit_expression_increment_decrement = printer_visit_expression_increment_decrement,
@@ -1121,6 +1163,7 @@ struct Visit_Table printer_visit_functions = {
.visit_block_node = printer_visit_block_node,
.visit_bare_declaration_node = printer_visit_bare_declaration_node,
.visit_function_header_node = printer_visit_function_header,
+ .visit_argument_group_node = printer_visit_argument_group_node,
.visit_pragma_node = printer_visit_pragma_node,
};