ox

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

expr.c (6391B)


      1 #include "../parser.h"
      2 #include "../utils.h"
      3 
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <stdbool.h>
      7 #include <assert.h>
      8 
      9 Node*
     10 parse_func_call(Parser* par)
     11 {
     12 	Token tok = expect(par, TOKEN_IDENT);
     13 	Span callee = { .start = tok.start, .end = tok.end };
     14 	Node* ident = make_ident_node(callee);
     15 
     16 	const char* name = span_str(par->src, ident->data.ident.name, (char[IDENTSZ]) { 0 });
     17 	printf("parse_func_call: %s\n", name);
     18 
     19 	expect(par, TOKEN_LPAREN);
     20 
     21 	Node* call = (Node*)calloc(1, sizeof(Node));
     22 	if (call == NULL) panic("parse_func_call: alloc failed");
     23 
     24 	// start parse arguments
     25 	if (peek(par).type != TOKEN_RPAREN) {
     26 		call->data.call_expr.args = (Node**)calloc(4, sizeof(Node*));
     27 		if (call->data.call_expr.args == NULL) panic("parse_func_call: args: could not alloc");
     28 		call->data.call_expr.cap = 4;
     29 		call->data.call_expr.len = 0;
     30 
     31 		for (;;) {
     32 			Node* arg = parse_expression(par);
     33 
     34 			if (call->data.call_expr.len == call->data.call_expr.cap) {
     35 				call->data.call_expr.cap *= 2;
     36 				call->data.call_expr.args
     37 					= (Node**)realloc(call->data.call_expr.args, call->data.call_expr.cap * sizeof(Node*));
     38 			}
     39 			call->data.call_expr.args[call->data.call_expr.len++] = arg;
     40 
     41 			if (!match(par, TOKEN_COMMA)) break; // found `)` instead of `,`
     42 		}
     43 	}
     44 	// ends parse arguments
     45 
     46 	expect(par, TOKEN_RPAREN);
     47 
     48 	call->type = NODE_CALL_EXPR;
     49 	call->scope = NULL;
     50 	call->data.call_expr.callee = ident;
     51 	return call;
     52 }
     53 
     54 Node*
     55 parse_number(Parser* par)
     56 {
     57 	Token tok = consume(par);
     58 	assert(tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL);
     59 
     60 	size_t len = tok.end - tok.start;
     61 	char buf[len + 1]; // strtod needs a \0 terminated string
     62 	for (size_t i = 0; i < len; i++)
     63 		buf[i] = par->src[tok.start + i];
     64 	buf[len] = '\0';
     65 	double value = strtod(buf, NULL);
     66 
     67 	Node* num_node = (Node*)calloc(1, sizeof(Node));
     68 	if (num_node == NULL) panic("parse_number: alloc failed");
     69 	num_node->type = tok.type == TOKEN_INT_LITERAL ? NODE_INT_LITERAL : NODE_FLOAT_LITERAL;
     70 	num_node->scope = NULL;
     71 	num_node->data.number.value = value;
     72 	return num_node;
     73 }
     74 
     75 Node*
     76 parse_ident(Parser* par)
     77 {
     78 	Token tok = consume(par);
     79 	assert(tok.type == TOKEN_IDENT);
     80 	Node* ident_node = (Node*)calloc(1, sizeof(Node));
     81 	if (ident_node == NULL) panic("parse_ident: alloc failed");
     82 	ident_node->type = NODE_IDENT;
     83 	ident_node->scope = NULL;
     84 	ident_node->data.ident.name = (Span) { .start = tok.start, .end = tok.end };
     85 
     86 	// const char* name = span_str(
     87 	// 	par->src, (Span) { .start = tok.start, .end = tok.end }, (char[IDENTSZ]) { 0 });
     88 	// printf("parse_ident: %s\n", name);
     89 
     90 	return ident_node;
     91 }
     92 
     93 NodeVec
     94 parse_func_arguments(Parser* par)
     95 {
     96 	NodeVec v = { 0 };
     97 	if (peek(par).type == TOKEN_RPAREN) return v; // found `)` no arguments
     98 
     99 	v.cap = 4;
    100 	v.items = (Node**)calloc(v.cap, sizeof(Node*));
    101 	if (v.items == NULL) panic("parse_func_arguments: could not alloc");
    102 
    103 	for (;;) {
    104 		Node* arg = parse_expression(par);
    105 
    106 		if (v.len == v.cap) {
    107 			v.cap *= 2;
    108 			v.items = (Node**)realloc(v.items, v.cap * sizeof(Node*));
    109 		}
    110 
    111 		v.items[v.len++] = arg;
    112 
    113 		if (!match(par, TOKEN_COMMA)) break; // found `)` instead of `,`
    114 	}
    115 	return v;
    116 }
    117 
    118 Node*
    119 parse_postfix(Parser* par)
    120 {
    121 	Node* node = parse_primary(par);
    122 
    123 	for (;;) {
    124 		if (match(par, TOKEN_PLUSPLUS)) {
    125 			node = make_postfix_node(OPER_POSTINC, node);
    126 		} else if (match(par, TOKEN_MINUSMINUS)) {
    127 			node = make_postfix_node(OPER_POSTDEC, node);
    128 		} else if (match(par, TOKEN_LBRACKET)) {
    129 			Node* index = parse_expression(par); // parse inside brackets
    130 			expect(par, TOKEN_RBRACKET);
    131 			node = make_subscript_node(node, index);
    132 			// } else if (match(par, TOKEN_DOT)) { // TODO dot members and arrows
    133 			//     Token id = expect(par, TOKEN_IDENTIFIER);
    134 			//     expr = make_member_node(expr, id);
    135 			// } else if (match(par, TOKEN_ARROW)) {
    136 			//     Token id = expect(par, TOKEN_IDENTIFIER);
    137 			//     expr = make_ptrmember_node(expr, id);
    138 		} else if (match(par, TOKEN_LPAREN)) {
    139 			NodeVec args = parse_func_arguments(par); // parse func call args
    140 			expect(par, TOKEN_RPAREN);
    141 			node = make_call_node(node, args);
    142 		} else {
    143 			break;
    144 		}
    145 	}
    146 	return node;
    147 }
    148 
    149 #define STARTING_ROOT_NODES 32
    150 
    151 Node*
    152 make_program_node(Parser* par)
    153 {
    154 	Node* node = (Node*)calloc(1, sizeof(Node));
    155 	if (node == NULL) panic("make_program_node: alloc failed");
    156 	node->type = NODE_PROGRAM;
    157 	node->filename = par->filename;
    158 	node->scope = NULL;
    159 	node->next = NULL;
    160 	node->data.program.cap = STARTING_ROOT_NODES;
    161 	node->data.program.len = 0;
    162 	node->data.program.decl = (Node**)calloc(STARTING_ROOT_NODES, sizeof(Node));
    163 	if (node->data.program.decl == NULL) panic("make_program_node: decls: alloc failed");
    164 	return node;
    165 }
    166 
    167 Node*
    168 make_ident_node(Span name)
    169 {
    170 	Node* node = (Node*)calloc(1, sizeof(Node));
    171 	if (node == NULL) panic("make_ident_node: alloc failed");
    172 	node->type = NODE_IDENT;
    173 	node->scope = NULL;
    174 	node->next = NULL;
    175 	node->data.ident.name = name;
    176 	return node;
    177 }
    178 
    179 Node*
    180 parse_primary(Parser* par)
    181 {
    182 	Token tok = peek(par);
    183 	if (tok.type == TOKEN_STRING_LITERAL) { return make_string_node(par); }
    184 	if (tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL) { return make_number_node(par); }
    185 	if (tok.type == TOKEN_IDENT) { return parse_ident(par); }
    186 	if (tok.type == TOKEN_LPAREN) {
    187 		consume(par); // consume '('
    188 		Node* node = parse_expression(par);
    189 		expect(par, TOKEN_RPAREN);
    190 		return node;
    191 	}
    192 
    193 	const char* name = span_str(par->src, (Span) { .start = tok.start, .end = tok.end }, (char[IDENTSZ]) { 0 });
    194 	panic("Expected Primary Expr, but found '%s' (%s at %s:%zu:%zu",
    195 		name,
    196 		token_type_str(tok.type),
    197 		par->filename,
    198 		tok.line,
    199 		tok.col);
    200 
    201 	return NULL;
    202 }
    203 
    204 Node*
    205 parse_unary(Parser* par)
    206 {
    207 	Node* inner = NULL;
    208 	switch (peek(par).type) {
    209 	case TOKEN_MINUS:
    210 		consume(par);
    211 		inner = parse_unary(par);
    212 		return make_unary_node(OPER_MINUS, inner);
    213 	case TOKEN_MINUSMINUS:
    214 		consume(par);
    215 		inner = parse_unary(par);
    216 		return make_unary_node(OPER_PREDEC, inner);
    217 	case TOKEN_BANG:
    218 		consume(par);
    219 		inner = parse_unary(par);
    220 		return make_unary_node(OPER_BANG, inner);
    221 		// TODO add others '~a' '$a' '*a' '^a' '@a' '&a'
    222 	case TOKEN_PLUSPLUS:
    223 		consume(par);
    224 		inner = parse_unary(par);
    225 		return make_unary_node(OPER_PREINC, inner);
    226 	case TOKEN_PLUS:
    227 		consume(par);
    228 		return parse_unary(par);
    229 	default:
    230 		return parse_postfix(par);
    231 	}
    232 }
    233 
    234 // called by parse_multiplicative
    235 Node*
    236 parse_term(Parser* par)
    237 {
    238 	return parse_unary(par);
    239 }