ox

The Ox programming language, compiler and tools (WIP)
Log | Files | Refs | README | LICENSE

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;
}