ox

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

parser_utils.c (11246B)



#include "../parser.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

/* basic range to str */
const char*
range_str(const char* src, size_t start, size_t end, char* stack_alloc_chptr)
{
	const size_t len = end - start;
	if (!src || !stack_alloc_chptr) return NULL;
	if (!strchr(src, '\0')) return NULL; // src has no '\0'
	if (len <= 0) return NULL;
	memcpy(stack_alloc_chptr, src + start, len);
	stack_alloc_chptr[len] = '\0';
	return stack_alloc_chptr;
}

const char*
span_str(const char* src, Span s, char* stack_alloc_chptr)
{
	return range_str(src, s.start, s.end, stack_alloc_chptr);
}

bool
span_ident_same(Span a, Span b, const char* src)
{
	const char* a_name = span_str(src, a, (char[IDENTSZ]) { 0 });
	const char* b_name = span_str(src, b, (char[IDENTSZ]) { 0 });
	return strcmp(a_name, b_name) == 0;
}

// int span_to_str(const char* src, size_t start, size_t end, char* out_buf) {
//     if (!src || !out_buf) return -1; /* Null pointer passed */
//     if (start >= end) return -2;     /* Empty or inverted span */
//     const size_t len = end - start;
//     if (len >= IDENTSZ) return -4; /* Identifier too long */
//     const char* src_end = strchr(src, '\0');
//     if (!src_end) return -5; /* src not NUL‑terminated */
//     const size_t src_len = (size_t)(src_end - src);

//     if (end > src_len) return -6; /* Span overruns source */

//     if (memchr(src + start, '\0', len))
//         return -7; /* span crosses a NUL byte */

//     memcpy(out_buf, src + start, len);
//     out_buf[len] = '\0';

//     return 0;
// }

// char* span_to_str_alloc(const char* src, size_t start, size_t end) {
//     if (!src || start >= end) return NULL;
//     const char* src_end = strchr(src, '\0');
//     if (!src_end) return NULL;
//     size_t src_len = (size_t)(src_end - src);
//     if (end > src_len) return NULL;
//     size_t n = end - start;
//     if (memchr(src + start, '\0', n)) return NULL;
//     char* s = calloc(1, n + 1);
//     if (!s) return NULL;
//     memcpy(s, src + start, n);
//     s[n] = '\0';
//     return s;
// }

