<commit_before>#include "slist_native.h"
#include "slist_context.h"
#include "slist_eval.h"
#include "slist_log.h"
#include <algorithm>

namespace slist
{
	node_ptr ___define(context& ctx, const node_ptr& root)
	{
		if (root->length() < 3)
		{
			log_errorln("Invalid arguments for 'define'\n", root);
			return nullptr;
		}

		node_ptr first = root->get(1);
		node_ptr body = root->get(2);

		if (first->type == node_type::pair)
		{
			// Lambda syntactic sugar
			// (define (f x) (...)) -> (define f (lambda (x) (...))

			node_ptr name = first->car;
			node_ptr args = first->cdr;

			node_ptr lambda_node(new node);
			lambda_node->type = node_type::pair;

			node_ptr name_node(new node);
			name_node->value = "lambda";
			name_node->type = node_type::name;			
			lambda_node->append(name_node);
			lambda_node->append(args);
			lambda_node->append(body);

			log_traceln("LAMBDA FROM SCRATCH:\n", lambda_node);

            ctx.global_env->register_variable(name->value, ___lambda(ctx, lambda_node));
		}
		else if (first->type == node_type::name)
		{
            node_ptr res = eval(ctx, body);
			ctx.global_env->register_variable(first->value, res);            
		}

		return nullptr;
	}

	node_ptr ___lambda(context& ctx, const node_ptr& root)
	{
		if (root->proc != nullptr)
		{
			log_warningln("Evaluating a lambda that already has a procedure. Was it evaluated twice?");
			return root;
		}

		if (root->length() != 3)
		{
			log_errorln("Invalid lambda format\n", root);
			return nullptr;
		}

		funcdef_ptr func(new funcdef);
		func->env->parent = ctx.active_env;
		func->is_native = false;
		func->name = root->get(0)->value; // "lambda"
		func->variables = root->get(1);
		func->body = root->get(2);

		node_ptr res(new node);
		res->proc = func;

		log_traceln("Lambda proc:\n", nullptr, func);

		return res;
	}

	node_ptr ___eval(context& ctx, const node_ptr& root)
	{
		if (root->length() != 2)
		{
			log_errorln("'eval' expects one argument: ", root);
			return nullptr;
		}

		return eval(ctx, root->get(1));
	}

	node_ptr ___apply(context& ctx, const node_ptr& root)
	{
		if (root->length() < 3)
		{
			log_errorln("Not enough arguments for 'apply'\n", root);
			return nullptr;
		}

        node_ptr func_node = eval(ctx, root->get(1));
		if (func_node->proc == nullptr)
		{
			log_errorln("First argument for 'apply' is not a procedure:\n", func_node);
			return nullptr;
		}

        node_ptr args = eval(ctx, root->get(2));
        if (args->type != node_type::pair)
        {
        	log_errorln("Arguments is not a list:\n", args);
        	return nullptr;
        }<commit_msg>Fixed eval of quoted expression.<commit_after>#include "slist_native.h"
#include "slist_context.h"
#include "slist_eval.h"
#include "slist_log.h"
#include <algorithm>

namespace slist
{
	node_ptr ___define(context& ctx, const node_ptr& root)
	{
		if (root->length() < 3)
		{
			log_errorln("Invalid arguments for 'define'\n", root);
			return nullptr;
		}

		node_ptr first = root->get(1);
		node_ptr body = root->get(2);

		if (first->type == node_type::pair)
		{
			// Lambda syntactic sugar
			// (define (f x) (...)) -> (define f (lambda (x) (...))

			node_ptr name = first->car;
			node_ptr args = first->cdr;

			node_ptr lambda_node(new node);
			lambda_node->type = node_type::pair;

			node_ptr name_node(new node);
			name_node->value = "lambda";
			name_node->type = node_type::name;			
			lambda_node->append(name_node);
			lambda_node->append(args);
			lambda_node->append(body);

			log_traceln("LAMBDA FROM SCRATCH:\n", lambda_node);

            ctx.global_env->register_variable(name->value, ___lambda(ctx, lambda_node));
		}
		else if (first->type == node_type::name)
		{
            node_ptr res = eval(ctx, body);
			ctx.global_env->register_variable(first->value, res);            
		}

		return nullptr;
	}

	node_ptr ___lambda(context& ctx, const node_ptr& root)
	{
		if (root->proc != nullptr)
		{
			log_warningln("Evaluating a lambda that already has a procedure. Was it evaluated twice?");
			return root;
		}

		if (root->length() != 3)
		{
			log_errorln("Invalid lambda format\n", root);
			return nullptr;
		}

		funcdef_ptr func(new funcdef);
		func->env->parent = ctx.active_env;
		func->is_native = false;
		func->name = root->get(0)->value; // "lambda"
		func->variables = root->get(1);
		func->body = root->get(2);

		node_ptr res(new node);
		res->proc = func;

		log_traceln("Lambda proc:\n", nullptr, func);

		return res;
	}

	node_ptr ___eval(context& ctx, const node_ptr& root)
	{
		if (root->length() != 2)
		{
			log_errorln("'eval' expects one argument: ", root);
			return nullptr;
		}

		return eval(ctx, eval(ctx, root->get(1)));
	}

	node_ptr ___apply(context& ctx, const node_ptr& root)
	{
		if (root->length() < 3)
		{
			log_errorln("Not enough arguments for 'apply'\n", root);
			return nullptr;
		}

        node_ptr func_node = eval(ctx, root->get(1));
		if (func_node->proc == nullptr)
		{
			log_errorln("First argument for 'apply' is not a procedure:\n", func_node);
			return nullptr;
		}

        node_ptr args = eval(ctx, root->get(2));
        if (args->type != node_type::pair)
        {
        	log_errorln("Arguments is not a list:\n", args);
        	return nullptr;
        }
{'fraction_non_alphanumeric': 0.15519208824648156, 'fraction_numerical': 0.004564473183720046, 'mean_word_length': 3.2377115229653506, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6134888', 'n_tokens_mistral': 2083, 'n_tokens_neox': 1849, 'n_words': 431}