1
0
Fork 0
lesson-lisp/builtins.c
2023-05-04 21:24:54 +04:00

349 lines
8.4 KiB
C

#include "builtins.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Builtin {
const char *name;
struct Object *(*func)(struct Object *args);
};
// Evaluation
static struct Object *func_eval(struct Object *args);
// Basic data structures
static struct Object *func_cons(struct Object *args);
static struct Object *func_quote(struct Object *args);
// Type predicates
static struct Object *func_booleanQN(struct Object *args);
static struct Object *func_charQN(struct Object *args);
static struct Object *func_nullQN(struct Object *args);
static struct Object *func_numberQN(struct Object *args);
static struct Object *func_pairQN(struct Object *args);
static struct Object *func_stringQN(struct Object *args);
static struct Object *func_symbolQN(struct Object *args);
// Logical operators
static struct Object *func_and(struct Object *args);
static struct Object *func_or(struct Object *args);
// IO
static struct Object *func_display(struct Object *args);
static struct Object *func_displayln(struct Object *args);
static struct Object *func_newline(struct Object *args);
// Other
static struct Object *func_sum(struct Object *args);
static struct Builtin builtins[] = {
// Evaluation
{ "eval", func_eval },
// Basic data structures
{ "cons", func_cons },
{ "quote", func_quote },
// Type predicates
{ "boolean?", func_booleanQN },
{ "char?", func_charQN },
{ "null?", func_nullQN },
{ "number?", func_numberQN },
{ "pair?", func_pairQN },
{ "string?", func_stringQN },
{ "symbol?", func_symbolQN },
// Logical operators
{ "and", func_and },
{ "or", func_or },
// IO
{ "display", func_display },
{ "displayln", func_displayln },
{ "newline", func_newline },
// Other
{ "+", func_sum },
{ NULL, NULL },
};
static struct Object *builtins_call(const char *name, struct Object *args)
{
for (size_t index = 0; builtins[index].name; ++index) {
if (strcmp(builtins[index].name, name) == 0) {
return builtins[index].func(args);
}
}
abort();
}
struct Object *builtins_eval(struct Object *program)
{
// NULL is an empty list, can't eval
assert(program);
// Almost everything evaluates to itself
if (program->type != TYPE_PAIR && program->type != TYPE_SYMBOL) {
return program;
}
// Symbols are variable names, but we can't lookup
assert(program->type != TYPE_SYMBOL);
// The first item of pair should be an symbol - a function name
assert(program->pair.a && program->pair.a->type == TYPE_SYMBOL);
return builtins_call(program->pair.a->s, program->pair.b);
}
/**************
* Evaluation *
**************/
struct Object *func_eval(struct Object *const args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
return builtins_eval(args->pair.a);
}
/*************************
* Basic data structures *
*************************/
struct Object *func_cons(struct Object *const args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.a);
assert(args->pair.b);
assert(args->pair.b->type == TYPE_PAIR);
assert(args->pair.b->pair.a);
assert(args->pair.b->pair.b == NULL);
struct Object *const car = builtins_eval(args->pair.a);
struct Object *const cdr = builtins_eval(args->pair.b->pair.a);
return Object_new_pair(car, cdr);
}
struct Object *func_quote(struct Object *const args)
{
if (!args) return NULL;
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
return args->pair.a;
}
/*******************
* Type predicates *
*******************/
struct Object *func_booleanQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object && object->type == TYPE_BOOLEAN);
}
struct Object *func_charQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object && object->type == TYPE_CHAR);
}
struct Object *func_nullQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object == NULL);
}
struct Object *func_numberQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object && object->type == TYPE_NUMBER);
}
struct Object *func_pairQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object && object->type == TYPE_PAIR);
}
struct Object *func_stringQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object && object->type == TYPE_STRING);
}
struct Object *func_symbolQN(struct Object *args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
return Object_new_boolean(object && object->type == TYPE_SYMBOL);
}
/*********************
* Logical operators *
*********************/
struct Object *func_and(struct Object *args)
{
struct Object *result = Object_new_boolean(true);
while (args) {
assert(args->type == TYPE_PAIR);
result = builtins_eval(args->pair.a);
if (IS_FALSE(result)) break;
args = args->pair.b;
}
return result;
}
struct Object *func_or(struct Object *args)
{
struct Object *result = Object_new_boolean(false);
while (args) {
assert(args->type == TYPE_PAIR);
result = builtins_eval(args->pair.a);
if (!IS_FALSE(result)) break;
args = args->pair.b;
}
return result;
}
/******
* IO *
******/
static void display_pair(struct Object *pair);
struct Object *func_display(struct Object *const args)
{
assert(args);
assert(args->type == TYPE_PAIR);
assert(args->pair.b == NULL);
struct Object *const object = builtins_eval(args->pair.a);
if (!object) {
printf("()");
return NULL;
}
switch (object->type) {
case TYPE_PROCEDURE:
if (object->procedure.name) {
printf("#<procedure:%s>", object->procedure.name);
} else {
printf("#<procedure>");
}
break;
case TYPE_PAIR:
printf("(");
display_pair(object);
printf(")");
break;
case TYPE_BOOLEAN:
printf("%s", object->boolean ? "#t" : "#f");
break;
case TYPE_CHAR:
printf("#\\TODO"); // TODO
break;
case TYPE_SYMBOL:
case TYPE_STRING:
printf("%s", object->s);
break;
case TYPE_NUMBER:
printf("%li", object->i);
break;
}
return NULL;
}
struct Object *func_displayln(struct Object *const args)
{
func_display(args);
func_newline(NULL);
return NULL;
}
struct Object *func_newline(struct Object *const args)
{
assert(args == NULL);
printf("\n");
return NULL;
}
void display_pair(struct Object *const pair)
{
assert(pair);
assert(pair->type == TYPE_PAIR);
func_display(Object_new_pair(pair->pair.a, NULL));
if (!pair->pair.b) return;
printf(" ");
if (pair->pair.b->type == TYPE_PAIR) {
display_pair(pair->pair.b);
return;
}
printf(". ");
func_display(Object_new_pair(pair->pair.b, NULL));
}
/*********
* Other *
*********/
struct Object *func_sum(struct Object *const args)
{
struct Object *const object = Object_new_number(0);
if (!args) return object;
assert(args->type == TYPE_PAIR);
assert(args->pair.a);
assert(args->pair.a->type == TYPE_NUMBER);
object->i = args->pair.a->i;
if (!args->pair.b) return object;
struct Object *const b_sum = func_sum(args->pair.b);
object->i += b_sum->i;
return object;
}