aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-12-30 15:45:10 +0000
committerGinger Bill <bill@gingerbill.org>2016-12-30 15:45:10 +0000
commit23d32f34e526cfb657a72e5b2dab86d1df765f0f (patch)
tree7998bcf40ca9f581be6296bf4f68c102a5d234c8 /src/parser.c
parentd714bece47ea058e482389452cd428dad9c28fd0 (diff)
Block Expressions and `give`
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c71
1 files changed, 68 insertions, 3 deletions
diff --git a/src/parser.c b/src/parser.c
index b620e911b..09a7d1ae1 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -144,6 +144,15 @@ AST_NODE_KIND(_ExprBegin, "", i32) \
bool triple_indexed; \
}) \
AST_NODE_KIND(FieldValue, "field value", struct { Token eq; AstNode *field, *value; }) \
+ AST_NODE_KIND(BlockExpr, "block expr", struct { \
+ AstNodeArray stmts; \
+ Token open, close; \
+ AstNode *give_node; \
+ }) \
+ AST_NODE_KIND(GiveExpr, "give expression", struct { \
+ Token token; \
+ AstNodeArray results; \
+ }) \
AST_NODE_KIND(_ExprEnd, "", i32) \
AST_NODE_KIND(_StmtBegin, "", i32) \
AST_NODE_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
@@ -432,6 +441,10 @@ Token ast_node_token(AstNode *node) {
return node->DerefExpr.op;
case AstNode_DemaybeExpr:
return node->DemaybeExpr.op;
+ case AstNode_BlockExpr:
+ return node->BlockExpr.open;
+ case AstNode_GiveExpr:
+ return node->GiveExpr.token;
case AstNode_BadStmt:
return node->BadStmt.begin;
case AstNode_EmptyStmt:
@@ -729,6 +742,24 @@ AstNode *make_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token
return result;
}
+
+AstNode *make_block_expr(AstFile *f, AstNodeArray stmts, Token open, Token close) {
+ AstNode *result = make_node(f, AstNode_BlockExpr);
+ result->BlockExpr.stmts = stmts;
+ result->BlockExpr.open = open;
+ result->BlockExpr.close = close;
+ return result;
+}
+
+AstNode *make_give_expr(AstFile *f, Token token, AstNodeArray results) {
+ AstNode *result = make_node(f, AstNode_GiveExpr);
+ result->GiveExpr.token = token;
+ result->GiveExpr.results = results;
+ return result;
+}
+
+
+
AstNode *make_bad_stmt(AstFile *f, Token begin, Token end) {
AstNode *result = make_node(f, AstNode_BadStmt);
result->BadStmt.begin = begin;
@@ -1508,6 +1539,9 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
}
}
+AstNodeArray parse_lhs_expr_list(AstFile *f);
+AstNodeArray parse_rhs_expr_list(AstFile *f);
+
AstNode *parse_operand(AstFile *f, bool lhs) {
AstNode *operand = NULL; // Operand
switch (f->curr_token.kind) {
@@ -1623,6 +1657,17 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return type;
}
+ case Token_OpenBrace: {
+ AstNodeArray stmts = {0};
+ Token open, close;
+ open = expect_token(f, Token_OpenBrace);
+ f->expr_level++;
+ stmts = parse_stmt_list(f);
+ f->expr_level--;
+ close = expect_token(f, Token_CloseBrace);
+ return make_block_expr(f, stmts, open, close);
+ }
+
default: {
AstNode *type = parse_identifier_or_type(f);
if (type != NULL) {
@@ -2619,12 +2664,15 @@ AstNode *parse_return_stmt(AstFile *f) {
syntax_error(f->curr_token, "You cannot use a return statement in the file scope");
return make_bad_stmt(f, f->curr_token, f->curr_token);
}
+ if (f->expr_level > 0) {
+ syntax_error(f->curr_token, "You cannot use a return statement within an expression");
+ return make_bad_stmt(f, f->curr_token, f->curr_token);
+ }
Token token = expect_token(f, Token_return);
AstNodeArray results = make_ast_node_array(f);
- if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace &&
- f->curr_token.pos.line == token.pos.line) {
+ if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) {
results = parse_rhs_expr_list(f);
}
@@ -2632,6 +2680,23 @@ AstNode *parse_return_stmt(AstFile *f) {
return make_return_stmt(f, token, results);
}
+
+AstNode *parse_give_stmt(AstFile *f) {
+ if (f->curr_proc == NULL) {
+ syntax_error(f->curr_token, "You cannot use a give statement in the file scope");
+ return make_bad_stmt(f, f->curr_token, f->curr_token);
+ }
+ if (f->expr_level == 0) {
+ syntax_error(f->curr_token, "A give statement must be used within an expression");
+ return make_bad_stmt(f, f->curr_token, f->curr_token);
+ }
+
+ Token token = expect_token(f, Token_give);
+ AstNodeArray results = parse_rhs_expr_list(f);
+ expect_semicolon(f, results.e[0]);
+ return make_expr_stmt(f, make_give_expr(f, token, results));
+}
+
AstNode *parse_for_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
@@ -2861,7 +2926,6 @@ AstNode *parse_stmt(AstFile *f) {
expect_semicolon(f, s);
return s;
- // TODO(bill): other keywords
case Token_if: return parse_if_stmt(f);
case Token_when: return parse_when_stmt(f);
case Token_for: return parse_for_stmt(f);
@@ -2869,6 +2933,7 @@ AstNode *parse_stmt(AstFile *f) {
case Token_defer: return parse_defer_stmt(f);
case Token_asm: return parse_asm_stmt(f);
case Token_return: return parse_return_stmt(f);
+ case Token_give: return parse_give_stmt(f);
case Token_break:
case Token_continue: