blob: 5ba66204f104630e2678ba60ac6e645ae1dcd49d [file] [log] [blame]
swissChilica107a02021-04-14 12:07:30 -07001#pragma once
2
3#include "lisp.h"
swissChilif3e7f182021-04-20 13:57:22 -07004#include <dasm_proto.h>
swissChilica107a02021-04-14 12:07:30 -07005#include <stdbool.h>
swissChilib3ca4fb2021-04-20 10:33:00 -07006#include <stdint.h>
swissChilica107a02021-04-14 12:07:30 -07007
swissChili2999dd12021-07-02 14:19:53 -07008enum namespace
9{
swissChiliddc97542021-07-04 11:47:42 -070010 /// A function
swissChili2999dd12021-07-02 14:19:53 -070011 NS_FUNCTION,
swissChiliddc97542021-07-04 11:47:42 -070012 /// A macro
swissChili2999dd12021-07-02 14:19:53 -070013 NS_MACRO,
swissChiliddc97542021-07-04 11:47:42 -070014 /// An anonymous function (a lambda/closure)
15 NS_ANONYMOUS,
swissChili2999dd12021-07-02 14:19:53 -070016};
17
swissChili15f1cae2021-07-05 19:08:47 -070018struct args *new_args();
19struct args *add_optional_arg(struct args *args, value_t name,
20 value_t expression);
21
22/**
23 * @returns if `number` is an acceptable number of arguments for `args`.
24 */
25bool are_args_acceptable(struct args *args, int number);
26
swissChilica107a02021-04-14 12:07:30 -070027struct function
28{
29 char *name;
swissChili15f1cae2021-07-05 19:08:47 -070030 struct args *args;
swissChili2999dd12021-07-02 14:19:53 -070031 enum namespace namespace;
swissChilica107a02021-04-14 12:07:30 -070032
swissChili7e1393c2021-07-07 12:59:12 -070033 union {
swissChili53472e82021-05-08 16:06:32 -070034 value_t (*def0)();
35 value_t (*def1)(value_t);
36 value_t (*def2)(value_t, value_t);
37 value_t (*def3)(value_t, value_t, value_t);
swissChili484295d2021-07-09 21:25:55 -070038 void *code_ptr;
swissChilif3e7f182021-04-20 13:57:22 -070039 uintptr_t code_addr;
swissChilica107a02021-04-14 12:07:30 -070040 };
41
42 struct function *prev;
43};
44
swissChilif68671f2021-07-05 14:14:44 -070045struct loaded_file
46{
47 char *resolved_path;
48 struct loaded_file *previous;
49};
50
swissChilica107a02021-04-14 12:07:30 -070051struct environment
52{
53 struct function *first;
swissChilif68671f2021-07-05 14:14:44 -070054 struct loaded_file *first_loaded;
swissChilica107a02021-04-14 12:07:30 -070055};
56
swissChili923b5362021-05-09 20:31:43 -070057enum var_type
58{
59 V_BOUND, // Bound local variable
60 V_ARGUMENT, // Bound function argument
61 V_GLOBAL, // Global variable
62 V_FREE // Free (lexical) variable
63};
64
swissChilica107a02021-04-14 12:07:30 -070065struct variable
66{
67 char *name;
swissChili923b5362021-05-09 20:31:43 -070068 uintptr_t number;
69 enum var_type type;
swissChilica107a02021-04-14 12:07:30 -070070 struct variable *prev;
71};
72
swissChilif1ba8c12021-07-02 18:45:38 -070073/// Local environment
swissChilica107a02021-04-14 12:07:30 -070074struct local
75{
swissChilif1ba8c12021-07-02 18:45:38 -070076 /// Parent environment, NULL if none (root).
77 struct local *parent;
78
swissChili74348422021-07-04 13:23:24 -070079 /// Name that the current function should be referred to by, e.g. `recurse`
80 /// for a lambda.
81 char *current_function_name;
82
swissChili7e1393c2021-07-07 12:59:12 -070083 /// Path to the current file
84 char *current_file_path;
85
swissChili15f1cae2021-07-05 19:08:47 -070086 int num_vars;
87 struct args *args;
swissChilif1ba8c12021-07-02 18:45:38 -070088 /// Most recently defined variable
swissChilica107a02021-04-14 12:07:30 -070089 struct variable *first;
swissChili53472e82021-05-08 16:06:32 -070090 int npc;
91 int nextpc;
swissChili67bdf282021-06-06 18:46:08 -070092 bool *stack_slots;
swissChiliddc97542021-07-04 11:47:42 -070093 /// Number of slots allocated in `stack_slots`
94 int num_stack_slots;
95 /// Number of entries used in `stack_slots`
96 int num_stack_entries;
97 /// Number of closure slots total (allocated as V_FREE variables)
98 int num_closure_slots;
swissChilica107a02021-04-14 12:07:30 -070099};
100
swissChili15f1cae2021-07-05 19:08:47 -0700101/**
102 * Parse a list of arguments to an args object and add them as V_ARGUMENT
103 * variables to `local`. The list should be in the same format as is accepted by
104 * `defun`, `defmacro`, `lambda`, etc.
105 * @returns NULL if the list is malformed.
106 */
swissChili7e1393c2021-07-07 12:59:12 -0700107struct args *list_to_args(struct environment *env, value_t list,
108 struct local *local);
swissChili15f1cae2021-07-05 19:08:47 -0700109
110/**
111 * Print out `args` to stdout. Useful for debugging.
112 */
113void display_args(struct args *args);
114
swissChili53472e82021-05-08 16:06:32 -0700115void compile_expression(struct environment *env, struct local *local,
swissChilib51552c2021-08-03 10:23:37 -0700116 value_t val, bool tail, dasm_State **Dst);
swissChili6b47b6d2021-06-30 22:08:55 -0700117
118/**
swissChiliddc97542021-07-04 11:47:42 -0700119 * Compile a function
120 * @param args The function args and body, e.g. `((b c) d)`
121 * @param namespace The function namespace.
122 * @param env The environment.
123 * @param local_out The local environment generated for this function will be
124 * returned here. NULL if you do not care about it being returned (you probably
125 * should since you need to free the stack slot allocation map).
126 * @param local_parent Parent local environment, only needed for closures. NULL
127 * if no parent.
swissChili15f1cae2021-07-05 19:08:47 -0700128 * @param args An object representing the arguments this function accepts will
129 * be returned here. Set this to NULL if you don't care.
swissChiliddc97542021-07-04 11:47:42 -0700130 * @returns The compiled function state. You should probably give this to
131 * `add_function` or something similar.
132 */
133struct dasm_State *compile_function(value_t args, enum namespace namespace,
swissChili7e1393c2021-07-07 12:59:12 -0700134 struct environment *env,
135 struct local *local_out,
136 struct local *local_parent,
137 struct args **ar, char *name, char *path);
swissChiliddc97542021-07-04 11:47:42 -0700138
139void compile_variable(struct variable *v, dasm_State *Dst);
140
141/**
swissChili6b47b6d2021-06-30 22:08:55 -0700142 * Compile a backquoted expression
143 */
144void compile_backquote(struct environment *env, struct local *local,
145 value_t val, dasm_State **Dst);
146
swissChili53472e82021-05-08 16:06:32 -0700147int nextpc(struct local *local, dasm_State **Dst);
swissChili67bdf282021-06-06 18:46:08 -0700148
149// Local utilities
150unsigned int local_alloc(struct local *local);
151void local_free(struct local *local, unsigned int slot);
152
swissChilif1ba8c12021-07-02 18:45:38 -0700153/**
swissChili708d4c42021-07-04 17:40:07 -0700154 * Deletes the memory allocated in `local`. Does not actually call `free()` on
155 * `local` itself, but frees the variables and stack slots associated with it.
156 */
157void del_local(struct local *local);
158
159/**
160 * Deletes the memory allocated in `env`. Does not actually call `free()` on
161 * `env` itself.
162 */
163void del_env(struct environment *env);
164
165/**
swissChilif1ba8c12021-07-02 18:45:38 -0700166 * Walk `body` and reserve space in `local` for any variable declarations.
167 */
swissChili67bdf282021-06-06 18:46:08 -0700168void walk_and_alloc(struct local *local, value_t body);
swissChili7e1393c2021-07-07 12:59:12 -0700169
170/**
171 * Compile a top level definition
172 * @param fname The path to the current file.
173 * @param val The expression to compile.
174 */
175void compile_tl(value_t val, struct environment *env, char *fname);
swissChilif68671f2021-07-05 14:14:44 -0700176
177/**
178 * Compile a file in a new environment.
179 * @param filename The path to the file.
180 * @param ok Set to `true` if loading succeeds, `false` otherwise. If `ok` is
181 * NULL it is ignored.
182 * @returns The environment for the compiled file, or an empty environment if
183 * `ok` was set to `false` (i.e. the file could not be compiled).
184 */
swissChili7e1393c2021-07-07 12:59:12 -0700185struct environment *compile_file(char *filename, bool *ok);
swissChilif68671f2021-07-05 14:14:44 -0700186
swissChili53472e82021-05-08 16:06:32 -0700187struct function *find_function(struct environment *env, char *name);
swissChili923b5362021-05-09 20:31:43 -0700188struct variable *add_variable(struct local *local, enum var_type type,
189 char *name, int number);
swissChiliddc97542021-07-04 11:47:42 -0700190
191/**
192 * Find a variable in `local` with name `name`.
193 * @returns The variable, NULL if not found.
194 */
swissChili923b5362021-05-09 20:31:43 -0700195struct variable *find_variable(struct local *local, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700196
swissChili923b5362021-05-09 20:31:43 -0700197void destroy_local(struct local *local);
swissChili2999dd12021-07-02 14:19:53 -0700198
199/**
200 * Like `apply` in lisp, calls func with list args and returns the result.
201 */
202value_t call_list(struct function *func, value_t list);
swissChiliddc97542021-07-04 11:47:42 -0700203value_t call_list_closure(struct closure *c, value_t list);
swissChilif68671f2021-07-05 14:14:44 -0700204
205/**
206 * Load a lisp file into the current environment.
207 * @returns `true` if succesful, `false` otherwise.
208 */
209bool load(struct environment *env, char *path);
210
211/**
swissChili484295d2021-07-09 21:25:55 -0700212 * Load a file relative to another file.
213 * @param to The file to load relative to.
214 * @param name The name or relative path of the file to load.
215 * @param env The environment to load in.
216 */
217value_t load_relative(struct environment *env, char *to, value_t name);
218
219/**
swissChilif68671f2021-07-05 14:14:44 -0700220 * Mark a file `path` as loaded in the environment. `path` will be expanded with
221 * `readlink`. You can pass a temporary string here, memory will be allocated by
222 * this function as needed.
223 */
224void add_load(struct environment *env, char *path);