blob: 62f1b69cc95eb8cc67f9e2254aa0adefe5af1aff [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 */
swissChili6d02af42021-08-05 19:49:01 -0700107struct error list_to_args(struct environment *env, value_t list,
108 struct local *local, struct args **args);
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
swissChili6d02af42021-08-05 19:49:01 -0700115struct error compile_expression(struct environment *env, struct local *local,
116 value_t val, bool tail, dasm_State **Dst) WARN_UNUSED;
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 */
swissChili6d02af42021-08-05 19:49:01 -0700133struct error compile_function(value_t args, enum namespace namespace,
134 struct environment *env,
135 struct local *local_out,
136 struct local *local_parent,
137 struct args **ar, char *name, char *path,
138 dasm_State **s) WARN_UNUSED;
swissChiliddc97542021-07-04 11:47:42 -0700139
swissChili6d02af42021-08-05 19:49:01 -0700140struct error compile_variable(struct variable *v, dasm_State *Dst) WARN_UNUSED;
swissChiliddc97542021-07-04 11:47:42 -0700141
142/**
swissChili6b47b6d2021-06-30 22:08:55 -0700143 * Compile a backquoted expression
144 */
swissChili6d02af42021-08-05 19:49:01 -0700145struct error compile_backquote(struct environment *env, struct local *local,
146 value_t val, dasm_State **Dst) WARN_UNUSED;
swissChili6b47b6d2021-06-30 22:08:55 -0700147
swissChili53472e82021-05-08 16:06:32 -0700148int nextpc(struct local *local, dasm_State **Dst);
swissChili67bdf282021-06-06 18:46:08 -0700149
150// Local utilities
151unsigned int local_alloc(struct local *local);
152void local_free(struct local *local, unsigned int slot);
153
swissChilif1ba8c12021-07-02 18:45:38 -0700154/**
swissChilic0acce42022-07-31 13:38:17 -0700155 * Deletes the memory allocated in `local`. Does not actually call
156 * `free()` on `local` itself, but frees the variables and stack slots
157 * associated with it. Also does NOT free `local->args`. You must do
158 * that yourself if you want. This is because these arguments are
159 * often used in multiple places.
swissChili708d4c42021-07-04 17:40:07 -0700160 */
161void del_local(struct local *local);
162
163/**
164 * Deletes the memory allocated in `env`. Does not actually call `free()` on
165 * `env` itself.
166 */
167void del_env(struct environment *env);
168
169/**
swissChilif1ba8c12021-07-02 18:45:38 -0700170 * Walk `body` and reserve space in `local` for any variable declarations.
171 */
swissChilifc5c9412021-08-08 19:08:26 -0700172struct error walk_and_alloc(struct environment *env, struct local *local, value_t *body, bool quoted);
swissChili7e1393c2021-07-07 12:59:12 -0700173
174/**
175 * Compile a top level definition
176 * @param fname The path to the current file.
177 * @param val The expression to compile.
178 */
swissChili6d02af42021-08-05 19:49:01 -0700179struct error compile_tl(value_t val, struct environment *env, char *fname) WARN_UNUSED;
swissChilif68671f2021-07-05 14:14:44 -0700180
181/**
182 * Compile a file in a new environment.
183 * @param filename The path to the file.
184 * @param ok Set to `true` if loading succeeds, `false` otherwise. If `ok` is
185 * NULL it is ignored.
186 * @returns The environment for the compiled file, or an empty environment if
187 * `ok` was set to `false` (i.e. the file could not be compiled).
188 */
swissChili6d02af42021-08-05 19:49:01 -0700189struct error compile_file(char *filename, struct environment **env) WARN_UNUSED;
swissChilif68671f2021-07-05 14:14:44 -0700190
swissChili53472e82021-05-08 16:06:32 -0700191struct function *find_function(struct environment *env, char *name);
swissChili923b5362021-05-09 20:31:43 -0700192struct variable *add_variable(struct local *local, enum var_type type,
193 char *name, int number);
swissChiliddc97542021-07-04 11:47:42 -0700194
195/**
196 * Find a variable in `local` with name `name`.
197 * @returns The variable, NULL if not found.
198 */
swissChili923b5362021-05-09 20:31:43 -0700199struct variable *find_variable(struct local *local, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700200
swissChili923b5362021-05-09 20:31:43 -0700201void destroy_local(struct local *local);
swissChili2999dd12021-07-02 14:19:53 -0700202
203/**
204 * Like `apply` in lisp, calls func with list args and returns the result.
205 */
206value_t call_list(struct function *func, value_t list);
swissChiliddc97542021-07-04 11:47:42 -0700207value_t call_list_closure(struct closure *c, value_t list);
swissChilif68671f2021-07-05 14:14:44 -0700208
209/**
210 * Load a lisp file into the current environment.
211 * @returns `true` if succesful, `false` otherwise.
212 */
213bool load(struct environment *env, char *path);
214
215/**
swissChili484295d2021-07-09 21:25:55 -0700216 * Load a file relative to another file.
217 * @param to The file to load relative to.
218 * @param name The name or relative path of the file to load.
219 * @param env The environment to load in.
220 */
221value_t load_relative(struct environment *env, char *to, value_t name);
222
223/**
swissChilif68671f2021-07-05 14:14:44 -0700224 * Mark a file `path` as loaded in the environment. `path` will be expanded with
225 * `readlink`. You can pass a temporary string here, memory will be allocated by
226 * this function as needed.
227 */
228void add_load(struct environment *env, char *path);