ox

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

expr.c (6872B)


      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 
     80 	bool comp_time = (tok.type == TOKEN_COMP_TIME);
     81 	bool variadic = (tok.type == TOKEN_VARIADIC);
     82 	if (comp_time || variadic) { tok = consume(par); }
     83 
     84 	assert(tok.type == TOKEN_IDENT);
     85 	Node* ident_node = (Node*)calloc(1, sizeof(Node));
     86 	if (ident_node == NULL) panic("parse_ident: alloc failed");
     87 	ident_node->type = NODE_IDENT;
     88 	ident_node->scope = NULL;
     89 	ident_node->data.ident_type.name = (Span) { .start = tok.start, .end = tok.end };
     90 	ident_node->data.ident_type.is_comp_time = comp_time;
     91 	ident_node->data.ident_type.is_variadic = variadic;
     92 
     93 	// const char* name = span_str(
     94 	// 	par->src, (Span) { .start = tok.start, .end = tok.end }, (char[IDENTSZ]) { 0 });
     95 	// printf("parse_ident: %s\n", name);
     96 
     97 	return ident_node;
     98 }
     99 
    100 NodeVec
    101 parse_func_arguments(Parser* par)
    102 {
    103 	NodeVec v = { 0 };
    104 	if (peek(par).type == TOKEN_RPAREN) return v; // found `)` no arguments
    105 
    106 	v.cap = 4;
    107 	v.items = (Node**)calloc(v.cap, sizeof(Node*));
    108 	if (v.items == NULL) panic("parse_func_arguments: could not alloc");
    109 
    110 	for (;;) {
    111 		Node* arg = parse_expression(par);
    112 
    113 		if (v.len == v.cap) {
    114 			v.cap *= 2;
    115 			v.items = (Node**)realloc(v.items, v.cap * sizeof(Node*));
    116 		}
    117 
    118 		v.items[v.len++] = arg;
    119 
    120 		if (!match(par, TOKEN_COMMA)) break; // found `)` instead of `,`
    121 	}
    122 	return v;
    123 }
    124 
    125 Node*
    126 parse_postfix(Parser* par)
    127 {
    128 	Node* node = parse_primary(par);
    129 
    130 	for (;;) {
    131 		if (match(par, TOKEN_PLUSPLUS)) {
    132 			node = make_postfix_node(OPER_POSTINC, node);
    133 		} else if (match(par, TOKEN_MINUSMINUS)) {
    134 			node = make_postfix_node(OPER_POSTDEC, node);
    135 		} else if (match(par, TOKEN_LBRACKET)) {
    136 			Node* index = parse_expression(par); // parse inside brackets
    137 			expect(par, TOKEN_RBRACKET);
    138 			node = make_subscript_node(node, index);
    139 			// } else if (match(par, TOKEN_DOT)) { // TODO dot members and arrows
    140 			//     Token id = expect(par, TOKEN_IDENTIFIER);
    141 			//     expr = make_member_node(expr, id);
    142 			// } else if (match(par, TOKEN_ARROW)) {
    143 			//     Token id = expect(par, TOKEN_IDENTIFIER);
    144 			//     expr = make_ptrmember_node(expr, id);
    145 		} else if (match(par, TOKEN_LPAREN)) {
    146 			NodeVec args = parse_func_arguments(par); // parse func call args
    147 			expect(par, TOKEN_RPAREN);
    148 			node = make_call_node(node, args);
    149 		} else {
    150 			break;
    151 		}
    152 	}
    153 	return node;
    154 }
    155 
    156 #define STARTING_ROOT_NODES 32
    157 
    158 Node*
    159 make_program_node(Parser* par)
    160 {
    161 	Node* node = (Node*)calloc(1, sizeof(Node));
    162 	if (node == NULL) panic("make_program_node: alloc failed");
    163 	node->type = NODE_PROGRAM;
    164 	node->filename = par->filename;
    165 	node->scope = NULL;
    166 	node->next = NULL;
    167 	node->data.program.cap = STARTING_ROOT_NODES;
    168 	node->data.program.len = 0;
    169 	node->data.program.decl = (Node**)calloc(STARTING_ROOT_NODES, sizeof(Node));
    170 	if (node->data.program.decl == NULL) panic("make_program_node: decls: alloc failed");
    171 	return node;
    172 }
    173 
    174 Node*
    175 make_ident_node(Span name)
    176 {
    177 	Node* node = (Node*)calloc(1, sizeof(Node));
    178 	if (node == NULL) panic("make_ident_node: alloc failed");
    179 	node->type = NODE_IDENT;
    180 	node->scope = NULL;
    181 	node->next = NULL;
    182 	node->data.ident.name = name;
    183 	return node;
    184 }
    185 
    186 Node*
    187 parse_primary(Parser* par)
    188 {
    189 	Token tok = peek(par);
    190 	if (tok.type == TOKEN_BOOL_TRUE_LITERAL || tok.type == TOKEN_BOOL_FALSE_LITERAL) {
    191 		return make_boolean_node(par, tok.type == TOKEN_BOOL_TRUE_LITERAL);
    192 	}
    193 	if (tok.type == TOKEN_STRING_LITERAL) { return make_string_node(par); }
    194 	if (tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL) { return make_number_node(par); }
    195 	if (tok.type == TOKEN_IDENT || tok.type == TOKEN_VARIADIC || tok.type == TOKEN_COMP_TIME) { return parse_ident(par); }
    196 	if (tok.type == TOKEN_LPAREN) {
    197 		consume(par); // consume '('
    198 		Node* node = parse_expression(par);
    199 		expect(par, TOKEN_RPAREN);
    200 		return node;
    201 	}
    202 
    203 	const char* name = span_str(par->src, (Span) { .start = tok.start, .end = tok.end }, (char[IDENTSZ]) { 0 });
    204 	panic("Expected Primary Expr, but found '%s' (%s at %s:%zu:%zu",
    205 		name,
    206 		token_type_str(tok.type),
    207 		par->filename,
    208 		tok.line,
    209 		tok.col);
    210 
    211 	return NULL;
    212 }
    213 
    214 Node*
    215 parse_unary(Parser* par)
    216 {
    217 	Node* inner = NULL;
    218 	switch (peek(par).type) {
    219 	case TOKEN_MINUS:
    220 		consume(par);
    221 		inner = parse_unary(par);
    222 		return make_unary_node(OPER_MINUS, inner);
    223 	case TOKEN_MINUSMINUS:
    224 		consume(par);
    225 		inner = parse_unary(par);
    226 		return make_unary_node(OPER_PREDEC, inner);
    227 	case TOKEN_BANG:
    228 		consume(par);
    229 		inner = parse_unary(par);
    230 		return make_unary_node(OPER_BANG, inner);
    231 		// TODO add others '~a' '$a' '*a' '^a' '@a' '&a'
    232 	case TOKEN_PLUSPLUS:
    233 		consume(par);
    234 		inner = parse_unary(par);
    235 		return make_unary_node(OPER_PREINC, inner);
    236 	case TOKEN_PLUS:
    237 		consume(par);
    238 		return parse_unary(par);
    239 	default:
    240 		return parse_postfix(par);
    241 	}
    242 }
    243 
    244 // called by parse_multiplicative
    245 Node*
    246 parse_term(Parser* par)
    247 {
    248 	return parse_unary(par);
    249 }