You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							101 lines
						
					
					
						
							2.2 KiB
						
					
					
				
			
		
		
	
	
							101 lines
						
					
					
						
							2.2 KiB
						
					
					
				/* | 
						|
 * Copyright (C) 2023 Riyyi | 
						|
 * | 
						|
 * SPDX-License-Identifier: MIT | 
						|
 */ | 
						|
 | 
						|
#include <span> // std::span | 
						|
 | 
						|
#include "ast.h" | 
						|
#include "environment.h" | 
						|
#include "eval.h" | 
						|
#include "ruc/meta/assert.h" | 
						|
#include "types.h" | 
						|
 | 
						|
namespace blaze { | 
						|
 | 
						|
Eval::Eval(ASTNodePtr ast, Environment* env) | 
						|
	: m_ast(ast) | 
						|
	, m_env(env) | 
						|
{ | 
						|
} | 
						|
 | 
						|
void Eval::eval() | 
						|
{ | 
						|
	m_ast = evalImpl(m_ast, m_env); | 
						|
} | 
						|
 | 
						|
ASTNodePtr Eval::evalImpl(ASTNodePtr ast, Environment* env) | 
						|
{ | 
						|
	if (!is<List>(ast.get())) { | 
						|
		return evalAst(ast, env); | 
						|
	} | 
						|
	if (static_cast<List*>(ast.get())->empty()) { | 
						|
		return ast; | 
						|
	} | 
						|
 | 
						|
	return apply(static_pointer_cast<List>(evalAst(ast, env))); | 
						|
} | 
						|
 | 
						|
ASTNodePtr Eval::evalAst(ASTNodePtr ast, Environment* env) | 
						|
{ | 
						|
	ASTNode* ast_raw_ptr = ast.get(); | 
						|
	if (is<Symbol>(ast_raw_ptr)) { | 
						|
		auto result = env->lookup(static_pointer_cast<Symbol>(ast)->symbol()); | 
						|
		if (!result) { | 
						|
			// TODO: Maybe add backlink to parent nodes? | 
						|
			if (is<List>(m_ast)) { | 
						|
				Error::the().addError(format("symbol's function definition is void: {}", ast_raw_ptr)); | 
						|
			} | 
						|
			else { | 
						|
				Error::the().addError(format("symbol's value as variable is void: {}", ast_raw_ptr)); | 
						|
			} | 
						|
		} | 
						|
		return result; | 
						|
	} | 
						|
	else if (is<List>(ast_raw_ptr)) { | 
						|
		auto result = makePtr<List>(); | 
						|
		auto nodes = static_pointer_cast<List>(ast)->nodes(); | 
						|
		for (auto node : nodes) { | 
						|
			result->addNode(evalImpl(node, env)); | 
						|
		} | 
						|
		return result; | 
						|
	} | 
						|
	else if (is<Vector>(ast_raw_ptr)) { | 
						|
		auto result = makePtr<Vector>(); | 
						|
		auto nodes = static_pointer_cast<Vector>(ast)->nodes(); | 
						|
		for (auto node : nodes) { | 
						|
			result->addNode(evalImpl(node, env)); | 
						|
		} | 
						|
		return result; | 
						|
	} | 
						|
	else if (is<HashMap>(ast_raw_ptr)) { | 
						|
		auto result = makePtr<HashMap>(); | 
						|
		auto elements = static_pointer_cast<HashMap>(ast)->elements(); | 
						|
		for (auto& element : elements) { | 
						|
			result->addElement(element.first, evalImpl(element.second, env)); | 
						|
		} | 
						|
		return result; | 
						|
	} | 
						|
 | 
						|
	return ast; | 
						|
} | 
						|
 | 
						|
ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list) | 
						|
{ | 
						|
	auto nodes = evaluated_list->nodes(); | 
						|
 | 
						|
	if (!is<Function>(nodes[0].get())) { | 
						|
		Error::the().addError(format("invalid function: {}", nodes[0])); | 
						|
		return nullptr; | 
						|
	} | 
						|
 | 
						|
	// car | 
						|
	auto lambda = static_pointer_cast<Function>(nodes[0])->lambda(); | 
						|
	// cdr | 
						|
	std::span<ASTNodePtr> span { nodes.data() + 1, nodes.size() - 1 }; | 
						|
 | 
						|
	return lambda(span); | 
						|
} | 
						|
 | 
						|
} // namespace blaze
 | 
						|
 |