Skip to content
Snippets Groups Projects
ast_visit.c 9.6 KiB
Newer Older
Clemens Paumgarten's avatar
Clemens Paumgarten committed
#include "mcc/ast_visit.h"

#include <assert.h>
#include <stdlib.h>

#define visit(node, callback, visitor) \
	do { \
		if (callback) { \
			(callback)(node, (visitor)->userdata); \
		} \
	} while (0)

#define visit_if(cond, node, callback, visitor) \
	do { \
		if (cond) { \
			visit(node, callback, visitor); \
		} \
	} while (0)

#define visit_if_pre_order(node, callback, visitor) \
	visit_if((visitor)->order == MCC_AST_VISIT_PRE_ORDER, node, callback, visitor)

#define visit_if_post_order(node, callback, visitor) \
	visit_if((visitor)->order == MCC_AST_VISIT_POST_ORDER, node, callback, visitor)

void mcc_ast_visit_expression(struct mcc_ast_expression *expression, struct mcc_ast_visitor *visitor)
{
	assert(expression);
	assert(visitor);

	visit_if_pre_order(expression, visitor->expression, visitor);

	switch (expression->type) {
		case MCC_AST_EXPRESSION_TYPE_LITERAL:
			visit_if_pre_order(expression, visitor->expression_literal, visitor);
			mcc_ast_visit_literal(expression->literal, visitor);
			visit_if_post_order(expression, visitor->expression_literal, visitor);
			break;

		case MCC_AST_EXPRESSION_TYPE_BINARY_OP:
			visit_if_pre_order(expression, visitor->expression_binary_op, visitor);
			mcc_ast_visit_expression(expression->lhs, visitor);
			mcc_ast_visit_expression(expression->rhs, visitor);
			visit_if_post_order(expression, visitor->expression_binary_op, visitor);
			break;

		case MCC_AST_EXPRESSION_TYPE_UNARY_OP:
			visit_if_pre_order(expression, visitor->expression_unary_op,visitor);
			mcc_ast_visit_expression(expression->unary_expression, visitor);
			visit_if_post_order(expression, visitor->expression_unary_op, visitor);
			break;

		case MCC_AST_EXPRESSION_TYPE_PARENTH:
			visit_if_pre_order(expression, visitor->expression_parenth, visitor);
			mcc_ast_visit_expression(expression->expression, visitor);
			visit_if_post_order(expression, visitor->expression_parenth, visitor);
			break;
		case MCC_AST_EXPRESSION_TYPE_IDENTIFIER:
			visit_if_pre_order(expression, visitor->expression_identifier, visitor);
			mcc_ast_visit_identifier(expression->identifier, visitor);
			visit_if_post_order(expression, visitor->expression_identifier, visitor);
			break;
		case MCC_AST_EXPRESSION_TYPE_CALL_EXPRESSION:
			visit_if_pre_order(expression, visitor->expression_call_expression, visitor);
			mcc_ast_visit_identifier(expression->function_name,visitor);
			if (expression->argument != NULL) {
				mcc_ast_visit_argument(expression->argument, visitor);
			}
			visit_if_post_order(expression, visitor->expression_parenth, visitor);
			break;
		case MCC_AST_EXPRESSION_TYPE_BRACKET:
			visit_if_pre_order(expression,visitor->expression_bracket,visitor);
			mcc_ast_visit_identifier(expression->bracket_identifier,visitor);
			mcc_ast_visit_expression(expression->bracket_expression,visitor);
			visit_if_post_order(expression,visitor->expression_bracket,visitor);
Clemens Paumgarten's avatar
Clemens Paumgarten committed
	}


	visit_if_post_order(expression, visitor->expression, visitor);
}

void mcc_ast_visit_literal(struct mcc_ast_literal *literal,struct mcc_ast_visitor *visitor)
{
	assert(literal);
	assert(visitor);

	switch (literal->type) {
		case MCC_AST_DATA_TYPE_BOOL:
			visit(literal, visitor->literal_bool, visitor);
			break;

		case MCC_AST_DATA_TYPE_INT:
			visit(literal, visitor->literal_int, visitor);
			break;

		case MCC_AST_DATA_TYPE_FLOAT:
			visit(literal, visitor->literal_float, visitor);
			break;

		case MCC_AST_DATA_TYPE_STRING:
			visit(literal, visitor->literal_string, visitor);
			break;
		default:
			break;
Clemens Paumgarten's avatar
Clemens Paumgarten committed
	}
}

