blob: 62b43c0c03a96e528ca526a159819e2fdda369da [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
swissChilica107a02021-04-14 12:07:30 -070018struct function
19{
20 char *name;
21 int nargs; // number of arguments
swissChili2999dd12021-07-02 14:19:53 -070022 enum namespace namespace;
swissChilica107a02021-04-14 12:07:30 -070023
swissChili2999dd12021-07-02 14:19:53 -070024 union
25 {
swissChili53472e82021-05-08 16:06:32 -070026 value_t (*def0)();
27 value_t (*def1)(value_t);
28 value_t (*def2)(value_t, value_t);
29 value_t (*def3)(value_t, value_t, value_t);
swissChilica107a02021-04-14 12:07:30 -070030 void *code_ptr;
swissChilif3e7f182021-04-20 13:57:22 -070031 uintptr_t code_addr;
swissChilica107a02021-04-14 12:07:30 -070032 };
33
34 struct function *prev;
35};
36
swissChilif68671f2021-07-05 14:14:44 -070037struct loaded_file
38{
39 char *resolved_path;
40 struct loaded_file *previous;
41};
42
swissChilica107a02021-04-14 12:07:30 -070043struct environment
44{
45 struct function *first;
swissChilif68671f2021-07-05 14:14:44 -070046 struct loaded_file *first_loaded;
swissChilica107a02021-04-14 12:07:30 -070047};
48
swissChili923b5362021-05-09 20:31:43 -070049enum var_type
50{
51 V_BOUND, // Bound local variable
52 V_ARGUMENT, // Bound function argument
53 V_GLOBAL, // Global variable
54 V_FREE // Free (lexical) variable
55};
56
swissChilica107a02021-04-14 12:07:30 -070057struct variable
58{
59 char *name;
swissChili923b5362021-05-09 20:31:43 -070060 uintptr_t number;
61 enum var_type type;
swissChilica107a02021-04-14 12:07:30 -070062 struct variable *prev;
63};
64
swissChilif1ba8c12021-07-02 18:45:38 -070065/// Local environment
swissChilica107a02021-04-14 12:07:30 -070066struct local
67{
swissChilif1ba8c12021-07-02 18:45:38 -070068 /// Parent environment, NULL if none (root).
69 struct local *parent;
70
swissChili74348422021-07-04 13:23:24 -070071 /// Name that the current function should be referred to by, e.g. `recurse`
72 /// for a lambda.
73 char *current_function_name;
74
75 int num_vars, num_args;
swissChilif1ba8c12021-07-02 18:45:38 -070076 /// Most recently defined variable
swissChilica107a02021-04-14 12:07:30 -070077 struct variable *first;
swissChili53472e82021-05-08 16:06:32 -070078 int npc;
79 int nextpc;
swissChili67bdf282021-06-06 18:46:08 -070080 bool *stack_slots;
swissChiliddc97542021-07-04 11:47:42 -070081 /// Number of slots allocated in `stack_slots`
82 int num_stack_slots;
83 /// Number of entries used in `stack_slots`
84 int num_stack_entries;
85 /// Number of closure slots total (allocated as V_FREE variables)
86 int num_closure_slots;
swissChilica107a02021-04-14 12:07:30 -070087};
88
swissChili53472e82021-05-08 16:06:32 -070089void compile_expression(struct environment *env, struct local *local,
90 value_t val, dasm_State **Dst);
swissChili6b47b6d2021-06-30 22:08:55 -070091
92/**
swissChiliddc97542021-07-04 11:47:42 -070093 * Compile a function
94 * @param args The function args and body, e.g. `((b c) d)`
95 * @param namespace The function namespace.
96 * @param env The environment.
97 * @param local_out The local environment generated for this function will be
98 * returned here. NULL if you do not care about it being returned (you probably
99 * should since you need to free the stack slot allocation map).
100 * @param local_parent Parent local environment, only needed for closures. NULL
101 * if no parent.
102 * @param nargs The number of arguments for this function will be returned here.
103 * NULL if you don't care about it.
104 * @returns The compiled function state. You should probably give this to
105 * `add_function` or something similar.
106 */
107struct dasm_State *compile_function(value_t args, enum namespace namespace,
108 struct environment *env, struct local *local_out,
swissChili74348422021-07-04 13:23:24 -0700109 struct local *local_parent, int *nargs, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700110
111void compile_variable(struct variable *v, dasm_State *Dst);
112
113/**
swissChili6b47b6d2021-06-30 22:08:55 -0700114 * Compile a backquoted expression
115 */
116void compile_backquote(struct environment *env, struct local *local,
117 value_t val, dasm_State **Dst);
118
swissChili53472e82021-05-08 16:06:32 -0700119void compile_expr_to_func(struct environment *env, char *name, value_t val,
120 dasm_State **Dst);
swissChili6b47b6d2021-06-30 22:08:55 -0700121
swissChili53472e82021-05-08 16:06:32 -0700122int nextpc(struct local *local, dasm_State **Dst);
swissChili67bdf282021-06-06 18:46:08 -0700123
124// Local utilities
125unsigned int local_alloc(struct local *local);
126void local_free(struct local *local, unsigned int slot);
127
swissChilif1ba8c12021-07-02 18:45:38 -0700128/**
swissChili708d4c42021-07-04 17:40:07 -0700129 * Deletes the memory allocated in `local`. Does not actually call `free()` on
130 * `local` itself, but frees the variables and stack slots associated with it.
131 */
132void del_local(struct local *local);
133
134/**
135 * Deletes the memory allocated in `env`. Does not actually call `free()` on
136 * `env` itself.
137 */
138void del_env(struct environment *env);
139
140/**
swissChilif1ba8c12021-07-02 18:45:38 -0700141 * Walk `body` and reserve space in `local` for any variable declarations.
142 */
swissChili67bdf282021-06-06 18:46:08 -0700143void walk_and_alloc(struct local *local, value_t body);
swissChili8fc5e2f2021-04-22 13:45:10 -0700144// Compile top-level declaration
swissChili53472e82021-05-08 16:06:32 -0700145void compile_tl(value_t val, struct environment *env);
swissChilif68671f2021-07-05 14:14:44 -0700146
147/**
148 * Compile a file in a new environment.
149 * @param filename The path to the file.
150 * @param ok Set to `true` if loading succeeds, `false` otherwise. If `ok` is
151 * NULL it is ignored.
152 * @returns The environment for the compiled file, or an empty environment if
153 * `ok` was set to `false` (i.e. the file could not be compiled).
154 */
155struct environment compile_file(char *filename, bool *ok);
156
swissChili53472e82021-05-08 16:06:32 -0700157struct function *find_function(struct environment *env, char *name);
swissChili923b5362021-05-09 20:31:43 -0700158struct variable *add_variable(struct local *local, enum var_type type,
159 char *name, int number);
swissChiliddc97542021-07-04 11:47:42 -0700160
161/**
162 * Find a variable in `local` with name `name`.
163 * @returns The variable, NULL if not found.
164 */
swissChili923b5362021-05-09 20:31:43 -0700165struct variable *find_variable(struct local *local, char *name);
swissChiliddc97542021-07-04 11:47:42 -0700166
swissChili923b5362021-05-09 20:31:43 -0700167void destroy_local(struct local *local);
swissChili2999dd12021-07-02 14:19:53 -0700168
169/**
170 * Like `apply` in lisp, calls func with list args and returns the result.
171 */
172value_t call_list(struct function *func, value_t list);
swissChiliddc97542021-07-04 11:47:42 -0700173value_t call_list_closure(struct closure *c, value_t list);
swissChilif68671f2021-07-05 14:14:44 -0700174
175/**
176 * Load a lisp file into the current environment.
177 * @returns `true` if succesful, `false` otherwise.
178 */
179bool load(struct environment *env, char *path);
180
181/**
182 * Mark a file `path` as loaded in the environment. `path` will be expanded with
183 * `readlink`. You can pass a temporary string here, memory will be allocated by
184 * this function as needed.
185 */
186void add_load(struct environment *env, char *path);