mirror of
https://github.com/kanaka/mal.git
synced 2024-09-20 01:57:09 +03:00
284 lines
6.0 KiB
C
284 lines
6.0 KiB
C
|
#include <stdarg.h>
|
||
|
#include <stdio.h>
|
||
|
#include <gc.h>
|
||
|
#include "types.h"
|
||
|
|
||
|
#define ERROR_BUFFER_SIZE 128
|
||
|
|
||
|
MalType THE_TRUE = {MALTYPE_TRUE, 0, 0, {0}};
|
||
|
MalType THE_FALSE = {MALTYPE_FALSE, 0, 0, {0}};
|
||
|
MalType THE_NIL = {MALTYPE_NIL, 0, 0, {0}};
|
||
|
|
||
|
|
||
|
inline int is_sequential(MalType* val) {
|
||
|
return (val->type == MALTYPE_LIST || val->type == MALTYPE_VECTOR);
|
||
|
}
|
||
|
|
||
|
inline int is_self_evaluating(MalType* val) {
|
||
|
return (val->type == MALTYPE_KEYWORD || val->type == MALTYPE_INTEGER ||
|
||
|
val->type == MALTYPE_FLOAT || val->type == MALTYPE_STRING ||
|
||
|
val->type == MALTYPE_TRUE || val->type == MALTYPE_FALSE ||
|
||
|
val->type == MALTYPE_NIL);
|
||
|
}
|
||
|
|
||
|
inline int is_list(MalType* val) {
|
||
|
return (val->type == MALTYPE_LIST);
|
||
|
}
|
||
|
|
||
|
inline int is_vector(MalType* val) {
|
||
|
return (val->type == MALTYPE_VECTOR);
|
||
|
}
|
||
|
|
||
|
inline int is_hashmap(MalType* val) {
|
||
|
return (val->type == MALTYPE_HASHMAP);
|
||
|
}
|
||
|
|
||
|
inline int is_nil(MalType* val) {
|
||
|
return (val->type == MALTYPE_NIL);
|
||
|
}
|
||
|
|
||
|
inline int is_string(MalType* val) {
|
||
|
return (val->type == MALTYPE_STRING);
|
||
|
}
|
||
|
|
||
|
inline int is_integer(MalType* val) {
|
||
|
return (val->type == MALTYPE_INTEGER);
|
||
|
}
|
||
|
|
||
|
inline int is_float(MalType* val) {
|
||
|
return (val->type == MALTYPE_FLOAT);
|
||
|
}
|
||
|
|
||
|
inline int is_number(MalType* val) {
|
||
|
return (val->type == MALTYPE_INTEGER || val->type == MALTYPE_FLOAT);
|
||
|
}
|
||
|
|
||
|
inline int is_true(MalType* val) {
|
||
|
return (val->type == MALTYPE_TRUE);
|
||
|
}
|
||
|
|
||
|
inline int is_false(MalType* val) {
|
||
|
return (val->type == MALTYPE_FALSE);
|
||
|
}
|
||
|
|
||
|
inline int is_symbol(MalType* val) {
|
||
|
return (val->type == MALTYPE_SYMBOL);
|
||
|
}
|
||
|
|
||
|
inline int is_keyword(MalType* val) {
|
||
|
return (val->type == MALTYPE_KEYWORD);
|
||
|
}
|
||
|
|
||
|
inline int is_atom(MalType* val) {
|
||
|
return (val->type == MALTYPE_ATOM);
|
||
|
}
|
||
|
|
||
|
inline int is_error(MalType* val) {
|
||
|
return (val->type == MALTYPE_ERROR);
|
||
|
}
|
||
|
|
||
|
inline int is_callable(MalType* val) {
|
||
|
return (val->type == MALTYPE_FUNCTION || val->type == MALTYPE_CLOSURE);
|
||
|
}
|
||
|
|
||
|
inline int is_function(MalType* val) {
|
||
|
return (val->type == MALTYPE_FUNCTION);
|
||
|
}
|
||
|
|
||
|
inline int is_closure(MalType* val) {
|
||
|
return (val->type == MALTYPE_CLOSURE);
|
||
|
}
|
||
|
|
||
|
inline int is_macro(MalType* val) {
|
||
|
return (val->is_macro);
|
||
|
}
|
||
|
|
||
|
|
||
|
MalType* make_symbol(char* value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_SYMBOL;
|
||
|
mal_val->value.mal_symbol = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_integer(long value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_INTEGER;
|
||
|
mal_val->value.mal_integer = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_float(double value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_FLOAT;
|
||
|
mal_val->value.mal_float = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_keyword(char* value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_KEYWORD;
|
||
|
mal_val->value.mal_keyword = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_string(char* value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_STRING;
|
||
|
mal_val->value.mal_string = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_list(list value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_LIST;
|
||
|
mal_val->value.mal_list = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_vector(list value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_VECTOR;
|
||
|
mal_val->value.mal_list = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_hashmap(list value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_HASHMAP;
|
||
|
mal_val->value.mal_list = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_atom(MalType* value) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_ATOM;
|
||
|
mal_val->value.mal_atom = value;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_function(MalType*(*fn)(list args)) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_FUNCTION;
|
||
|
mal_val->value.mal_function = fn;
|
||
|
mal_val->is_macro = 0;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_closure(Env* env, MalType* parameters, MalType* definition, MalType* more_symbol) {
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_CLOSURE;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
/* Allocate memory for embedded struct */
|
||
|
MalClosure* mc = GC_MALLOC(sizeof(*mc));
|
||
|
mc->env = env;
|
||
|
mc->parameters = parameters;
|
||
|
mc->definition = definition;
|
||
|
mc->more_symbol = more_symbol;
|
||
|
|
||
|
mal_val->is_macro = 0;
|
||
|
mal_val->value.mal_closure = mc;
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
inline MalType* make_true() {
|
||
|
return &THE_TRUE;
|
||
|
}
|
||
|
|
||
|
inline MalType* make_false() {
|
||
|
return &THE_FALSE;
|
||
|
}
|
||
|
|
||
|
inline MalType* make_nil() {
|
||
|
return &THE_NIL;
|
||
|
}
|
||
|
|
||
|
MalType* make_error(char* msg) {
|
||
|
|
||
|
MalType* mal_string = GC_MALLOC(sizeof(*mal_string));
|
||
|
mal_string->type = MALTYPE_STRING;
|
||
|
mal_string->value.mal_string = msg;
|
||
|
|
||
|
MalType* mal_val = GC_MALLOC(sizeof(*mal_val));
|
||
|
mal_val->type = MALTYPE_ERROR;
|
||
|
mal_val->value.mal_error = mal_string;
|
||
|
mal_val->metadata = NULL;
|
||
|
|
||
|
return mal_val;
|
||
|
}
|
||
|
|
||
|
MalType* make_error_fmt(char* fmt, ...) {
|
||
|
|
||
|
va_list argptr;
|
||
|
va_start(argptr, fmt);
|
||
|
|
||
|
char* buffer = GC_MALLOC(sizeof(*buffer) * ERROR_BUFFER_SIZE);
|
||
|
|
||
|
long n = vsnprintf(buffer, ERROR_BUFFER_SIZE, fmt, argptr);
|
||
|
va_end(argptr);
|
||
|
|
||
|
if (n > ERROR_BUFFER_SIZE) {
|
||
|
va_start(argptr, fmt);
|
||
|
|
||
|
buffer = GC_REALLOC(buffer, sizeof(*buffer) * n);
|
||
|
vsnprintf(buffer, n, fmt, argptr);
|
||
|
|
||
|
va_end(argptr);
|
||
|
}
|
||
|
return make_error(buffer);
|
||
|
}
|
||
|
|
||
|
MalType* wrap_error(MalType* value) {
|
||
|
|
||
|
MalType* mal_error = GC_MALLOC(sizeof(*mal_error));
|
||
|
mal_error->type = MALTYPE_ERROR;
|
||
|
mal_error->metadata = NULL;
|
||
|
mal_error->value.mal_error = value;
|
||
|
|
||
|
return mal_error;
|
||
|
}
|
||
|
|
||
|
MalType* copy_type(MalType* value) {
|
||
|
|
||
|
MalType* new_val = GC_MALLOC(sizeof(*new_val));
|
||
|
|
||
|
new_val->type = value->type;
|
||
|
new_val->is_macro = value->is_macro;
|
||
|
new_val->value = value->value;
|
||
|
new_val->metadata = value->metadata;
|
||
|
|
||
|
return new_val;
|
||
|
}
|