void mcc_ast_visit_declaration(struct mcc_ast_declaration *declaration,
							   struct mcc_ast_visitor *visitor)
Clemens Paumgarten's avatar
Clemens Paumgarten committed
{
	assert(declaration);
	assert(visitor);

	visit_if_pre_order(declaration, visitor->declaration, visitor);
	if (declaration->arr_literal) {
		mcc_ast_visit_literal(declaration->arr_literal, visitor);
	}
	mcc_ast_visit_identifier(declaration->ident, visitor);
	visit_if_post_order(declaration, visitor->declaration, visitor);
}

void mcc_ast_visit_statement_list(struct mcc_ast_statement_list *statement_list,
								  struct mcc_ast_visitor *visitor)
	assert(statement_list);
	assert(visitor);

	struct mcc_ast_statement_list *next = statement_list;
	while (next != NULL) {
		visit_if_pre_order(next, visitor->statement_list, visitor);
		mcc_ast_visit_statement(next->statement, visitor);
		visit_if_post_order(statement_list, visitor->statement_list, visitor);
		next = next->next;
	}
Clemens Paumgarten's avatar
Clemens Paumgarten committed
}

void mcc_ast_visit_statement(struct mcc_ast_statement *statement,
							 struct mcc_ast_visitor *visitor)
	assert(statement);
	assert(visitor);
	visit_if_pre_order(statement, visitor->statement, visitor);
	switch (statement->type) {
Clemens Paumgarten's avatar
Clemens Paumgarten committed
		case MCC_AST_STATEMENT_TYPE_IF:
			visit_if_pre_order(statement, visitor->statement_if, visitor);
			mcc_ast_visit_expression(statement->if_condition, visitor);
			mcc_ast_visit_statement(statement->if_stmt, visitor);
			if (statement->else_stmt != NULL) {
				mcc_ast_visit_statement(statement->else_stmt, visitor);
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			}
			visit_if_post_order(statement, visitor->statement_if, visitor);
			break;


		case MCC_AST_STATEMENT_TYPE_WHILE:
			visit_if_pre_order(statement, visitor->statement_while, visitor);
			mcc_ast_visit_expression(statement->while_condition, visitor);
			mcc_ast_visit_statement(statement->while_stmt, visitor);
			visit_if_post_order(statement, visitor->statement_while, visitor);
			break;

		case MCC_AST_STATEMENT_TYPE_DECL:
			visit_if_pre_order(statement, visitor->statement_declaration,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			mcc_ast_visit_declaration(statement->declaration, visitor);
			visit_if_post_order(statement, visitor->statement_declaration,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			break;

		case MCC_AST_STATEMENT_TYPE_ASSGN:
			visit_if_pre_order(statement, visitor->statement_assignment,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			mcc_ast_visit_identifier(statement->assignment->identifier, visitor);
			if (statement->assignment) {
				mcc_ast_visit_expression(statement->assignment->array_ass.index, visitor);
			}
			mcc_ast_visit_expression(statement->assignment->normal_ass.rhs, visitor);
			visit_if_post_order(statement, visitor->statement_assignment,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			break;

		case MCC_AST_STATEMENT_TYPE_EXPRESSION:
			visit_if_pre_order(statement, visitor->statement_expression,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			mcc_ast_visit_expression(statement->expression, visitor);
			visit_if_post_order(statement, visitor->statement_expression,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			break;


		case MCC_AST_STATEMENT_TYPE_COMPOUND:
			visit_if_pre_order(statement, visitor->statement_compound, visitor);
			if (statement->statement_list != NULL) {
				mcc_ast_visit_statement_list(statement->statement_list, visitor);
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			}
			visit_if_post_order(statement, visitor->statement_compound,
Clemens Paumgarten's avatar
Clemens Paumgarten committed
			break;

		case MCC_AST_STATEMENT_TYPE_RETURN:
			visit_if_pre_order(statement, visitor->statement_return, visitor);
			if (statement->expression != NULL) {
				mcc_ast_visit_expression(statement->expression, visitor);
			}
			visit_if_post_order(statement, visitor->statement_return, visitor);
			break;

		case MCC_AST_STATEMENT_TYPE_ASSGN_ARR:
			break;
	}

	visit_if_post_order(statement, visitor->statement, visitor);

Clemens Paumgarten's avatar
Clemens Paumgarten committed
}

void mcc_ast_visit_assignment(struct mcc_ast_assignment *assignment,
							  struct mcc_ast_visitor *visitor)
Clemens Paumgarten's avatar
Clemens Paumgarten committed
{
	assert(assignment);
	assert(visitor);
	visit_if_pre_order(assignment, visitor->assignment, visitor);
	switch (assignment->type) {
		case MCC_AST_ASSIGNMENT_TYPE_NORMAL:
			mcc_ast_visit_identifier(assignment->identifier, visitor);
			mcc_ast_visit_expression(assignment->normal_ass.rhs, visitor);
			break;
		case MCC_AST_ASSIGNMENT_TYPE_ARRAY:
			mcc_ast_visit_identifier(assignment->identifier, visitor);
			mcc_ast_visit_expression(assignment->array_ass.index, visitor);
			mcc_ast_visit_expression(assignment->array_ass.rhs, visitor);
			break;
Clemens Paumgarten's avatar
Clemens Paumgarten committed
	}
	visit_if_post_order(assignment, visitor->assignment, visitor);
}

void mcc_ast_visit_identifier(struct mcc_ast_identifier *identifier, struct mcc_ast_visitor *visitor)
{
	assert(identifier);
	assert(visitor);

	visit(identifier, visitor->identifier, visitor);
}

void mcc_ast_visit_parameter(struct mcc_ast_parameter *parameter,
							 struct mcc_ast_visitor *visitor)
Clemens Paumgarten's avatar
Clemens Paumgarten committed
{
	assert(visitor);

	if (parameter) {
		visit_if_pre_order(parameter, visitor->parameter, visitor);
		for (int i = 0; i < parameter-> parameters -> size; i++) {
			mcc_ast_visit_declaration(parameter->parameters -> arr[i], visitor);
Clemens Paumgarten's avatar
Clemens Paumgarten committed
		}
		visit_if_post_order(parameter, visitor->parameter, visitor);
	}
}

void mcc_ast_visit_argument(struct mcc_ast_argument *argument,
							struct mcc_ast_visitor *visitor)
Clemens Paumgarten's avatar
Clemens Paumgarten committed
{
	assert(visitor);

	if (argument) {
		visit_if_pre_order(argument, visitor->argument, visitor);
		for (int i = 0; i < argument-> expressions -> size; i++) {
			mcc_ast_visit_expression(argument->expressions -> arr[i], visitor);
Clemens Paumgarten's avatar
Clemens Paumgarten committed
		}
		visit_if_post_order(argument, visitor->argument, visitor);
	}
}

void mcc_ast_visit_function(struct mcc_ast_function *function,
							struct mcc_ast_visitor *visitor)
Clemens Paumgarten's avatar
Clemens Paumgarten committed
{
	assert(function);
	assert(visitor);
	visit_if_pre_order(function, visitor->function, visitor);
	mcc_ast_visit_identifier(function->identifier, visitor);

	if (function -> parameter != NULL) {
		mcc_ast_visit_parameter(function->parameter, visitor);
	}
	if (function -> statement != NULL) {
		mcc_ast_visit_statement(function->statement, visitor);
	}
Clemens Paumgarten's avatar
Clemens Paumgarten committed

	visit_if_post_order(function, visitor->function, visitor);
}

void mcc_ast_visit_program(struct mcc_ast_program *program, struct mcc_ast_visitor *visitor)
{
	assert(program);
	assert(visitor);

	visit_if_pre_order(program, visitor->program, visitor);
	for (int i = 0; i < program-> function_def -> size; i++) {
		mcc_ast_visit_function(program->function_def -> arr [i], visitor);
Clemens Paumgarten's avatar
Clemens Paumgarten committed
	}
	visit_if_post_order(program, visitor->program, visitor);
}