summaryrefslogtreecommitdiff
path: root/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c76
1 files changed, 62 insertions, 14 deletions
diff --git a/parse.c b/parse.c
index e0f6cdc..7749ddc 100644
--- a/parse.c
+++ b/parse.c
@@ -70,6 +70,7 @@ typedef enum {
EXPR_IDENT, /* variable or constant */
EXPR_BINARY_OP,
EXPR_UNARY_OP,
+ EXPR_IF,
EXPR_FN,
EXPR_CALL,
EXPR_BLOCK,
@@ -102,6 +103,12 @@ typedef struct {
Array args; /* of Expression */
} CallExpr;
+typedef struct {
+ struct Expression *cond; /* NULL = this is an else */
+ struct Expression *next_elif; /* next elif/else of this statement */
+ Block body;
+} IfExpr;
+
#define EXPR_FLAG_FOUND_TYPE 0x01
typedef struct Expression {
@@ -125,6 +132,7 @@ typedef struct Expression {
CallExpr call;
DirectExpr direct;
Identifier ident;
+ IfExpr if_;
struct FnExpr *fn;
Block block;
};
@@ -372,6 +380,7 @@ static int op_precedence(Keyword op) {
/* TODO: check that we check which thing ends it everywhere */
#define EXPR_CAN_END_WITH_COMMA 0x01 /* a comma could end the expression */
+#define EXPR_CAN_END_WITH_LBRACE 0x02
static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) {
Tokenizer *t = p->tokr;
@@ -406,12 +415,14 @@ static Token *expr_find_end(Parser *p, uint16_t flags, bool *is_vbs) {
return token;
break;
case KW_LBRACE:
+ if ((flags & EXPR_CAN_END_WITH_LBRACE) && square_level == 0 && paren_level == 0)
+ return token;
brace_level++;
could_be_vbs = true;
break;
case KW_RBRACE:
brace_level--;
- if (brace_level == 0 && could_be_vbs) {
+ if (brace_level == 0 && could_be_vbs && !token_is_kw(token + 1, KW_RPAREN)) {
if (is_vbs) *is_vbs = true;
return token + 1; /* token afer } is end */
}
@@ -714,21 +725,41 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
}
Token *start = t->token;
+
+ if (t->token->kind == TOKEN_KW) switch (t->token->kw) {
+ case KW_FN: {
+ /* this is a function */
+ e->kind = EXPR_FN;
+ e->fn = err_malloc(sizeof *e->fn);
+ if (!parse_fn_expr(p, e->fn))
+ return false;
- if (token_is_kw(t->token, KW_FN)) {
- /* this is a function */
- e->kind = EXPR_FN;
- e->fn = err_malloc(sizeof *e->fn);
- if (!parse_fn_expr(p, e->fn))
- return false;
-
- if (t->token != end) {
- tokr_err(t, "Direct function calling in an expression is not supported yet.\nYou can wrap the function in parentheses.");
- /* TODO */
- return false;
+ if (t->token != end) {
+ tokr_err(t, "Direct function calling in an expression is not supported yet.\nYou can wrap the function in parentheses.");
+ /* TODO */
+ return false;
+ }
+ return true;
+ }
+ case KW_IF: {
+ IfExpr *i = &e->if_;
+ e->kind = EXPR_IF;
+ t->token++;
+ Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE, NULL);
+ if (!token_is_kw(cond_end, KW_LBRACE)) {
+ t->token = cond_end;
+ tokr_err(t, "Expected { to open if body.");
+ return false;
+ }
+ i->cond = parser_new_expr(p);
+ if (!parse_expr(p, i->cond, cond_end)) return false;
+ if (!parse_block(p, &i->body)) return false;
+ i->next_elif = NULL;
+ /* TODO: elif/else */
+ return true;
+ }
+ default: break;
}
- return true;
- }
/* Find the lowest-precedence operator not in parentheses/braces/square brackets */
int paren_level = 0;
@@ -808,6 +839,12 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (entirely_within_parentheses) {
t->token++; /* move past opening ( */
+ if (token_is_kw(t->token, KW_RPAREN)) {
+ /* ()foo */
+ t->token--;
+ tokr_err(t, "Stray () (maybe try wrapping the stuff before this in parentheses)");
+ return false;
+ }
Token *new_end = end - 1; /* parse to ending ) */
if (!parse_expr(p, e, new_end))
return false;
@@ -1338,6 +1375,17 @@ static void fprint_expr(FILE *out, Expression *e) {
case EXPR_FN:
fprint_fn_expr(out, e->fn);
break;
+ case EXPR_IF:
+ if (e->if_.cond) {
+ fprintf(out, "(else)? if ");
+ fprint_expr(out, e->if_.cond);
+ } else {
+ fprintf(out, "else");
+ }
+ fprint_block(out, &e->if_.body);
+ if (e->if_.next_elif)
+ fprint_expr(out, e->if_.next_elif);
+ break;
case EXPR_CALL:
fprint_expr(out, e->call.fn);
fprint_args(out, &e->call.args);