blob: 75abe33695f1927e836e8e64a0d5643320459c4d [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/**
swissChili708d4c42021-07-04 17:40:07 -0700155 * Deletes the memory allocated in `local`. Does not actually call `free()` on
156 * `local` itself, but frees the variables and stack slots associated with it.
157 */
158void del_local(struct local *local);
159
160/**
161 * Deletes the memory allocated in `env`. Does not actually call `free()` on
162 * `env` itself.
163 */
164void del_env(struct environment *env);
165
166/**
swissChilif1ba8c12021-07-02 18:45:38 -0700167 * Walk `body` and reserve space in `local` for any variable declarations.
168 */
swissChili36f2c692021-08-08 14:31:44 -0700169struct error walk_and_alloc(struct environment *env, struct local *local, value_t *body);
swissChili7e1393c2021-07-07 12:59:12 -0700170
171/**
172 * Compile a top level definition
173 * @param fname The path to the current file.
174 * @param val The expression to compile.
175 */
swissChili6d02af42021-08-05 19:49:01 -0700176struct error compile_tl(value_t val, struct environment *env, char *fname) WARN_UNUSED;
swissChilif68671f2021-07-05 14:14:44 -0700177
178/**
179 * Compile a file in a new environment.
180 * @param filename The path to the file.
181 * @param ok Set to `true` if loading succeeds, `false` otherwise. If `ok` is
182 * NULL it is ignored.
183 * @returns The environment for the compiled file, or an empty environment if
184 * `ok` was set to `false` (i.e. the file could not be compiled).
185 */
swissChili6d02af42021-08-05 19:49:01 -0700186struct error compile_file(char *filename, struct environment **env) WARN_UNUSED;
swissChilif68671f2021-07-05 14:14:44 -0700187
swissChili53472e82021-05-08 16:06:32 -0700188struct function *find_function(struct environment *env, char *name);
swissChili923b5362021-05-09 20:31:43 -0700189struct variable *add_variable(struct local *local, enum var_type type,
190 char *name, int number);
swissChiliddc97542021-07-04 11:47:42 -0700191
192/**
193 * Find a variable in `local` with name `name`.
194 * @returns The variable, NULL if not found.
195 */
swissChili923b5362021-05-09 20:31:43 -0700196struct variable *find_variable(struct local *local, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700197
swissChili923b5362021-05-09 20:31:43 -0700198void destroy_local(struct local *local);
swissChili2999dd12021-07-02 14:19:53 -0700199
200/**
201 * Like `apply` in lisp, calls func with list args and returns the result.
202 */
203value_t call_list(struct function *func, value_t list);
swissChiliddc97542021-07-04 11:47:42 -0700204value_t call_list_closure(struct closure *c, value_t list);
swissChilif68671f2021-07-05 14:14:44 -0700205
206/**
207 * Load a lisp file into the current environment.
208 * @returns `true` if succesful, `false` otherwise.
209 */
210bool load(struct environment *env, char *path);
211
212/**
swissChili484295d2021-07-09 21:25:55 -0700213 * Load a file relative to another file.
214 * @param to The file to load relative to.
215 * @param name The name or relative path of the file to load.
216 * @param env The environment to load in.
217 */
218value_t load_relative(struct environment *env, char *to, value_t name);
219
220/**
swissChilif68671f2021-07-05 14:14:44 -0700221 * Mark a file `path` as loaded in the environment. `path` will be expanded with
222 * `readlink`. You can pass a temporary string here, memory will be allocated by
223 * this function as needed.
224 */
225void add_load(struct environment *env, char *path);