stmt.c (4823B)
#include "../parser.h"
#include "../utils.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
Node*
parse_if(Parser* par)
{
expect(par, TOKEN_IF);
expect(par, TOKEN_LPAREN); // @later remove necessity for parens
Node* cond = parse_expression(par);
expect(par, TOKEN_RPAREN);
Node* then_body = parse_statement(par);
Node* else_body = NULL;
if (match(par, TOKEN_ELSE)) else_body = parse_statement(par);
Node* node = (Node*)calloc(1, sizeof(Node));
if (node == NULL) panic("parse_if: could not alloc");
node->type = NODE_IF;
node->scope = NULL;
node->data.if_statement.cond = cond;
node->data.if_statement.then_body = then_body;
node->data.if_statement.else_body = else_body;
return node;
}
Node*
parse_while(Parser* par)
{
expect(par, TOKEN_WHILE);
expect(par, TOKEN_LPAREN);
Node* cond = parse_expression(par);
expect(par, TOKEN_RPAREN);
Node* body = parse_statement(par);
Node* node = (Node*)calloc(1, sizeof(Node));
if (node == NULL) panic("parse_while: could not alloc");
node->type = NODE_WHILE;
node->scope = NULL;
node->data.while_statement.cond = cond;
node->data.while_statement.body = body;
return node;
}
Node*
parse_for(Parser* par)
{
Token for_token = expect(par, TOKEN_FOR);
expect(par, TOKEN_LPAREN);
// init can be empty, a decl, or a expr statement
Node* init = NULL; // int i = 0 ... conditional expression stment
if (!check(par, TOKEN_SEMICOLON)) {
Token tok2 = peek2(par);
if (tok2.type == TOKEN_IDENT) {
init = parse_declaration_statement(par);
} else {
// TODO check: init = parse_assignment_expr(par);
init = parse_expression_statement(par);
}
} else
expect(par, TOKEN_SEMICOLON);
Node* cond = NULL; // i < len ... optional expression
if (!check(par, TOKEN_SEMICOLON)) cond = parse_expression(par);
expect(par, TOKEN_SEMICOLON);
Node* inc = NULL; // i++ ... optional expression
if (!check(par, TOKEN_RPAREN)) { inc = parse_expression(par); }
expect(par, TOKEN_RPAREN);
Node* body = parse_statement(par);
Node* node = (Node*)calloc(1, sizeof(Node));
node->type = NODE_FOR;
node->scope = NULL;
node->line = for_token.line;
node->col = for_token.col;
node->filename = par->filename;
node->data.for_statement.init = init;
node->data.for_statement.cond = cond;
node->data.for_statement.increment = inc;
if (node == NULL) panic("parse_for: could not alloc");
node->data.for_statement.body = body;
return node;
}
Node*
parse_assignment(Parser* par)
{
Token ident = expect(par, TOKEN_IDENT);
Span name = { .start = ident.start, .end = ident.end };
expect(par, TOKEN_EQUAL);
Node* expr = parse_expression(par);
Node* assign = (Node*)calloc(1, sizeof(Node));
if (assign == NULL) panic("parse_assignment: could not alloc");
assign->type = NODE_VAR_ASSIGN;
assign->scope = NULL;
assign->data.var_assign.lhs = (Node*)calloc(1, sizeof(Node));
if (assign->data.var_assign.lhs == NULL) panic("parse_for: lhs: could not alloc");
/*
identifier
x = 5;
member field access
obj.field = 5;
obj->field = 5;
array or pointer indexing
arr[0] = 5;
*(p + 1) = 5;
dereference
*p = 5;
*/
assign->filename = par->filename;
assign->line = ident.line;
assign->col = ident.col;
assign->data.var_assign.lhs->type = NODE_IDENT; // TODO handle other cases, e.g. subscript assignment
assign->data.var_assign.lhs->scope = NULL;
assign->data.var_assign.lhs->data.ident.name = name;
assign->data.var_assign.rhs = expr;
expect(par, TOKEN_SEMICOLON);
return assign;
}
Node*
parse_break(Parser* par)
{
expect(par, TOKEN_BREAK);
expect(par, TOKEN_SEMICOLON);
Node* node = (Node*)calloc(1, sizeof(Node));
if (node == NULL) panic("parse_break: could not alloc");
node->type = NODE_BREAK;
node->scope = NULL;
return node;
}
Node*
parse_continue_statement(Parser* par)
{
expect(par, TOKEN_CONTINUE); // consume 'continue'
Node* node = (Node*)calloc(1, sizeof(Node));
if (node == NULL) panic("parse_continue_statemenet: could not alloc");
node->type = NODE_CONTINUE;
node->scope = NULL;
TokenType next_type = peek(par).type;
if (next_type != TOKEN_SEMICOLON)
node->data.cont.expr = parse_expression(par);
else
node->data.cont.expr = NULL;
expect(par, TOKEN_SEMICOLON);
return node;
}
Node*
parse_return_statement(Parser* par)
{
Token tok = expect(par, TOKEN_RETURN); // consume 'return'
Node* ret = (Node*)calloc(1, sizeof(Node));
if (ret == NULL) panic("parse_return_statemenet: could not alloc");
ret->type = NODE_RETURN;
ret->filename = par->filename;
ret->line = tok.line;
ret->col = tok.col;
ret->scope = NULL;
TokenType next_type = peek(par).type;
if (next_type != TOKEN_SEMICOLON)
ret->data.ret.expr = parse_expression(par);
else
ret->data.ret.expr = NULL;
expect(par, TOKEN_SEMICOLON);
return ret;
}