aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/parse.c36
-rw-r--r--boot/tree.c32
2 files changed, 52 insertions, 16 deletions
diff --git a/boot/parse.c b/boot/parse.c
index 3d2706f..ac324f9 100644
--- a/boot/parse.c
+++ b/boot/parse.c
@@ -705,7 +705,7 @@ parser_expression_member(struct Parser* p, struct Parser_Error* error)
{
struct Expression* left = CHECK(parser_expression_primary(p, error));
- // NOTE: see `parser_expression_postfix_call`.
+ // NOTE: see `parser_expression_postfix_call_or_construct`.
while (parser_probe(p, TOKEN_DOT)) {
parser_next(p);
struct Token name_token = CHECK(parser_need(p, TOKEN_NAME, error));
@@ -720,31 +720,53 @@ parser_expression_member(struct Parser* p, struct Parser_Error* error)
}
struct Expression*
-parser_expression_postfix_call(
+parser_expression_postfix_call_or_construct(
struct Parser* p, struct Expression* subject, struct Parser_Error* error)
{
// NOTE: because of the way the parser works, we have to parse all subsequent
- // call expressions in the same loop.
+ // call/construct expressions in the same loop.
// this is the case with an expression like `meow_function()(123)`,
// where the hypothetical `meow_function` returns a function pointer.
+
+ // calls and constructs look identical in the parser.
+ // * call: `meow_function(123, "hello")`
+ // * construct: `Meow(num = 123, str = "hello")`
while (parser_probe(p, TOKEN_ROUND_OPEN)) {
parser_next(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 Expression* argument = CHECK(parser_expression(p, error));
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);
}
struct Token token = CHECK(parser_need(p, TOKEN_ROUND_CLOSE, error));
struct Span span = span_merge(subject->span, token.span);
- union Expression_Value value = { .call = { subject, arguments_head } };
- subject = expression_new(EXPRESSION_CALL, value, span, token.location);
+ union Expression_Value value = {
+ .call_or_construct = { subject, arguments_head, argument_names }
+ };
+ subject = expression_new(EXPRESSION_CALL_OR_CONSTRUCT, value, span, token.location);
}
return subject;
@@ -754,7 +776,7 @@ struct Expression*
parser_expression_postfix_subscript(
struct Parser* p, struct Expression* subject, struct Parser_Error* error)
{
- // NOTE: see `parser_expression_postfix_call`.
+ // NOTE: see `parser_expression_postfix_call_or_construct`.
while (parser_probe(p, TOKEN_SQUARE_OPEN)) {
parser_next(p);
@@ -776,7 +798,7 @@ parser_expression_postfix(struct Parser* p, struct Parser_Error* error)
struct Token token = parser_peek(p);
switch (token.kind) {
case TOKEN_ROUND_OPEN:
- return parser_expression_postfix_call(p, expression, error);
+ return parser_expression_postfix_call_or_construct(p, expression, error);
case TOKEN_SQUARE_OPEN:
return parser_expression_postfix_subscript(p, expression, error);
default:;
diff --git a/boot/tree.c b/boot/tree.c
index e4d0272..2e046da 100644
--- a/boot/tree.c
+++ b/boot/tree.c
@@ -665,7 +665,7 @@ enum Expression_Kind
EXPRESSION_BINARY_OPERATION,
EXPRESSION_GROUP,
- EXPRESSION_CALL,
+ EXPRESSION_CALL_OR_CONSTRUCT,
EXPRESSION_SUBSCRIPT,
EXPRESSION_MEMBER,
EXPRESSION_INCREMENT_DECREMENT,
@@ -717,10 +717,14 @@ struct Expression_Group
struct Expression* inner_expression;
};
-struct Expression_Call
+struct Expression_Call_Or_Construct
{
struct Expression* subject;
- struct Expression* arguments; // linked list of expressions.
+ // 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 Expression_Subscript
@@ -764,7 +768,7 @@ union Expression_Value
struct Expression_Unary_Operator unary_operator;
struct Expression_Binary_Operator binary_operator;
struct Expression_Group group;
- struct Expression_Call call;
+ struct Expression_Call_Or_Construct call_or_construct;
struct Expression_Subscript subscript;
struct Expression_Member member;
struct Expression_Increment_Decrement increment_decrement;
@@ -867,16 +871,26 @@ expression_print(const struct Expression* expression)
expression_print(expression->value.group.inner_expression);
printf(")");
break;
- case EXPRESSION_CALL:
- printf("(call ");
- expression_print(expression->value.call.subject);
- FOR_EACH(struct Expression*, argument, expression->value.call.arguments)
+ case EXPRESSION_CALL_OR_CONSTRUCT: {
+ const struct Expression_Call_Or_Construct* coc =
+ &expression->value.call_or_construct;
+ printf("(call/construct ");
+ expression_print(coc->subject);
+ uint i = 0;
+ FOR_EACH(struct Expression*, argument, coc->arguments)
{
- printf(" ");
+ struct String name = string_array_at(&coc->argument_names, i++);
+ if (!string_is_empty(name)) {
+ printf(" (named arg '%s' ", name.data);
+ } else {
+ printf(" (arg ");
+ }
expression_print(argument);
+ printf(")");
}
printf(")");
break;
+ }
case EXPRESSION_SUBSCRIPT:
printf("(subscript ");
expression_print(expression->value.subscript.subject);