1 /*
2 * Copyright (c) 2021 Calvin Rose
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 
23 #ifndef JANET_COMPILE_H
24 #define JANET_COMPILE_H
25 
26 #ifndef JANET_AMALG
27 #include "features.h"
28 #include <janet.h>
29 #include "regalloc.h"
30 #endif
31 
32 /* Levels for compiler warnings */
33 typedef enum {
34     JANET_C_LINT_RELAXED,
35     JANET_C_LINT_NORMAL,
36     JANET_C_LINT_STRICT
37 } JanetCompileLintLevel;
38 
39 /* Tags for some functions for the prepared inliner */
40 #define JANET_FUN_DEBUG 1
41 #define JANET_FUN_ERROR 2
42 #define JANET_FUN_APPLY 3
43 #define JANET_FUN_YIELD 4
44 #define JANET_FUN_RESUME 5
45 #define JANET_FUN_IN 6
46 #define JANET_FUN_PUT 7
47 #define JANET_FUN_LENGTH 8
48 #define JANET_FUN_ADD 9
49 #define JANET_FUN_SUBTRACT 10
50 #define JANET_FUN_MULTIPLY 11
51 #define JANET_FUN_DIVIDE 12
52 #define JANET_FUN_BAND 13
53 #define JANET_FUN_BOR 14
54 #define JANET_FUN_BXOR 15
55 #define JANET_FUN_LSHIFT 16
56 #define JANET_FUN_RSHIFT 17
57 #define JANET_FUN_RSHIFTU 18
58 #define JANET_FUN_BNOT 19
59 #define JANET_FUN_GT 20
60 #define JANET_FUN_LT 21
61 #define JANET_FUN_GTE 22
62 #define JANET_FUN_LTE 23
63 #define JANET_FUN_EQ 24
64 #define JANET_FUN_NEQ 25
65 #define JANET_FUN_PROP 26
66 #define JANET_FUN_GET 27
67 #define JANET_FUN_NEXT 28
68 #define JANET_FUN_MODULO 29
69 #define JANET_FUN_REMAINDER 30
70 #define JANET_FUN_CMP 31
71 #define JANET_FUN_CANCEL 32
72 
73 /* Compiler typedefs */
74 typedef struct JanetCompiler JanetCompiler;
75 typedef struct FormOptions FormOptions;
76 typedef struct SlotTracker SlotTracker;
77 typedef struct JanetScope JanetScope;
78 typedef struct JanetSlot JanetSlot;
79 typedef struct JanetFopts JanetFopts;
80 typedef struct JanetFunOptimizer JanetFunOptimizer;
81 typedef struct JanetSpecial JanetSpecial;
82 
83 #define JANET_SLOT_CONSTANT 0x10000
84 #define JANET_SLOT_NAMED 0x20000
85 #define JANET_SLOT_MUTABLE 0x40000
86 #define JANET_SLOT_REF 0x80000
87 #define JANET_SLOT_RETURNED 0x100000
88 #define JANET_SLOT_DEP_NOTE 0x200000
89 #define JANET_SLOT_DEP_WARN 0x400000
90 #define JANET_SLOT_DEP_ERROR 0x800000
91 #define JANET_SLOT_SPLICED 0x1000000
92 
93 #define JANET_SLOTTYPE_ANY 0xFFFF
94 
95 /* A stack slot */
96 struct JanetSlot {
97     Janet constant; /* If the slot has a constant value */
98     int32_t index;
99     int32_t envindex; /* 0 is local, positive number is an upvalue */
100     uint32_t flags;
101 };
102 
103 #define JANET_SCOPE_FUNCTION 1
104 #define JANET_SCOPE_ENV 2
105 #define JANET_SCOPE_TOP 4
106 #define JANET_SCOPE_UNUSED 8
107 #define JANET_SCOPE_CLOSURE 16
108 #define JANET_SCOPE_WHILE 32
109 
110 /* A symbol and slot pair */
111 typedef struct SymPair {
112     JanetSlot slot;
113     const uint8_t *sym;
114     int keep;
115 } SymPair;
116 
117 /* A lexical scope during compilation */
118 struct JanetScope {
119 
120     /* For debugging */
121     const char *name;
122 
123     /* Scopes are doubly linked list */
124     JanetScope *parent;
125     JanetScope *child;
126 
127     /* Constants for this funcdef */
128     Janet *consts;
129 
130     /* Map of symbols to slots. Use a simple linear scan for symbols. */
131     SymPair *syms;
132 
133     /* FuncDefs */
134     JanetFuncDef **defs;
135 
136     /* Regsiter allocator */
137     JanetcRegisterAllocator ra;
138 
139     /* Upvalue allocator */
140     JanetcRegisterAllocator ua;
141 
142     /* Referenced closure environments. The values at each index correspond
143      * to which index to get the environment from in the parent. The environment
144      * that corresponds to the direct parent's stack will always have value 0. */
145     int32_t *envs;
146 
147     int32_t bytecode_start;
148     int flags;
149 };
150 
151 /* Compilation state */
152 struct JanetCompiler {
153 
154     /* Pointer to current scope */
155     JanetScope *scope;
156 
157     uint32_t *buffer;
158     JanetSourceMapping *mapbuffer;
159 
160     /* Hold the environment */
161     JanetTable *env;
162 
163     /* Name of source to attach to generated functions */
164     const uint8_t *source;
165 
166     /* The result of compilation */
167     JanetCompileResult result;
168 
169     /* Keep track of where we are in the source */
170     JanetSourceMapping current_mapping;
171 
172     /* Prevent unbounded recursion */
173     int recursion_guard;
174 
175     /* Collect linting results */
176     JanetArray *lints;
177 };
178 
179 #define JANET_FOPTS_TAIL 0x10000
180 #define JANET_FOPTS_HINT 0x20000
181 #define JANET_FOPTS_DROP 0x40000
182 
183 /* Options for compiling a single form */
184 struct JanetFopts {
185     JanetCompiler *compiler;
186     JanetSlot hint;
187     uint32_t flags; /* bit set of accepted primitive types */
188 };
189 
190 /* Get the default form options */
191 JanetFopts janetc_fopts_default(JanetCompiler *c);
192 
193 /* For optimizing builtin normal functions. */
194 struct JanetFunOptimizer {
195     int (*can_optimize)(JanetFopts opts, JanetSlot *args);
196     JanetSlot(*optimize)(JanetFopts opts, JanetSlot *args);
197 };
198 
199 /* A grouping of a named special and the corresponding compiler fragment */
200 struct JanetSpecial {
201     const char *name;
202     JanetSlot(*compile)(JanetFopts opts, int32_t argn, const Janet *argv);
203 };
204 
205 /****************************************************/
206 
207 /* Get an optimizer if it exists, otherwise NULL */
208 const JanetFunOptimizer *janetc_funopt(uint32_t flags);
209 
210 /* Get a special. Return NULL if none exists */
211 const JanetSpecial *janetc_special(const uint8_t *name);
212 
213 void janetc_freeslot(JanetCompiler *c, JanetSlot s);
214 void janetc_nameslot(JanetCompiler *c, const uint8_t *sym, JanetSlot s);
215 JanetSlot janetc_farslot(JanetCompiler *c);
216 
217 /* Throw away some code after checking that it is well formed. */
218 void janetc_throwaway(JanetFopts opts, Janet x);
219 
220 /* Get a target slot for emitting an instruction. Will always return
221  * a local slot. */
222 JanetSlot janetc_gettarget(JanetFopts opts);
223 
224 /* Get a bunch of slots for function arguments */
225 JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len);
226 
227 /* Get a bunch of slots for function arguments */
228 JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds);
229 
230 /* Push slots load via janetc_toslots. */
231 int32_t janetc_pushslots(JanetCompiler *c, JanetSlot *slots);
232 
233 /* Free slots loaded via janetc_toslots */
234 void janetc_freeslots(JanetCompiler *c, JanetSlot *slots);
235 
236 /* Generate the return instruction for a slot. */
237 JanetSlot janetc_return(JanetCompiler *c, JanetSlot s);
238 
239 /* Store an error */
240 void janetc_error(JanetCompiler *c, const uint8_t *m);
241 void janetc_cerror(JanetCompiler *c, const char *m);
242 
243 /* Linting */
244 void janetc_lintf(JanetCompiler *C, JanetCompileLintLevel level, const char *format, ...);
245 
246 /* Dispatch to correct form compiler */
247 JanetSlot janetc_value(JanetFopts opts, Janet x);
248 
249 /* Push and pop from the scope stack */
250 void janetc_scope(JanetScope *s, JanetCompiler *c, int flags, const char *name);
251 void janetc_popscope(JanetCompiler *c);
252 void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot);
253 JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c);
254 
255 /* Create a destory slots */
256 JanetSlot janetc_cslot(Janet x);
257 
258 /* Search for a symbol */
259 JanetSlot janetc_resolve(JanetCompiler *c, const uint8_t *sym);
260 
261 #endif
262