diff --git a/builtins.c b/builtins.c index f6dbc1b..9607610 100644 --- a/builtins.c +++ b/builtins.c @@ -1,6 +1,8 @@ #include "lisp.h" -Node *lisp_function_addition(Nodes *args) { +Node *lisp_function_addition(Nodes *args, Scopes *scopes) { + (void)(scopes); + if (args->count != 2) { printf("'+' expects two arguments!\n"); return NULL; @@ -20,3 +22,16 @@ Node *lisp_function_addition(Nodes *args) { node->as_number = a + b; return node; } + +Node *lisp_function_println(Nodes *args, Scopes *scopes) { + if (args->count != 1) { + printf("'+' expects one argument!\n"); + return NULL; + } + + Node *result = eval(&args->items[0], scopes); + node_print(*result); + printf("\n"); + + return result; +} diff --git a/lisp.c b/lisp.c index f184aad..11f6a0f 100644 --- a/lisp.c +++ b/lisp.c @@ -1,16 +1,13 @@ #include "lisp.h" -static LispFunction globalScope[] = { - (LispFunction){.name = (Nob_String_View){.items = "+", .count = 1}, - .apply = lisp_function_addition}}; +static Scope globalScope = {0}; -static Node *lisp_function_lookup(Nob_String_View name) { - for (size_t i = 0; i < NOB_ARRAY_LEN(globalScope); i++) { - if (nob_sv_eq(globalScope[i].name, name)) { - Node *node = malloc(sizeof(Node)); - node->kind = NODE_KIND_FUNCTION; - node->as_function = globalScope[i]; - return node; +static Node *scope_lookup(Scopes *scopes, Nob_String_View name) { + nob_da_foreach(Scope, scope, scopes) { + nob_da_foreach(ScopeObject, scopeObject, scope) { + if (nob_sv_eq(name, scopeObject->name)) { + return &scopeObject->node; + } } } @@ -18,6 +15,44 @@ static Node *lisp_function_lookup(Nob_String_View name) { return NULL; } +void build_scopes(Scopes *scopes) { + // clang-format off + Nob_String_View obj_name = (Nob_String_View){ + .items = "+", + .count = 1 + }; + ScopeObject obj = (ScopeObject){ + .name = obj_name, + .node = (Node){ + .kind = NODE_KIND_FUNCTION, + .as_function = { + .name = obj_name, + .apply = lisp_function_addition + } + } + }; + nob_da_append(&globalScope, obj); + + obj_name = (Nob_String_View){ + .items = "println", + .count = 7 + }; + obj = (ScopeObject){ + .name = obj_name, + .node = (Node){ + .kind = NODE_KIND_FUNCTION, + .as_function = { + .name = obj_name, + .apply = lisp_function_println + } + } + }; + nob_da_append(&globalScope, obj); + // clang-format on + + nob_da_append(scopes, globalScope); +} + const char *token_kind_name(TokenKind kind) { switch (kind) { case TOKEN_KIND_PAR_LEFT: @@ -54,8 +89,8 @@ void node_print(Node node) { printf(")"); } break; case NODE_KIND_FUNCTION: { - LispFunction func = node.as_function; - printf(SV_Fmt, SV_Arg(func.name)); + Nob_String_View func_name = node.as_function.name; + printf(SV_Fmt, SV_Arg(func_name)); } break; } } @@ -180,15 +215,15 @@ Node *parse(Tokens *tokens) { return node; } -Node *eval(Node *node) { - if (node == NULL) +Node *eval(Node *node, Scopes *scopes) { + if (node == NULL || scopes == NULL) return NULL; switch (node->kind) { case NODE_KIND_NUMBER: return node; case NODE_KIND_SYMBOL: { - return lisp_function_lookup(node->as_symbol); + return scope_lookup(scopes, node->as_symbol); } case NODE_KIND_LIST: { Nodes *children = node->as_list; @@ -196,16 +231,15 @@ Node *eval(Node *node) { return node; Node *head = &children->items[0]; - Node *func_node = eval(head); + Node *func_node = eval(head, scopes); Nodes *args = malloc(sizeof(Nodes)); for (size_t i = 1; i < children->count; i++) { - nob_da_append(args, *eval(&children->items[i])); + nob_da_append(args, *eval(&children->items[i], scopes)); } if (func_node->kind == NODE_KIND_FUNCTION) { - LispFunction func = func_node->as_function; - return func.apply(args); + return func_node->as_function.apply(args, scopes); } printf("Not a function: '"); diff --git a/lisp.h b/lisp.h index 294c847..db2dd71 100644 --- a/lisp.h +++ b/lisp.h @@ -30,22 +30,22 @@ typedef enum e_NodeKind { typedef struct s_Node Node; typedef struct s_Nodes Nodes; +typedef struct s_Scopes Scopes; -typedef Node *(*lisp_function_ptr)(Nodes *args); -typedef struct s_LispFunction { - Nob_String_View name; - lisp_function_ptr apply; -} LispFunction; +typedef Node *(*LispFunction)(Nodes *args, Scopes *scopes); -typedef struct s_Node { +struct s_Node { NodeKind kind; union { Nob_String_View as_symbol; Nodes *as_list; long long as_number; - LispFunction as_function; + struct { + Nob_String_View name; + LispFunction apply; + } as_function; }; -} Node; +}; struct s_Nodes { Node *items; @@ -53,14 +53,34 @@ struct s_Nodes { size_t capacity; }; +typedef struct s_ScopeObject { + Nob_String_View name; + Node node; +} ScopeObject; + +// TODO: use hashtable +typedef struct s_Scope { + ScopeObject *items; + size_t count; + size_t capacity; +} Scope; + +struct s_Scopes { + Scope *items; + size_t count; + size_t capacity; +}; + const char *token_kind_name(TokenKind kind); void node_print(Node node); +void build_scopes(Scopes *scopes); void tokenize(Nob_String_View content, Tokens *tokens); Node *parse(Tokens *tokens); -Node *eval(Node *node); +Node *eval(Node *node, Scopes *scopes); // builtins -Node *lisp_function_addition(Nodes *args); +Node *lisp_function_addition(Nodes *args, Scopes *scopes); +Node *lisp_function_println(Nodes *args, Scopes *scopes); #endif // LISP_H diff --git a/main.c b/main.c index 722bc93..763ddca 100644 --- a/main.c +++ b/main.c @@ -37,11 +37,15 @@ int main(int argc, char **argv) { } #endif + Scopes scopes = {0}; + build_scopes(&scopes); + Node *result = parse(&tokens); if (result == NULL) return 1; - result = eval(result); + result = eval(result, &scopes); + printf("= "); node_print(*result); printf("\n");