1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-14 20:54:48 +00:00
janet/src/core/compile.c

743 lines
24 KiB
C
Raw Normal View History

/*
* Copyright (c) 2019 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef JANET_AMALG
2018-09-06 02:18:42 +00:00
#include <janet/janet.h>
2017-12-15 00:33:45 +00:00
#include "compile.h"
2018-07-01 15:52:15 +00:00
#include "emit.h"
#include "vector.h"
#include "util.h"
#endif
2018-09-06 02:18:42 +00:00
JanetFopts janetc_fopts_default(JanetCompiler *c) {
JanetFopts ret;
ret.compiler = c;
ret.flags = 0;
2018-09-06 02:18:42 +00:00
ret.hint = janetc_cslot(janet_wrap_nil());
return ret;
}
2018-09-06 02:18:42 +00:00
/* Throw an error with a janet string. */
void janetc_error(JanetCompiler *c, const uint8_t *m) {
/* Don't override first error */
2018-09-06 02:18:42 +00:00
if (c->result.status == JANET_COMPILE_ERROR) {
return;
}
2018-09-06 02:18:42 +00:00
c->result.status = JANET_COMPILE_ERROR;
c->result.error = m;
2017-12-15 00:33:45 +00:00
}
/* Throw an error with a message in a cstring */
2018-09-06 02:18:42 +00:00
void janetc_cerror(JanetCompiler *c, const char *m) {
janetc_error(c, janet_cstring(m));
2017-12-15 00:33:45 +00:00
}
/* Free a slot */
2018-09-06 02:18:42 +00:00
void janetc_freeslot(JanetCompiler *c, JanetSlot s) {
if (s.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF | JANET_SLOT_NAMED)) return;
if (s.envindex >= 0) return;
2018-09-06 02:18:42 +00:00
janetc_regalloc_free(&c->scope->ra, s.index);
}
/* Add a slot to a scope with a symbol associated with it (def or var). */
2018-09-06 02:18:42 +00:00
void janetc_nameslot(JanetCompiler *c, const uint8_t *sym, JanetSlot s) {
SymPair sp;
sp.sym = sym;
sp.slot = s;
2018-01-21 19:39:32 +00:00
sp.keep = 0;
2018-09-06 02:18:42 +00:00
sp.slot.flags |= JANET_SLOT_NAMED;
janet_v_push(c->scope->syms, sp);
2018-07-01 15:52:15 +00:00
}
/* Create a slot with a constant */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_cslot(Janet x) {
JanetSlot ret;
ret.flags = (1 << janet_type(x)) | JANET_SLOT_CONSTANT;
2018-07-01 15:52:15 +00:00
ret.index = -1;
ret.constant = x;
ret.envindex = -1;
return ret;
}
/* Get a local slot */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_farslot(JanetCompiler *c) {
JanetSlot ret;
ret.flags = JANET_SLOTTYPE_ANY;
ret.index = janetc_allocfar(c);
ret.constant = janet_wrap_nil();
2018-07-01 15:52:15 +00:00
ret.envindex = -1;
return ret;
}
/* Enter a new scope */
2018-09-06 02:18:42 +00:00
void janetc_scope(JanetScope *s, JanetCompiler *c, int flags, const char *name) {
JanetScope scope;
2018-07-01 15:52:15 +00:00
scope.name = name;
scope.child = NULL;
scope.consts = NULL;
scope.syms = NULL;
scope.envs = NULL;
scope.defs = NULL;
scope.selfconst = -1;
2018-09-06 02:18:42 +00:00
scope.bytecode_start = janet_v_count(c->buffer);
scope.flags = flags;
scope.parent = c->scope;
/* Inherit slots */
2018-09-06 02:18:42 +00:00
if ((!(flags & JANET_SCOPE_FUNCTION)) && c->scope) {
janetc_regalloc_clone(&scope.ra, &(c->scope->ra));
2018-07-01 15:52:15 +00:00
} else {
janetc_regalloc_init(&scope.ra);
}
2018-07-01 15:52:15 +00:00
/* Link parent and child and update pointer */
if (c->scope)
c->scope->child = s;
c->scope = s;
*s = scope;
2017-12-15 00:33:45 +00:00
}
/* Leave a scope. */
2018-09-06 02:18:42 +00:00
void janetc_popscope(JanetCompiler *c) {
JanetScope *oldscope = c->scope;
JanetScope *newscope = oldscope->parent;
/* Move free slots to parent scope if not a new function.
* We need to know the total number of slots used when compiling the function. */
2018-09-06 02:18:42 +00:00
if (!(oldscope->flags & (JANET_SCOPE_FUNCTION | JANET_SCOPE_UNUSED)) && newscope) {
/* Parent scopes inherit child's closure flag. Needed
* for while loops. (if a while loop creates a closure, it
* is compiled to a tail recursive iife) */
2018-09-06 02:18:42 +00:00
if (oldscope->flags & JANET_SCOPE_CLOSURE) {
newscope->flags |= JANET_SCOPE_CLOSURE;
}
2018-07-01 15:52:15 +00:00
if (newscope->ra.max < oldscope->ra.max)
newscope->ra.max = oldscope->ra.max;
2018-01-21 19:39:32 +00:00
/* Keep upvalue slots */
2018-09-06 02:18:42 +00:00
for (int32_t i = 0; i < janet_v_count(oldscope->syms); i++) {
2018-07-01 15:52:15 +00:00
SymPair pair = oldscope->syms[i];
2018-01-21 19:39:32 +00:00
if (pair.keep) {
/* The variable should not be lexically accessible */
pair.sym = NULL;
2018-09-06 02:18:42 +00:00
janet_v_push(newscope->syms, pair);
janetc_regalloc_touch(&newscope->ra, pair.slot.index);
2018-01-21 19:39:32 +00:00
}
}
}
2018-07-01 15:52:15 +00:00
/* Free the old scope */
2018-09-06 02:18:42 +00:00
janet_v_free(oldscope->consts);
janet_v_free(oldscope->syms);
janet_v_free(oldscope->envs);
janet_v_free(oldscope->defs);
janetc_regalloc_deinit(&oldscope->ra);
2018-07-01 15:52:15 +00:00
/* Update pointer */
if (newscope)
newscope->child = NULL;
c->scope = newscope;
2017-12-15 00:33:45 +00:00
}
2018-01-16 04:31:39 +00:00
/* Leave a scope but keep a slot allocated. */
2018-09-06 02:18:42 +00:00
void janetc_popscope_keepslot(JanetCompiler *c, JanetSlot retslot) {
JanetScope *scope;
janetc_popscope(c);
2018-07-01 15:52:15 +00:00
scope = c->scope;
if (scope && retslot.envindex < 0 && retslot.index >= 0) {
2018-09-06 02:18:42 +00:00
janetc_regalloc_touch(&scope->ra, retslot.index);
2018-01-16 04:31:39 +00:00
}
}
2017-12-15 00:33:45 +00:00
/* Allow searching for symbols. Return information about the symbol */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_resolve(
JanetCompiler *c,
2017-12-15 00:33:45 +00:00
const uint8_t *sym) {
2018-09-06 02:18:42 +00:00
JanetSlot ret = janetc_cslot(janet_wrap_nil());
JanetScope *scope = c->scope;
2018-01-21 19:39:32 +00:00
SymPair *pair;
int foundlocal = 1;
int unused = 0;
2017-12-15 00:33:45 +00:00
/* Search scopes for symbol, starting from top */
2018-07-01 15:52:15 +00:00
while (scope) {
int32_t i, len;
2018-09-06 02:18:42 +00:00
if (scope->flags & JANET_SCOPE_UNUSED)
unused = 1;
2018-09-06 02:18:42 +00:00
len = janet_v_count(scope->syms);
2018-01-29 20:46:26 +00:00
/* Search in reverse order */
for (i = len - 1; i >= 0; i--) {
2018-01-21 19:39:32 +00:00
pair = scope->syms + i;
if (pair->sym == sym) {
ret = pair->slot;
goto found;
}
}
2018-09-06 02:18:42 +00:00
if (scope->flags & JANET_SCOPE_FUNCTION)
foundlocal = 0;
2018-07-01 15:52:15 +00:00
scope = scope->parent;
2017-12-15 00:33:45 +00:00
}
/* Symbol not found - check for global */
{
2018-09-06 02:18:42 +00:00
Janet check;
JanetBindingType btype = janet_resolve(c->env, sym, &check);
switch (btype) {
default:
2018-09-06 02:18:42 +00:00
case JANET_BINDING_NONE:
janetc_error(c, janet_formatc("unknown symbol %q", sym));
return janetc_cslot(janet_wrap_nil());
case JANET_BINDING_DEF:
case JANET_BINDING_MACRO: /* Macro should function like defs when not in calling pos */
return janetc_cslot(check);
case JANET_BINDING_VAR:
{
2018-09-06 02:18:42 +00:00
JanetSlot ret = janetc_cslot(check);
/* TODO save type info */
2018-09-06 02:18:42 +00:00
ret.flags |= JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY;
ret.flags &= ~JANET_SLOT_CONSTANT;
return ret;
}
}
}
2017-12-15 00:33:45 +00:00
/* Symbol was found */
found:
/* Constants can be returned immediately (they are stateless) */
2018-09-06 02:18:42 +00:00
if (ret.flags & (JANET_SLOT_CONSTANT | JANET_SLOT_REF))
return ret;
/* Unused references and locals shouldn't add captured envs. */
if (unused || foundlocal) {
ret.envindex = -1;
2017-12-15 00:33:45 +00:00
return ret;
}
2017-12-15 00:33:45 +00:00
/* non-local scope needs to expose its environment */
2018-01-21 19:39:32 +00:00
pair->keep = 1;
2018-09-06 02:18:42 +00:00
while (scope && !(scope->flags & JANET_SCOPE_FUNCTION))
2018-07-01 15:52:15 +00:00
scope = scope->parent;
2018-09-06 02:18:42 +00:00
janet_assert(scope, "invalid scopes");
scope->flags |= JANET_SCOPE_ENV;
2018-07-01 15:52:15 +00:00
scope = scope->child;
2017-12-15 00:33:45 +00:00
/* Propagate env up to current scope */
int32_t envindex = -1;
2018-07-01 15:52:15 +00:00
while (scope) {
2018-09-06 02:18:42 +00:00
if (scope->flags & JANET_SCOPE_FUNCTION) {
int32_t j, len;
int scopefound = 0;
/* Check if scope already has env. If so, break */
2018-09-06 02:18:42 +00:00
len = janet_v_count(scope->envs);
for (j = 0; j < len; j++) {
if (scope->envs[j] == envindex) {
scopefound = 1;
envindex = j;
break;
}
2017-12-15 00:33:45 +00:00
}
/* Add the environment if it is not already referenced */
if (!scopefound) {
2018-09-06 02:18:42 +00:00
len = janet_v_count(scope->envs);
janet_v_push(scope->envs, envindex);
envindex = len;
}
2017-12-15 00:33:45 +00:00
}
2018-07-01 15:52:15 +00:00
scope = scope->child;
2017-12-15 00:33:45 +00:00
}
ret.envindex = envindex;
2017-12-15 00:33:45 +00:00
return ret;
}
/* Generate the return instruction for a slot. */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_return(JanetCompiler *c, JanetSlot s) {
if (!(s.flags & JANET_SLOT_RETURNED)) {
if (s.flags & JANET_SLOT_CONSTANT && janet_checktype(s.constant, JANET_NIL))
janetc_emit(c, JOP_RETURN_NIL);
2018-07-01 15:52:15 +00:00
else
2018-09-06 02:18:42 +00:00
janetc_emit_s(c, JOP_RETURN, s, 0);
s.flags |= JANET_SLOT_RETURNED;
}
return s;
}
/* Get a target slot for emitting an instruction. */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_gettarget(JanetFopts opts) {
JanetSlot slot;
if ((opts.flags & JANET_FOPTS_HINT) &&
(opts.hint.envindex < 0) &&
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
slot = opts.hint;
} else {
slot.envindex = -1;
2018-09-06 02:18:42 +00:00
slot.constant = janet_wrap_nil();
slot.flags = 0;
2018-09-06 02:18:42 +00:00
slot.index = janetc_allocfar(opts.compiler);
}
return slot;
}
/* Get a bunch of slots for function arguments */
2018-09-06 02:18:42 +00:00
JanetSlot *janetc_toslots(JanetCompiler *c, const Janet *vals, int32_t len) {
int32_t i;
2018-09-06 02:18:42 +00:00
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
for (i = 0; i < len; i++) {
2018-09-06 02:18:42 +00:00
janet_v_push(ret, janetc_value(subopts, vals[i]));
}
return ret;
}
/* Get a bunch of slots for function arguments */
2018-09-06 02:18:42 +00:00
JanetSlot *janetc_toslotskv(JanetCompiler *c, Janet ds) {
JanetSlot *ret = NULL;
JanetFopts subopts = janetc_fopts_default(c);
const JanetKV *kvs = NULL;
2018-07-04 17:15:52 +00:00
int32_t cap, i, len;
2018-09-06 02:18:42 +00:00
janet_dictionary_view(ds, &kvs, &len, &cap);
2018-07-04 17:15:52 +00:00
for (i = 0; i < cap; i++) {
2018-09-06 02:18:42 +00:00
if (janet_checktype(kvs[i].key, JANET_NIL)) continue;
janet_v_push(ret, janetc_value(subopts, kvs[i].key));
janet_v_push(ret, janetc_value(subopts, kvs[i].value));
}
return ret;
}
2018-09-06 02:18:42 +00:00
/* Push slots load via janetc_toslots. */
void janetc_pushslots(JanetCompiler *c, JanetSlot *slots) {
int32_t i;
int32_t count = janet_v_count(slots);
for (i = 0; i < count;) {
if (slots[i].flags & JANET_SLOT_SPLICED) {
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i], 0);
i++;
} else if (i + 1 == count) {
janetc_emit_s(c, JOP_PUSH, slots[i], 0);
i++;
} else if (slots[i + 1].flags & JANET_SLOT_SPLICED) {
janetc_emit_s(c, JOP_PUSH, slots[i], 0);
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i+1], 0);
i += 2;
} else if (i + 2 == count) {
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i+1], 0);
i += 2;
} else if (slots[i + 2].flags & JANET_SLOT_SPLICED) {
janetc_emit_ss(c, JOP_PUSH_2, slots[i], slots[i+1], 0);
janetc_emit_s(c, JOP_PUSH_ARRAY, slots[i+2], 0);
i += 3;
} else {
janetc_emit_sss(c, JOP_PUSH_3, slots[i], slots[i+1], slots[i+2], 0);
i += 3;
}
}
}
/* Check if a list of slots has any spliced slots */
static int has_spliced(JanetSlot *slots) {
int32_t i;
for (i = 0; i < janet_v_count(slots); i++) {
if (slots[i].flags & JANET_SLOT_SPLICED)
return 1;
}
return 0;
}
2018-09-06 02:18:42 +00:00
/* Free slots loaded via janetc_toslots */
void janetc_freeslots(JanetCompiler *c, JanetSlot *slots) {
int32_t i;
2018-09-06 02:18:42 +00:00
for (i = 0; i < janet_v_count(slots); i++) {
janetc_freeslot(c, slots[i]);
}
2018-09-06 02:18:42 +00:00
janet_v_free(slots);
}
/* Compile some code that will be thrown away. Used to ensure
* that dead code is well formed without including it in the final
* bytecode. */
2018-09-06 02:18:42 +00:00
void janetc_throwaway(JanetFopts opts, Janet x) {
JanetCompiler *c = opts.compiler;
JanetScope unusedScope;
int32_t bufstart = janet_v_count(c->buffer);
int32_t mapbufstart = janet_v_count(c->mapbuffer);
janetc_scope(&unusedScope, c, JANET_SCOPE_UNUSED, "unusued");
janetc_value(opts, x);
janetc_popscope(c);
2018-07-01 15:52:15 +00:00
if (c->buffer) {
2018-09-06 02:18:42 +00:00
janet_v__cnt(c->buffer) = bufstart;
2018-07-01 15:52:15 +00:00
if (c->mapbuffer)
2018-09-06 02:18:42 +00:00
janet_v__cnt(c->mapbuffer) = mapbufstart;
}
}
/* Compile a call or tailcall instruction */
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_call(JanetFopts opts, JanetSlot *slots, JanetSlot fun) {
JanetSlot retslot;
JanetCompiler *c = opts.compiler;
int specialized = 0;
if (fun.flags & JANET_SLOT_CONSTANT && !has_spliced(slots)) {
2018-09-06 02:18:42 +00:00
if (janet_checktype(fun.constant, JANET_FUNCTION)) {
JanetFunction *f = janet_unwrap_function(fun.constant);
const JanetFunOptimizer *o = janetc_funopt(f->def->flags);
2018-07-01 23:35:45 +00:00
if (o && (!o->can_optimize || o->can_optimize(opts, slots))) {
specialized = 1;
2018-06-29 03:36:31 +00:00
retslot = o->optimize(opts, slots);
}
}
2018-09-06 02:18:42 +00:00
/* TODO janet function inlining (no c functions)*/
}
if (!specialized) {
2018-09-06 02:18:42 +00:00
janetc_pushslots(c, slots);
if ((opts.flags & JANET_FOPTS_TAIL) &&
/* Prevent top level tail calls for better errors */
!(c->scope->flags & JANET_SCOPE_TOP)) {
2018-09-06 02:18:42 +00:00
janetc_emit_s(c, JOP_TAILCALL, fun, 0);
retslot = janetc_cslot(janet_wrap_nil());
retslot.flags = JANET_SLOT_RETURNED;
} else {
2018-09-06 02:18:42 +00:00
retslot = janetc_gettarget(opts);
janetc_emit_ss(c, JOP_CALL, retslot, fun, 1);
}
}
2018-09-06 02:18:42 +00:00
janetc_freeslots(c, slots);
return retslot;
}
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_maker(JanetFopts opts, JanetSlot *slots, int op) {
JanetCompiler *c = opts.compiler;
JanetSlot retslot;
janetc_pushslots(c, slots);
janetc_freeslots(c, slots);
retslot = janetc_gettarget(opts);
janetc_emit_s(c, op, retslot, 1);
return retslot;
}
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_array(JanetFopts opts, Janet x) {
JanetCompiler *c = opts.compiler;
JanetArray *a = janet_unwrap_array(x);
return janetc_maker(opts,
janetc_toslots(c, a->data, a->count),
JOP_MAKE_ARRAY);
}
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_tablector(JanetFopts opts, Janet x, int op) {
JanetCompiler *c = opts.compiler;
return janetc_maker(opts,
2018-09-06 02:18:42 +00:00
janetc_toslotskv(c, x),
op);
}
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_bufferctor(JanetFopts opts, Janet x) {
JanetCompiler *c = opts.compiler;
JanetBuffer *b = janet_unwrap_buffer(x);
Janet onearg = janet_stringv(b->data, b->count);
return janetc_maker(opts,
janetc_toslots(c, &onearg, 1),
JOP_MAKE_BUFFER);
2018-02-03 23:12:07 +00:00
}
/* Expand a macro one time. Also get the special form compiler if we
* find that instead. */
static int macroexpand1(
JanetCompiler *c,
Janet x,
Janet *out,
2018-09-06 02:18:42 +00:00
const JanetSpecial **spec) {
if (!janet_checktype(x, JANET_TUPLE))
return 0;
2018-09-06 02:18:42 +00:00
const Janet *form = janet_unwrap_tuple(x);
if (janet_tuple_length(form) == 0)
return 0;
/* Source map - only set when we get a tuple */
if (janet_tuple_sm_start(form) >= 0) {
c->current_mapping.start = janet_tuple_sm_start(form);
c->current_mapping.end = janet_tuple_sm_end(form);
}
2018-09-06 02:18:42 +00:00
if (!janet_checktype(form[0], JANET_SYMBOL))
return 0;
2018-09-06 02:18:42 +00:00
const uint8_t *name = janet_unwrap_symbol(form[0]);
const JanetSpecial *s = janetc_special(name);
if (s) {
*spec = s;
return 0;
}
2018-09-06 02:18:42 +00:00
Janet macroval;
JanetBindingType btype = janet_resolve(c->env, name, &macroval);
if (btype != JANET_BINDING_MACRO ||
!janet_checktype(macroval, JANET_FUNCTION))
return 0;
/* Evaluate macro */
2018-09-06 02:18:42 +00:00
JanetFiber *fiberp;
JanetFunction *macro = janet_unwrap_function(macroval);
int lock = janet_gclock();
JanetSignal status = janet_pcall(
macro,
2018-09-06 02:18:42 +00:00
janet_tuple_length(form) - 1,
form + 1,
&x,
&fiberp);
2018-09-06 02:18:42 +00:00
janet_gcunlock(lock);
if (status != JANET_SIGNAL_OK) {
const uint8_t *es = janet_formatc("(macro) %V", x);
c->result.macrofiber = fiberp;
2018-09-06 02:18:42 +00:00
janetc_error(c, es);
} else {
*out = x;
}
return 1;
}
/* Compile a single value */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_value(JanetFopts opts, Janet x) {
JanetSlot ret;
JanetCompiler *c = opts.compiler;
JanetSourceMapping last_mapping = c->current_mapping;
c->recursion_guard--;
/* Guard against previous errors and unbounded recursion */
2018-09-06 02:18:42 +00:00
if (c->result.status == JANET_COMPILE_ERROR) return janetc_cslot(janet_wrap_nil());
if (c->recursion_guard <= 0) {
2018-09-06 02:18:42 +00:00
janetc_cerror(c, "recursed too deeply");
return janetc_cslot(janet_wrap_nil());
}
/* Macro expand. Also gets possible special form and
* refines source mapping cursor if possible. */
2018-09-06 02:18:42 +00:00
const JanetSpecial *spec = NULL;
int macroi = JANET_MAX_MACRO_EXPAND;
2018-07-04 17:15:52 +00:00
while (macroi &&
2018-09-06 02:18:42 +00:00
c->result.status != JANET_COMPILE_ERROR &&
2018-07-04 17:15:52 +00:00
macroexpand1(c, x, &x, &spec))
macroi--;
if (macroi == 0) {
2018-09-06 02:18:42 +00:00
janetc_cerror(c, "recursed too deeply in macro expansion");
return janetc_cslot(janet_wrap_nil());
}
/* Special forms */
if (spec) {
2018-09-06 02:18:42 +00:00
const Janet *tup = janet_unwrap_tuple(x);
ret = spec->compile(opts, janet_tuple_length(tup) - 1, tup + 1);
} else {
2018-09-06 02:18:42 +00:00
switch (janet_type(x)) {
case JANET_TUPLE:
{
2018-09-06 02:18:42 +00:00
JanetFopts subopts = janetc_fopts_default(c);
const Janet *tup = janet_unwrap_tuple(x);
/* Empty tuple is tuple literal */
2018-09-06 02:18:42 +00:00
if (janet_tuple_length(tup) == 0) {
ret = janetc_cslot(x);
} else {
2018-09-06 02:18:42 +00:00
JanetSlot head = janetc_value(subopts, tup[0]);
subopts.flags = JANET_FUNCTION | JANET_CFUNCTION;
ret = janetc_call(opts, janetc_toslots(c, tup + 1, janet_tuple_length(tup) - 1), head);
janetc_freeslot(c, head);
2018-01-28 20:29:47 +00:00
}
ret.flags &= ~JANET_SLOT_SPLICED;
2018-01-28 20:29:47 +00:00
}
break;
2018-09-06 02:18:42 +00:00
case JANET_SYMBOL:
ret = janetc_resolve(c, janet_unwrap_symbol(x));
break;
2018-09-06 02:18:42 +00:00
case JANET_ARRAY:
ret = janetc_array(opts, x);
break;
2018-09-06 02:18:42 +00:00
case JANET_STRUCT:
ret = janetc_tablector(opts, x, JOP_MAKE_STRUCT);
break;
2018-09-06 02:18:42 +00:00
case JANET_TABLE:
ret = janetc_tablector(opts, x, JOP_MAKE_TABLE);
break;
2018-09-06 02:18:42 +00:00
case JANET_BUFFER:
ret = janetc_bufferctor(opts, x);
break;
default:
2018-09-06 02:18:42 +00:00
ret = janetc_cslot(x);
break;
}
}
2018-09-06 02:18:42 +00:00
if (c->result.status == JANET_COMPILE_ERROR)
return janetc_cslot(janet_wrap_nil());
if (opts.flags & JANET_FOPTS_TAIL)
ret = janetc_return(c, ret);
2018-09-06 02:18:42 +00:00
if (opts.flags & JANET_FOPTS_HINT) {
janetc_copy(c, opts.hint, ret);
2018-01-16 04:31:39 +00:00
ret = opts.hint;
}
c->current_mapping = last_mapping;
c->recursion_guard++;
return ret;
}
/* Compile a funcdef */
2018-09-06 02:18:42 +00:00
JanetFuncDef *janetc_pop_funcdef(JanetCompiler *c) {
JanetScope *scope = c->scope;
JanetFuncDef *def = janet_funcdef_alloc();
2018-07-01 15:52:15 +00:00
def->slotcount = scope->ra.max + 1;
2018-09-06 02:18:42 +00:00
janet_assert(scope->flags & JANET_SCOPE_FUNCTION, "expected function scope");
2018-01-21 19:39:32 +00:00
/* Copy envs */
2018-09-06 02:18:42 +00:00
def->environments_length = janet_v_count(scope->envs);
def->environments = janet_v_flatten(scope->envs);
2018-09-06 02:18:42 +00:00
def->constants_length = janet_v_count(scope->consts);
def->constants = janet_v_flatten(scope->consts);
2018-09-06 02:18:42 +00:00
def->defs_length = janet_v_count(scope->defs);
def->defs = janet_v_flatten(scope->defs);
2018-06-29 03:36:31 +00:00
/* Copy bytecode (only last chunk) */
2018-09-06 02:18:42 +00:00
def->bytecode_length = janet_v_count(c->buffer) - scope->bytecode_start;
if (def->bytecode_length) {
size_t s = sizeof(int32_t) * def->bytecode_length;
def->bytecode = malloc(s);
if (NULL == def->bytecode) {
2018-09-06 02:18:42 +00:00
JANET_OUT_OF_MEMORY;
}
2018-07-01 15:52:15 +00:00
memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
2018-09-06 02:18:42 +00:00
janet_v__cnt(c->buffer) = scope->bytecode_start;
if (NULL != c->mapbuffer) {
2018-09-06 02:18:42 +00:00
size_t s = sizeof(JanetSourceMapping) * def->bytecode_length;
def->sourcemap = malloc(s);
if (NULL == def->sourcemap) {
2018-09-06 02:18:42 +00:00
JANET_OUT_OF_MEMORY;
}
2018-07-01 15:52:15 +00:00
memcpy(def->sourcemap, c->mapbuffer + scope->bytecode_start, s);
2018-09-06 02:18:42 +00:00
janet_v__cnt(c->mapbuffer) = scope->bytecode_start;
}
}
2018-06-29 03:36:31 +00:00
/* Get source from parser */
def->source = c->source;
2018-06-29 03:36:31 +00:00
def->arity = 0;
def->flags = 0;
2018-09-06 02:18:42 +00:00
if (scope->flags & JANET_SCOPE_ENV) {
def->flags |= JANET_FUNCDEF_FLAG_NEEDSENV;
}
/* Pop the scope */
2018-09-06 02:18:42 +00:00
janetc_popscope(c);
return def;
}
/* Initialize a compiler */
2018-09-06 02:18:42 +00:00
static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where) {
2018-07-01 15:52:15 +00:00
c->scope = NULL;
c->buffer = NULL;
c->mapbuffer = NULL;
2018-09-06 02:18:42 +00:00
c->recursion_guard = JANET_RECURSION_GUARD;
c->env = env;
c->source = where;
c->current_mapping.start = -1;
c->current_mapping.end = -1;
/* Init result */
c->result.error = NULL;
2018-09-06 02:18:42 +00:00
c->result.status = JANET_COMPILE_OK;
2018-06-29 05:15:47 +00:00
c->result.funcdef = NULL;
c->result.macrofiber = NULL;
c->result.error_mapping.start = -1;
c->result.error_mapping.end = -1;
}
/* Deinitialize a compiler struct */
2018-09-06 02:18:42 +00:00
static void janetc_deinit(JanetCompiler *c) {
janet_v_free(c->buffer);
janet_v_free(c->mapbuffer);
2018-01-18 22:25:45 +00:00
c->env = NULL;
}
/* Compile a form. */
2018-09-06 02:18:42 +00:00
JanetCompileResult janet_compile(Janet source, JanetTable *env, const uint8_t *where) {
JanetCompiler c;
JanetScope rootscope;
JanetFopts fopts;
2018-09-06 02:18:42 +00:00
janetc_init(&c, env, where);
/* Push a function scope */
2018-09-06 02:18:42 +00:00
janetc_scope(&rootscope, &c, JANET_SCOPE_FUNCTION | JANET_SCOPE_TOP, "root");
/* Set initial form options */
fopts.compiler = &c;
2018-09-06 02:18:42 +00:00
fopts.flags = JANET_FOPTS_TAIL | JANET_SLOTTYPE_ANY;
fopts.hint = janetc_cslot(janet_wrap_nil());
/* Compile the value */
2018-09-06 02:18:42 +00:00
janetc_value(fopts, source);
2018-09-06 02:18:42 +00:00
if (c.result.status == JANET_COMPILE_OK) {
JanetFuncDef *def = janetc_pop_funcdef(&c);
def->name = janet_cstring("_thunk");
2018-01-20 22:19:47 +00:00
c.result.funcdef = def;
2018-06-29 05:15:47 +00:00
} else {
c.result.error_mapping = c.current_mapping;
2018-09-06 02:18:42 +00:00
janetc_popscope(&c);
}
2018-09-06 02:18:42 +00:00
janetc_deinit(&c);
return c.result;
}
2018-01-16 04:31:39 +00:00
/* C Function for compiling */
static Janet cfun(int32_t argc, Janet *argv) {
janet_arity(argc, 2, 3);
JanetTable *env = janet_gettable(argv, 1);
const uint8_t *source = NULL;
if (argc == 3) {
source = janet_getstring(argv, 2);
2018-06-29 03:36:31 +00:00
}
JanetCompileResult res = janet_compile(argv[0], env, source);
2018-09-06 02:18:42 +00:00
if (res.status == JANET_COMPILE_OK) {
return janet_wrap_function(janet_thunk(res.funcdef));
2018-01-16 04:31:39 +00:00
} else {
JanetTable *t = janet_table(4);
janet_table_put(t, janet_ckeywordv("error"), janet_wrap_string(res.error));
janet_table_put(t, janet_ckeywordv("start"), janet_wrap_integer(res.error_mapping.start));
janet_table_put(t, janet_ckeywordv("end"), janet_wrap_integer(res.error_mapping.end));
if (res.macrofiber) {
janet_table_put(t, janet_ckeywordv("fiber"), janet_wrap_fiber(res.macrofiber));
}
return janet_wrap_table(t);
2018-01-16 04:31:39 +00:00
}
}
static const JanetReg compile_cfuns[] = {
{"compile", cfun,
JDOC("(compile ast env [, source])\n\n"
"Compiles an Abstract Syntax Tree (ast) into a janet function. "
"Pair the compile function with parsing functionality to implement "
"eval. Returns a janet function and does not modify ast. Throws an "
"error if the ast cannot be compiled.")
},
{NULL, NULL, NULL}
2018-07-01 16:44:41 +00:00
};
void janet_lib_compile(JanetTable *env) {
janet_core_cfuns(env, NULL, compile_cfuns);
}