static void
print_node(const char* source, Node* node, int level)
{
	assert(node != NULL);
	assert(level < 192);

	const char* name;
	switch (node->type) {
	case NODE_FUNCTION_DECL:
		name = range_str(
			source, node->data.function_decl.name.start, node->data.function_decl.name.end, (char[IDENTSZ]) { 0 });
		printf("%*s FUNC DECL: name='%s'\n", level, "", name);
		if (node->data.function_decl.return_type) {
			printf("%*s ↳ return type:\n", level * 2, "");
			print_node(source, node->data.function_decl.return_type, level + 1);
		}
		if (node->data.function_decl.params) {
			printf("%*s ↳ params:\n", level * 2, "");
			for (size_t i = 0; i < node->data.function_decl.p_len; i++) {
				Node* param = node->data.function_decl.params[i];
				print_node(source, param, level + 1);
			}
		} else {
			printf("%*s ↳ params: N/A\n", level * 2, "");
		}
		if (node->data.function_decl.body) {
			printf("%*s ↳ body:\n", level * 2, "");
			print_node(source, node->data.function_decl.body, level + 1);
		}
		break;
	case NODE_PARAM:
		name = range_str(source, node->data.param.name.start, node->data.param.name.end, (char[IDENTSZ]) { 0 });
		printf("%*s ↳ param: name='%s'\n", level * 2, "", name);
		if (node->data.param.type) { print_node(source, node->data.param.type, level + 1); }
		break;
	case NODE_VAR_DECL:
		name = range_str(source, node->data.var_decl.name.start, node->data.var_decl.name.end, (char[IDENTSZ]) { 0 });
		printf("%*s VAR DECL: name='%s'\n", level, "", name);
		if (node->data.var_decl.type) {
			printf("%*s ↳ type:\n", level * 2, "");
			print_node(source, node->data.var_decl.type, level + 1);
		}
		if (node->data.var_decl.init) {
			printf("%*s ↳ init:\n", level * 2, "");
			print_node(source, node->data.var_decl.init, level + 1);
		}
		break;
	case NODE_PROGRAM:
		printf("%*s PROGRAM:\n", level, "");
		if (node->data.program.decl) {
			for (size_t i = 0; i < node->data.program.len; i++) {
				print_node(source, node->data.program.decl[i], level + 1);
			}
		}
		break;
	case NODE_BLOCK:
		printf("%*s BLOCK:\n", level, "");
		if (node->data.block.stmts) {
			for (size_t i = 0; i < node->data.block.len; i++) {
				print_node(source, node->data.block.stmts[i], level + 1);
			}
		}
		break;
	case NODE_CALL_EXPR:
		printf("%*s ↳ FUNC CALL:\n", level, "");
		if (node->data.call_expr.callee) {
			printf("%*s ↳ callee:\n", level * 2, "");
			print_node(source, node->data.call_expr.callee, level + 1);
		}
		if (node->data.call_expr.args) {
			printf("%*s ↳ args:\n", level * 2, "");
			for (size_t i = 0; i < node->data.call_expr.len; i++) {
				Node* arg = node->data.call_expr.args[i];
				print_node(source, arg, level + 1);
			}
		}
		break;
	case NODE_RETURN:
		printf("%*s RETURN statement:\n", level, "");
		if (node->data.ret.expr) { print_node(source, node->data.ret.expr, level + 1); }
		break;
	case NODE_CONTINUE:
		printf("%*s CONTINUE statement\n", level, "");
		if (node->data.cont.expr) { print_node(source, node->data.cont.expr, level + 1); }
		break;
	case NODE_INT_LITERAL:
		printf("%*s ↳ LITERAL INT NUMBER value=%f\n", level * 2, "", node->data.number.value);
		break;
	case NODE_FLOAT_LITERAL:
		printf("%*s ↳ LITERAL FLOAT NUMBER value=%f\n", level * 2, "", node->data.number.value);
		break;
	case NODE_BOOL_LITERAL:
		if (node->data.boolean.value)
			printf("%*s   LITERAL BOOL TRUE\n", level * 2, "");
		else
			printf("%*s   LITERAL BOOL FALSE\n", level * 2, "");
		break;
	case NODE_STRING_LITERAL: {
		const char* lit = span_str(source, node->data.string.value, (char[IDENTSZ]) { 0 });
		printf("%*s ↳ LITERAL STRING value=\"%s\"\n", level * 2, "", lit);
		break;
	}
	case NODE_TYPE:
		name = range_str(source, node->data.ident.name.start, node->data.ident.name.end, (char[IDENTSZ]) { 0 });
		printf("%*s ↳ TYPE name='%s'\n", level * 2, "", name);
		break;
	case NODE_IDENT:
		name = range_str(source, node->data.ident.name.start, node->data.ident.name.end, (char[IDENTSZ]) { 0 });
		printf("%*s ↳ IDENT name='%s'\n", level * 2, "", name);
		break;
	// case NODE_VOID:
	//     printf("%*s  <VOID>\n", level * 2, "");
	//     break;
	// case NODE_FLOAT:
	//     printf("%*s  <FLOAT>\n", level * 2, "");
	//     break;
	// case NODE_INT:
	//     printf("%*s  <INT>\n", level * 2, "");
	//     break;
	// case NODE_STRING:
	//     printf("%*s  <STRING>\n", level * 2, "");
	//     break;
	case NODE_UNKNOWN:
		break;
	case NODE_VAR_ASSIGN: {
		const Span name_s = node->data.var_assign.lhs->data.ident.name;
		name = range_str(source, name_s.start, name_s.end, (char[IDENTSZ]) { 0 });
		printf("%*s VAR ASSIGN: name='%s'\n", level, "", name);
		break;
	}
	case NODE_BREAK:
		printf("%*s BREAK statement\n", level, "");
		break;
	case NODE_BINARY_EXPR:
		printf("%*s BINARY EXPR op='%c'\n", level, "", node->data.binary_expr.op);
		if (node->data.binary_expr.lhs) {
			printf("%*s ↳ lhs:\n", level * 2, "");
			print_node(source, node->data.binary_expr.lhs, level + 1);
		}
		if (node->data.binary_expr.rhs) {
			printf("%*s ↳ rhs:\n", level * 2, "");
			print_node(source, node->data.binary_expr.rhs, level + 1);
		}
		break;
	case NODE_UNARY_EXPR:
		printf("%*s UNARY EXPR: op='%d' is_postfix='%s'\n",
			level,
			"",
			node->data.unary_expr.op,
			node->data.unary_expr.is_postfix ? "true" : "false");
		if (node->data.unary_expr.operand) {
			printf("%*s ↳ operand:\n", level * 2, "");
			print_node(source, node->data.unary_expr.operand, level + 1);
		}
		break;
	case NODE_EXPR_STATEMENT:
		printf("%*s EXPR STMT:\n", level, "");
		if (node->data.expr_statement.expr) { print_node(source, node->data.expr_statement.expr, level + 1); }
		break;
	case NODE_SUBSCRIPT_EXPR:
		printf("%*s SUBSCRIPT expr:\n", level, "");
		if (node->data.subscript_expr.array) {
			printf("%*s ↳ array:\n", level * 2, "");
			print_node(source, node->data.subscript_expr.array, level + 1);
		}
		if (node->data.subscript_expr.index) {
			printf("%*s ↳ index:\n", level * 2, "");
			print_node(source, node->data.subscript_expr.index, level + 1);
		}
		break;
	case NODE_IF:
		printf("%*s IF Statement:\n", level, "");
		if (node->data.if_statement.cond) {
			printf("%*s ↳ cond:\n", level * 2, "");
			print_node(source, node->data.if_statement.cond, level + 1);
		}
		if (node->data.if_statement.then_body) {
			printf("%*s ↳ then body:\n", level * 2, "");
			print_node(source, node->data.if_statement.then_body, level + 1);
		}
		if (node->data.if_statement.else_body) {
			printf("%*s ↳ else body:\n", level * 2, "");
			print_node(source, node->data.if_statement.else_body, level + 1);
		}
		break;
	case NODE_WHILE:
		printf("%*s WHILE Statement:\n", level, "");
		if (node->data.while_statement.cond) {
			printf("%*s ↳ cond:\n", level * 2, "");
			print_node(source, node->data.while_statement.cond, level + 1);
		}
		if (node->data.while_statement.body) {
			printf("%*s ↳ body:\n", level * 2, "");
			print_node(source, node->data.while_statement.body, level + 1);
		}
		break;
	case NODE_FOR:
		printf("%*s FOR Statement:\n", level, "");
		if (node->data.for_statement.init) {
			printf("%*s ↳ init:\n", level * 2, "");
			print_node(source, node->data.for_statement.init, level + 1);
		}
		if (node->data.for_statement.cond) {
			printf("%*s ↳ cond:\n", level * 2, "");
			print_node(source, node->data.for_statement.cond, level + 1);
		}
		if (node->data.for_statement.increment) {
			printf("%*s ↳ increment:\n", level * 2, "");
			print_node(source, node->data.for_statement.increment, level + 1);
		}
		if (node->data.for_statement.body) {
			printf("%*s ↳ body:\n", level * 2, "");
			print_node(source, node->data.for_statement.body, level + 1);
		}
		break;
	case NODE_EMPTY_STATEMENT:
		printf("%*s EMPTY Statement\n", level, "");
		break;
	}

	while (node->next) {
		print_node(source, node->next, level);
		node = node->next;
	}
}

