blob: e03d93abcfe3a0139dc6c1a15c438ca6e7461030 [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 -070018
19struct args *new_args();
20struct args *add_optional_arg(struct args *args, value_t name,
21 value_t expression);
22
23/**
24 * @returns if `number` is an acceptable number of arguments for `args`.
25 */
26bool are_args_acceptable(struct args *args, int number);
27
swissChilica107a02021-04-14 12:07:30 -070028struct function
29{
30 char *name;
swissChili15f1cae2021-07-05 19:08:47 -070031 struct args *args;
swissChili2999dd12021-07-02 14:19:53 -070032 enum namespace namespace;
swissChilica107a02021-04-14 12:07:30 -070033
swissChili2999dd12021-07-02 14:19:53 -070034 union
35 {
swissChili53472e82021-05-08 16:06:32 -070036 value_t (*def0)();
37 value_t (*def1)(value_t);
38 value_t (*def2)(value_t, value_t);
39 value_t (*def3)(value_t, value_t, value_t);
swissChilica107a02021-04-14 12:07:30 -070040 void *code_ptr;
swissChilif3e7f182021-04-20 13:57:22 -070041 uintptr_t code_addr;
swissChilica107a02021-04-14 12:07:30 -070042 };
43
44 struct function *prev;
45};
46
swissChilif68671f2021-07-05 14:14:44 -070047struct loaded_file
48{
49 char *resolved_path;
50 struct loaded_file *previous;
51};
52
swissChilica107a02021-04-14 12:07:30 -070053struct environment
54{
55 struct function *first;
swissChilif68671f2021-07-05 14:14:44 -070056 struct loaded_file *first_loaded;
swissChilica107a02021-04-14 12:07:30 -070057};
58
swissChili923b5362021-05-09 20:31:43 -070059enum var_type
60{
61 V_BOUND, // Bound local variable
62 V_ARGUMENT, // Bound function argument
63 V_GLOBAL, // Global variable
64 V_FREE // Free (lexical) variable
65};
66
swissChilica107a02021-04-14 12:07:30 -070067struct variable
68{
69 char *name;
swissChili923b5362021-05-09 20:31:43 -070070 uintptr_t number;
71 enum var_type type;
swissChilica107a02021-04-14 12:07:30 -070072 struct variable *prev;
73};
74
swissChilif1ba8c12021-07-02 18:45:38 -070075/// Local environment
swissChilica107a02021-04-14 12:07:30 -070076struct local
77{
swissChilif1ba8c12021-07-02 18:45:38 -070078 /// Parent environment, NULL if none (root).
79 struct local *parent;
80
swissChili74348422021-07-04 13:23:24 -070081 /// Name that the current function should be referred to by, e.g. `recurse`
82 /// for a lambda.
83 char *current_function_name;
84
swissChili15f1cae2021-07-05 19:08:47 -070085 int num_vars;
86 struct args *args;
swissChilif1ba8c12021-07-02 18:45:38 -070087 /// Most recently defined variable
swissChilica107a02021-04-14 12:07:30 -070088 struct variable *first;
swissChili53472e82021-05-08 16:06:32 -070089 int npc;
90 int nextpc;
swissChili67bdf282021-06-06 18:46:08 -070091 bool *stack_slots;
swissChiliddc97542021-07-04 11:47:42 -070092 /// Number of slots allocated in `stack_slots`
93 int num_stack_slots;
94 /// Number of entries used in `stack_slots`
95 int num_stack_entries;
96 /// Number of closure slots total (allocated as V_FREE variables)
97 int num_closure_slots;
swissChilica107a02021-04-14 12:07:30 -070098};
99
swissChili15f1cae2021-07-05 19:08:47 -0700100/**
101 * Parse a list of arguments to an args object and add them as V_ARGUMENT
102 * variables to `local`. The list should be in the same format as is accepted by
103 * `defun`, `defmacro`, `lambda`, etc.
104 * @returns NULL if the list is malformed.
105 */
106struct args *list_to_args(struct environment *env, value_t list, struct local *local);
107
108/**
109 * Print out `args` to stdout. Useful for debugging.
110 */
111void display_args(struct args *args);
112
swissChili53472e82021-05-08 16:06:32 -0700113void compile_expression(struct environment *env, struct local *local,
114 value_t val, dasm_State **Dst);
swissChili6b47b6d2021-06-30 22:08:55 -0700115
116/**
swissChiliddc97542021-07-04 11:47:42 -0700117 * Compile a function
118 * @param args The function args and body, e.g. `((b c) d)`
119 * @param namespace The function namespace.
120 * @param env The environment.
121 * @param local_out The local environment generated for this function will be
122 * returned here. NULL if you do not care about it being returned (you probably
123 * should since you need to free the stack slot allocation map).
124 * @param local_parent Parent local environment, only needed for closures. NULL
125 * if no parent.
swissChili15f1cae2021-07-05 19:08:47 -0700126 * @param args An object representing the arguments this function accepts will
127 * be returned here. Set this to NULL if you don't care.
swissChiliddc97542021-07-04 11:47:42 -0700128 * @returns The compiled function state. You should probably give this to
129 * `add_function` or something similar.
130 */
131struct dasm_State *compile_function(value_t args, enum namespace namespace,
132 struct environment *env, struct local *local_out,
swissChili15f1cae2021-07-05 19:08:47 -0700133 struct local *local_parent, struct args **ar, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700134
135void compile_variable(struct variable *v, dasm_State *Dst);
136
137/**
swissChili6b47b6d2021-06-30 22:08:55 -0700138 * Compile a backquoted expression
139 */
140void compile_backquote(struct environment *env, struct local *local,
141 value_t val, dasm_State **Dst);
142
swissChili53472e82021-05-08 16:06:32 -0700143void compile_expr_to_func(struct environment *env, char *name, value_t val,
144 dasm_State **Dst);
swissChili6b47b6d2021-06-30 22:08:55 -0700145
swissChili53472e82021-05-08 16:06:32 -0700146int nextpc(struct local *local, dasm_State **Dst);
swissChili67bdf282021-06-06 18:46:08 -0700147
148// Local utilities
149unsigned int local_alloc(struct local *local);
150void local_free(struct local *local, unsigned int slot);
151
swissChilif1ba8c12021-07-02 18:45:38 -0700152/**
swissChili708d4c42021-07-04 17:40:07 -0700153 * Deletes the memory allocated in `local`. Does not actually call `free()` on
154 * `local` itself, but frees the variables and stack slots associated with it.
155 */
156void del_local(struct local *local);
157
158/**
159 * Deletes the memory allocated in `env`. Does not actually call `free()` on
160 * `env` itself.
161 */
162void del_env(struct environment *env);
163
164/**
swissChilif1ba8c12021-07-02 18:45:38 -0700165 * Walk `body` and reserve space in `local` for any variable declarations.
166 */
swissChili67bdf282021-06-06 18:46:08 -0700167void walk_and_alloc(struct local *local, value_t body);
swissChili8fc5e2f2021-04-22 13:45:10 -0700168// Compile top-level declaration
swissChili53472e82021-05-08 16:06:32 -0700169void compile_tl(value_t val, struct environment *env);
swissChilif68671f2021-07-05 14:14:44 -0700170
171/**
172 * Compile a file in a new environment.
173 * @param filename The path to the file.
174 * @param ok Set to `true` if loading succeeds, `false` otherwise. If `ok` is
175 * NULL it is ignored.
176 * @returns The environment for the compiled file, or an empty environment if
177 * `ok` was set to `false` (i.e. the file could not be compiled).
178 */
179struct environment compile_file(char *filename, bool *ok);
180
swissChili53472e82021-05-08 16:06:32 -0700181struct function *find_function(struct environment *env, char *name);
swissChili923b5362021-05-09 20:31:43 -0700182struct variable *add_variable(struct local *local, enum var_type type,
183 char *name, int number);
swissChiliddc97542021-07-04 11:47:42 -0700184
185/**
186 * Find a variable in `local` with name `name`.
187 * @returns The variable, NULL if not found.
188 */
swissChili923b5362021-05-09 20:31:43 -0700189struct variable *find_variable(struct local *local, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700190
swissChili923b5362021-05-09 20:31:43 -0700191void destroy_local(struct local *local);
swissChili2999dd12021-07-02 14:19:53 -0700192
193/**
194 * Like `apply` in lisp, calls func with list args and returns the result.
195 */
196value_t call_list(struct function *func, value_t list);
swissChiliddc97542021-07-04 11:47:42 -0700197value_t call_list_closure(struct closure *c, value_t list);
swissChilif68671f2021-07-05 14:14:44 -0700198
199/**
200 * Load a lisp file into the current environment.
201 * @returns `true` if succesful, `false` otherwise.
202 */
203bool load(struct environment *env, char *path);
204
205/**
206 * Mark a file `path` as loaded in the environment. `path` will be expanded with
207 * `readlink`. You can pass a temporary string here, memory will be allocated by
208 * this function as needed.
209 */
210void add_load(struct environment *env, char *path);