From 7ad32a2a907150e3ce71e89f126ca2a530550158 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 22 Dec 2021 18:07:53 +0100 Subject: Add builtin object type --- src/ir.h | 53 ++++++++++++++++++++++++++++++--------------------- src/parser.c | 62 ++++++++++++++++++++++++++++++++++++++++++++---------------- src/parser.h | 31 ++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 38 deletions(-) diff --git a/src/ir.h b/src/ir.h index b42e02f..a42cd48 100644 --- a/src/ir.h +++ b/src/ir.h @@ -115,34 +115,43 @@ proc_alloc(ProgramIr *program, StringView name) { void compile_object(ProgramIr *program, Procedure *proc, Object *obj); void -compile_arithmetic_list(ProgramIr *program, Procedure *proc, Op op, Object *obj) { - size_t op_line = obj->head->line; - size_t op_col = obj->head->col; - obj = obj->tail; - - compile_object(program, proc, obj->head); - obj = obj->tail; - while (obj != NULL) { - compile_object(program, proc, obj->head); - obj = obj->tail; - Instruction inst = (Instruction){op, NULL, op_line, op_col}; +compile_arithmetic(ProgramIr *program, Procedure *proc, Op op, + size_t line, size_t col, Object *args) { + compile_object(program, proc, args->head); + args = args->tail; + while (args != NULL) { + compile_object(program, proc, args->head); + args = args->tail; + Instruction inst = (Instruction){op, NULL, line, col}; array_push(proc->instructions, inst); } } void compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { - // TODO: Handle this on the parser? - if (sv_equal(&obj->head->text, &STRING("+"))) { - compile_arithmetic_list(program, proc, OP_ADD, obj); - } else if (sv_equal(&obj->head->text, &STRING("-"))) { - compile_arithmetic_list(program, proc, OP_SUB, obj); - } else if (sv_equal(&obj->head->text, &STRING("*"))) { - compile_arithmetic_list(program, proc, OP_MUL, obj); - } else if (sv_equal(&obj->head->text, &STRING("/"))) { - compile_arithmetic_list(program, proc, OP_DIV, obj); - } else if (sv_equal(&obj->head->text, &STRING("%"))) { - compile_arithmetic_list(program, proc, OP_MOD, obj); + size_t line = obj->line; + size_t col = obj->col; + if (obj->head->type == OBJ_TYPE_BUILTIN) { + switch (obj->head->builtin) { + case BUILTIN_ADD: { + compile_arithmetic(program, proc, OP_ADD, line, col, obj->tail); + } break; + case BUILTIN_SUB: { + compile_arithmetic(program, proc, OP_SUB, line, col, obj->tail); + } break; + case BUILTIN_MUL: { + compile_arithmetic(program, proc, OP_MUL, line, col, obj->tail); + } break; + case BUILTIN_DIV: { + compile_arithmetic(program, proc, OP_DIV, line, col, obj->tail); + } break; + case BUILTIN_MOD: { + compile_arithmetic(program, proc, OP_MOD, line, col, obj->tail); + } break; + default: { + assert(false && "builtin not implemented"); + } break; + } } else { assert(false && "compile_proc_call: not implemented"); } diff --git a/src/parser.c b/src/parser.c index e72675f..298220a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -5,7 +5,7 @@ static Object **objects = NULL; static Root *roots = NULL; static Environment **environments = NULL; -static char *builtins [] = { +static char *builtin_names[] = { "+", "-", "*", "/", "%", "=", "<", ">", "<=", ">=", "not", "and", "or", @@ -14,6 +14,30 @@ static char *builtins [] = { "cons", "car", "cdr", }; +static Object builtins[] = { + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_ADD } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_SUB } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_MUL } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_DIV } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_MOD } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_EQ } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_LT } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_GT } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_LE } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_GE } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_NOT } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_AND } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_OR } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_NIL } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_ZERO } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_FIXNUM } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_BOOL } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_PRINT } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_CONS } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_CAR } , + { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_IS_CDR } , +}; + Token peek_token(const Parser *parser) { if (parser->current >= array_size(parser->tokens)) { @@ -79,6 +103,16 @@ parse_string(Token tok) { Object * parse_symbol(Token tok) { + // Check if symbol is a builtin procedure. + size_t n_builtins = sizeof(builtin_names) / sizeof(char*); + for (size_t i = 0; i < n_builtins; ++i) { + char *str = builtin_names[i]; + size_t str_n = strlen(str); + if (sv_equal(&tok.value, &(StringView){str, str_n})) { + return &builtins[i]; + } + } + Object *ret = object_alloc(tok, OBJ_TYPE_SYMBOL); ret->text = tok.value; return ret; @@ -352,7 +386,9 @@ parse_list(Parser *parser, Errors *errors) { } if (first) { - if (!IS_SYMBOL(current->head) && !IS_LAMBDA(current->head)) { + if (!IS_SYMBOL(current->head) && + !IS_LAMBDA(current->head) && + !IS_BUILTIN(current->head)) { error_push(errors, (Error){ .type = ERR_TYPE_PARSER, .value = ERR_NOT_CALLABLE, @@ -613,20 +649,8 @@ parse(Token *tokens, Errors *errors) { array_push(roots, root); } - // Prepare global environment of builtin functions. - Environment *global_env = env_alloc(NULL); - Environment *env = env_alloc(global_env); - size_t n_builtins = sizeof(builtins) / sizeof(char*); - for (size_t i = 0; i < n_builtins; i++) { - // Prepare builtin symbol. - char *str = builtins[i]; - size_t str_n = strlen(str); - Object *symbol = object_alloc((Token){0}, OBJ_TYPE_SYMBOL); - symbol->text = (StringView){str, str_n}; - - // Insert in global table. - insert_local(global_env, symbol, symbol); - } + // Prepare global environment. + Environment *env = env_alloc(NULL); // Perform semantic analysis: // 1. Populate symbol tables and ensure symbols are in scope when used. @@ -807,6 +831,9 @@ object_display(Object *obj) { object_display(obj->var_expr); printf(" }"); } break; + case OBJ_TYPE_BUILTIN: { + printf("%s", builtin_names[obj->builtin]); + } break; } return; } @@ -828,6 +855,9 @@ object_equal(Object *a, Object *b) { case OBJ_TYPE_STRING: { return sv_equal(&a->text, &b->text); } break; + case OBJ_TYPE_BUILTIN: { + return a->builtin = b->builtin; + } break; default: break; } return false; diff --git a/src/parser.h b/src/parser.h index 60a307c..41f1fc1 100644 --- a/src/parser.h +++ b/src/parser.h @@ -23,8 +23,33 @@ typedef enum ObjectType { OBJ_TYPE_IF, OBJ_TYPE_DEF, OBJ_TYPE_SET, + OBJ_TYPE_BUILTIN, } ObjectType; +typedef enum Builtin { + BUILTIN_ADD, + BUILTIN_SUB, + BUILTIN_MUL, + BUILTIN_DIV, + BUILTIN_MOD, + BUILTIN_EQ, + BUILTIN_LT, + BUILTIN_GT, + BUILTIN_LE, + BUILTIN_GE, + BUILTIN_NOT, + BUILTIN_AND, + BUILTIN_OR, + BUILTIN_IS_NIL, + BUILTIN_IS_ZERO, + BUILTIN_IS_FIXNUM, + BUILTIN_IS_BOOL, + BUILTIN_IS_PRINT, + BUILTIN_IS_CONS, + BUILTIN_IS_CAR, + BUILTIN_IS_CDR, +} Builtin; + typedef struct Object { ObjectType type; union { @@ -62,6 +87,11 @@ typedef struct Object { struct Object *var_name; struct Object *var_expr; }; + + // OBJ_TYPE_BUILTIN + struct { + Builtin builtin; + }; }; bool visited; @@ -125,6 +155,7 @@ void free_objects(void); #define IS_SYMBOL(VAL) ((VAL)->type == OBJ_TYPE_SYMBOL) #define IS_PAIR(VAL) ((VAL)->type == OBJ_TYPE_PAIR) #define IS_LAMBDA(VAL) ((VAL)->type == OBJ_TYPE_LAMBDA) +#define IS_BUILTIN(VAL) ((VAL)->type == OBJ_TYPE_BUILTIN) // Debug. #define OBJ_PRINT(OBJ) object_display(OBJ); printf("\n"); -- cgit v1.2.1