void
ast_print(Ast* ast)
{
	print_node(ast->src, ast->node, 0);
}

void
print_node_type_str(NodeType t)
{
	printf("print_node_type_str: %s\n", node_type_str(t));
}

const char*
node_type_str(NodeType t)
{
	static const char* type_strings[] = { [NODE_PROGRAM] = "NODE_PROGRAM",
		[NODE_FUNCTION_DECL] = "NODE_FUNCTION_DECL",
		[NODE_PARAM] = "NODE_PARAM",
		[NODE_VAR_DECL] = "NODE_VAR_DECL",
		[NODE_BLOCK] = "NODE_BLOCK",
		[NODE_CALL_EXPR] = "NODE_CALL_EXPR",
		[NODE_RETURN] = "NODE_RETURN",
		[NODE_CONTINUE] = "NODE_CONTINUE",
		[NODE_INT_LITERAL] = "NODE_INT_LITERAL",
		[NODE_FLOAT_LITERAL] = "NODE_FLOAT_LITERAL",
		[NODE_STRING_LITERAL] = "NODE_STRING_LITERAL",
		[NODE_TYPE] = "NODE_TYPE",
		[NODE_IDENT] = "NODE_IDENT",
		[NODE_UNKNOWN] = "NODE_UNKNOWN",
		[NODE_VAR_ASSIGN] = "NODE_VAR_ASSIGN",
		[NODE_BREAK] = "NODE_BREAK",
		[NODE_BINARY_EXPR] = "NODE_BINARY_EXPR",
		[NODE_UNARY_EXPR] = "NODE_UNARY_EXPR",
		[NODE_EXPR_STATEMENT] = "NODE_EXPR_STATEMENT",
		[NODE_SUBSCRIPT_EXPR] = "NODE_SUBSCRIPT_EXPR",
		[NODE_IF] = "NODE_IF",
		[NODE_WHILE] = "NODE_WHILE",
		[NODE_FOR] = "NODE_FOR",
		[NODE_EMPTY_STATEMENT] = "NODE_EMPTY_STATEMENT" };
	if (t >= NODE_PROGRAM && t <= NODE_EMPTY_STATEMENT) {
		return type_strings[t];
	} else {
		return "UNKNOWN_NODE_TYPE";
	}
}