ox

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

expr.c (6249B)


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