2017-12-03 17:52:09 +00:00
|
|
|
/*
|
2018-05-18 03:41:20 +00:00
|
|
|
* Copyright (c) 2018 Calvin Rose
|
2017-12-03 17:52:09 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <dst/dst.h>
|
2018-01-30 04:38:49 +00:00
|
|
|
#include <dst/dstcorelib.h>
|
2017-12-15 00:33:45 +00:00
|
|
|
#include "compile.h"
|
2018-07-01 15:52:15 +00:00
|
|
|
#include "emit.h"
|
2018-01-19 21:43:19 +00:00
|
|
|
|
|
|
|
#define DST_V_DEF_FLATTENMEM
|
|
|
|
#include <headerlibs/vector.h>
|
|
|
|
#undef DST_V_DEF_FLATTENMEM
|
2017-12-03 17:52:09 +00:00
|
|
|
|
2018-01-17 04:18:45 +00:00
|
|
|
DstFopts dstc_fopts_default(DstCompiler *c) {
|
|
|
|
DstFopts ret;
|
|
|
|
ret.compiler = c;
|
|
|
|
ret.flags = 0;
|
|
|
|
ret.hint = dstc_cslot(dst_wrap_nil());
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Throw an error with a dst string. */
|
2018-06-29 03:36:31 +00:00
|
|
|
void dstc_error(DstCompiler *c, const uint8_t *m) {
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Don't override first error */
|
|
|
|
if (c->result.status == DST_COMPILE_ERROR) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
c->result.status = DST_COMPILE_ERROR;
|
2017-12-30 21:46:59 +00:00
|
|
|
c->result.error = m;
|
2017-12-15 00:33:45 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 06:17:53 +00:00
|
|
|
/* Throw an error with a message in a cstring */
|
2018-06-29 03:36:31 +00:00
|
|
|
void dstc_cerror(DstCompiler *c, const char *m) {
|
|
|
|
dstc_error(c, dst_cstring(m));
|
2017-12-15 00:33:45 +00:00
|
|
|
}
|
2017-12-21 04:03:34 +00:00
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Check error */
|
2018-01-12 15:41:27 +00:00
|
|
|
int dstc_iserr(DstFopts *opts) {
|
2018-01-05 21:17:55 +00:00
|
|
|
return (opts->compiler->result.status == DST_COMPILE_ERROR);
|
|
|
|
}
|
|
|
|
|
2018-06-17 17:55:02 +00:00
|
|
|
/* Get the next key in an associative data structure. Used for iterating through an
|
|
|
|
* associative data structure. */
|
|
|
|
const DstKV *dstc_next(Dst ds, const DstKV *kv) {
|
|
|
|
switch(dst_type(ds)) {
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
case DST_TABLE:
|
|
|
|
return (const DstKV *) dst_table_next(dst_unwrap_table(ds), kv);
|
|
|
|
case DST_STRUCT:
|
|
|
|
return dst_struct_next(dst_unwrap_struct(ds), kv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 04:03:34 +00:00
|
|
|
/* Free a slot */
|
2018-01-05 21:17:55 +00:00
|
|
|
void dstc_freeslot(DstCompiler *c, DstSlot s) {
|
2018-01-16 04:31:39 +00:00
|
|
|
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF | DST_SLOT_NAMED)) return;
|
2018-02-12 21:43:59 +00:00
|
|
|
if (s.envindex >= 0) return;
|
2018-07-01 15:52:15 +00:00
|
|
|
dstc_regalloc_free(&c->scope->ra, s.index);
|
2017-12-21 04:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add a slot to a scope with a symbol associated with it (def or var). */
|
2018-01-12 15:41:27 +00:00
|
|
|
void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s) {
|
2018-01-05 21:17:55 +00:00
|
|
|
SymPair sp;
|
|
|
|
sp.sym = sym;
|
|
|
|
sp.slot = s;
|
2018-01-21 19:39:32 +00:00
|
|
|
sp.keep = 0;
|
2018-01-05 21:17:55 +00:00
|
|
|
sp.slot.flags |= DST_SLOT_NAMED;
|
2018-07-01 15:52:15 +00:00
|
|
|
dst_v_push(c->scope->syms, sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a slot with a constant */
|
|
|
|
DstSlot dstc_cslot(Dst x) {
|
|
|
|
DstSlot ret;
|
|
|
|
ret.flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT;
|
|
|
|
ret.index = -1;
|
|
|
|
ret.constant = x;
|
|
|
|
ret.envindex = -1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get a temp near slot */
|
|
|
|
DstSlot dstc_nearslot(DstCompiler *c, DstcRegisterTemp tag) {
|
|
|
|
DstSlot ret;
|
|
|
|
ret.flags = DST_SLOTTYPE_ANY;
|
2018-07-01 19:49:33 +00:00
|
|
|
ret.index = dstc_allocnear(c, tag);
|
2018-07-01 15:52:15 +00:00
|
|
|
ret.constant = dst_wrap_nil();
|
|
|
|
ret.envindex = -1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get a temp near slot */
|
|
|
|
DstSlot dstc_farslot(DstCompiler *c) {
|
|
|
|
DstSlot ret;
|
|
|
|
ret.flags = DST_SLOTTYPE_ANY;
|
2018-07-01 19:49:33 +00:00
|
|
|
ret.index = dstc_allocfar(c);
|
2018-07-01 15:52:15 +00:00
|
|
|
ret.constant = dst_wrap_nil();
|
|
|
|
ret.envindex = -1;
|
|
|
|
return ret;
|
2017-12-21 04:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Enter a new scope */
|
2018-07-01 15:52:15 +00:00
|
|
|
void dstc_scope(DstScope *s, DstCompiler *c, int flags, const char *name) {
|
2018-01-05 21:17:55 +00:00
|
|
|
DstScope scope;
|
2018-07-01 15:52:15 +00:00
|
|
|
scope.name = name;
|
|
|
|
scope.child = NULL;
|
2018-01-05 21:17:55 +00:00
|
|
|
scope.consts = NULL;
|
|
|
|
scope.syms = NULL;
|
|
|
|
scope.envs = NULL;
|
|
|
|
scope.defs = NULL;
|
2018-01-19 17:37:37 +00:00
|
|
|
scope.selfconst = -1;
|
2018-01-05 21:17:55 +00:00
|
|
|
scope.bytecode_start = dst_v_count(c->buffer);
|
|
|
|
scope.flags = flags;
|
2018-07-01 15:52:15 +00:00
|
|
|
*s = scope;
|
2018-01-04 02:36:10 +00:00
|
|
|
/* Inherit slots */
|
2018-07-01 15:52:15 +00:00
|
|
|
if ((!(flags & DST_SCOPE_FUNCTION)) && c->scope) {
|
|
|
|
dstc_regalloc_clone(&s->ra, &(c->scope->ra));
|
|
|
|
} else {
|
|
|
|
dstc_regalloc_init(&s->ra);
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
2018-07-01 15:52:15 +00:00
|
|
|
/* Link parent and child and update pointer */
|
|
|
|
s->parent = c->scope;
|
|
|
|
if (c->scope)
|
|
|
|
c->scope->child = s;
|
|
|
|
c->scope = s;
|
2017-12-15 00:33:45 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 06:17:53 +00:00
|
|
|
/* Leave a scope. */
|
2018-01-05 21:17:55 +00:00
|
|
|
void dstc_popscope(DstCompiler *c) {
|
2018-07-01 15:52:15 +00:00
|
|
|
DstScope *oldscope = c->scope;
|
|
|
|
DstScope *newscope = oldscope->parent;
|
2018-01-06 16:09:15 +00:00
|
|
|
/* 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-07-01 15:52:15 +00:00
|
|
|
if (!(oldscope->flags & (DST_SCOPE_FUNCTION | DST_SCOPE_UNUSED)) && newscope) {
|
|
|
|
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-07-01 15:52:15 +00:00
|
|
|
for (int32_t i = 0; i < dst_v_count(oldscope->syms); i++) {
|
|
|
|
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;
|
|
|
|
dst_v_push(newscope->syms, pair);
|
2018-07-01 15:52:15 +00:00
|
|
|
dstc_regalloc_touch(&newscope->ra, pair.slot.index);
|
2018-01-21 19:39:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-06 16:09:15 +00:00
|
|
|
}
|
2018-07-01 15:52:15 +00:00
|
|
|
/* Free the old scope */
|
|
|
|
dst_v_free(oldscope->consts);
|
|
|
|
dst_v_free(oldscope->syms);
|
|
|
|
dst_v_free(oldscope->envs);
|
|
|
|
dst_v_free(oldscope->defs);
|
|
|
|
dstc_regalloc_deinit(&oldscope->ra);
|
|
|
|
/* 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. */
|
|
|
|
void dstc_popscope_keepslot(DstCompiler *c, DstSlot retslot) {
|
2018-07-01 15:52:15 +00:00
|
|
|
DstScope *scope;
|
2018-01-16 04:31:39 +00:00
|
|
|
dstc_popscope(c);
|
2018-07-01 15:52:15 +00:00
|
|
|
scope = c->scope;
|
|
|
|
if (scope && retslot.envindex < 0 && retslot.index >= 0) {
|
|
|
|
dstc_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-01-05 21:17:55 +00:00
|
|
|
DstSlot dstc_resolve(
|
2017-12-15 00:33:45 +00:00
|
|
|
DstCompiler *c,
|
|
|
|
const uint8_t *sym) {
|
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
DstSlot ret = dstc_cslot(dst_wrap_nil());
|
2018-07-01 15:52:15 +00:00
|
|
|
DstScope *scope = c->scope;
|
2018-01-21 19:39:32 +00:00
|
|
|
SymPair *pair;
|
2017-12-16 06:17:53 +00:00
|
|
|
int foundlocal = 1;
|
2018-01-04 02:36:10 +00:00
|
|
|
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) {
|
2018-01-05 21:17:55 +00:00
|
|
|
int32_t i, len;
|
2018-01-04 02:36:10 +00:00
|
|
|
if (scope->flags & DST_SCOPE_UNUSED)
|
|
|
|
unused = 1;
|
2018-01-05 21:17:55 +00:00
|
|
|
len = dst_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;
|
2018-01-05 21:17:55 +00:00
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
2017-12-16 06:17:53 +00:00
|
|
|
if (scope->flags & DST_SCOPE_FUNCTION)
|
|
|
|
foundlocal = 0;
|
2018-07-01 15:52:15 +00:00
|
|
|
scope = scope->parent;
|
2017-12-15 00:33:45 +00:00
|
|
|
}
|
|
|
|
|
2017-12-21 04:03:34 +00:00
|
|
|
/* Symbol not found - check for global */
|
2018-01-05 21:17:55 +00:00
|
|
|
{
|
2018-06-17 17:55:02 +00:00
|
|
|
Dst check;
|
|
|
|
DstBindingType btype = dst_env_resolve(c->env, sym, &check);
|
|
|
|
switch (btype) {
|
|
|
|
default:
|
|
|
|
case DST_BINDING_NONE:
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_error(c, dst_formatc("unknown symbol %q", sym));
|
2018-06-17 17:55:02 +00:00
|
|
|
return dstc_cslot(dst_wrap_nil());
|
|
|
|
case DST_BINDING_DEF:
|
|
|
|
case DST_BINDING_MACRO: /* Macro should function like defs when not in calling pos */
|
|
|
|
return dstc_cslot(check);
|
|
|
|
case DST_BINDING_VAR:
|
|
|
|
{
|
|
|
|
DstSlot ret = dstc_cslot(check);
|
|
|
|
/* TODO save type info */
|
|
|
|
ret.flags |= DST_SLOT_REF | DST_SLOT_NAMED | DST_SLOT_MUTABLE | DST_SLOTTYPE_ANY;
|
|
|
|
ret.flags &= ~DST_SLOT_CONSTANT;
|
|
|
|
return ret;
|
|
|
|
}
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
|
|
|
}
|
2017-12-15 00:33:45 +00:00
|
|
|
|
|
|
|
/* Symbol was found */
|
|
|
|
found:
|
|
|
|
|
2017-12-16 06:17:53 +00:00
|
|
|
/* Constants can be returned immediately (they are stateless) */
|
2018-01-04 02:36:10 +00:00
|
|
|
if (ret.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Unused references and locals shouldn't add captured envs. */
|
|
|
|
if (unused || foundlocal) {
|
2018-02-12 21:43:59 +00:00
|
|
|
ret.envindex = -1;
|
2017-12-15 00:33:45 +00:00
|
|
|
return ret;
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
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-07-01 15:52:15 +00:00
|
|
|
while (scope && !(scope->flags & DST_SCOPE_FUNCTION))
|
|
|
|
scope = scope->parent;
|
|
|
|
dst_assert(scope, "invalid scopes");
|
2018-01-21 19:39:32 +00:00
|
|
|
scope->flags |= DST_SCOPE_ENV;
|
2018-07-01 15:52:15 +00:00
|
|
|
scope = scope->child;
|
2017-12-15 00:33:45 +00:00
|
|
|
|
|
|
|
/* Propogate env up to current scope */
|
2018-02-12 21:43:59 +00:00
|
|
|
int32_t envindex = -1;
|
2018-07-01 15:52:15 +00:00
|
|
|
while (scope) {
|
2017-12-16 06:17:53 +00:00
|
|
|
if (scope->flags & DST_SCOPE_FUNCTION) {
|
2018-01-05 21:17:55 +00:00
|
|
|
int32_t j, len;
|
2017-12-16 06:17:53 +00:00
|
|
|
int scopefound = 0;
|
|
|
|
/* Check if scope already has env. If so, break */
|
2018-01-05 21:17:55 +00:00
|
|
|
len = dst_v_count(scope->envs);
|
2018-02-12 21:43:59 +00:00
|
|
|
for (j = 0; j < len; j++) {
|
2017-12-21 04:03:34 +00:00
|
|
|
if (scope->envs[j] == envindex) {
|
2017-12-16 06:17:53 +00:00
|
|
|
scopefound = 1;
|
2017-12-21 04:03:34 +00:00
|
|
|
envindex = j;
|
2017-12-16 06:17:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-12-15 00:33:45 +00:00
|
|
|
}
|
2017-12-21 04:03:34 +00:00
|
|
|
/* Add the environment if it is not already referenced */
|
2018-01-05 21:17:55 +00:00
|
|
|
if (!scopefound) {
|
2018-01-13 19:08:42 +00:00
|
|
|
len = dst_v_count(scope->envs);
|
2018-01-05 21:17:55 +00:00
|
|
|
dst_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
|
|
|
}
|
2018-05-20 01:16:00 +00:00
|
|
|
|
2017-12-21 04:03:34 +00:00
|
|
|
ret.envindex = envindex;
|
2017-12-15 00:33:45 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-12-17 04:11:51 +00:00
|
|
|
/* Generate the return instruction for a slot. */
|
2018-06-29 03:36:31 +00:00
|
|
|
DstSlot dstc_return(DstCompiler *c, DstSlot s) {
|
2018-01-04 02:36:10 +00:00
|
|
|
if (!(s.flags & DST_SLOT_RETURNED)) {
|
2018-07-01 15:52:15 +00:00
|
|
|
if (s.flags & DST_SLOT_CONSTANT && dst_checktype(s.constant, DST_NIL))
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_emit(c, DOP_RETURN_NIL);
|
2018-07-01 15:52:15 +00:00
|
|
|
else
|
|
|
|
dstc_emit_s(c, DOP_RETURN, s);
|
2018-01-04 02:36:10 +00:00
|
|
|
s.flags |= DST_SLOT_RETURNED;
|
2017-12-17 04:11:51 +00:00
|
|
|
}
|
2018-01-04 02:36:10 +00:00
|
|
|
return s;
|
2017-12-17 04:11:51 +00:00
|
|
|
}
|
|
|
|
|
2018-01-04 02:36:10 +00:00
|
|
|
/* Get a target slot for emitting an instruction. Will always return
|
|
|
|
* a local slot. */
|
2018-01-12 15:41:27 +00:00
|
|
|
DstSlot dstc_gettarget(DstFopts opts) {
|
2018-01-04 02:36:10 +00:00
|
|
|
DstSlot slot;
|
|
|
|
if ((opts.flags & DST_FOPTS_HINT) &&
|
2018-02-12 21:43:59 +00:00
|
|
|
(opts.hint.envindex < 0) &&
|
2018-01-04 02:36:10 +00:00
|
|
|
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
|
|
|
|
slot = opts.hint;
|
|
|
|
} else {
|
2018-02-12 21:43:59 +00:00
|
|
|
slot.envindex = -1;
|
2018-01-04 02:36:10 +00:00
|
|
|
slot.constant = dst_wrap_nil();
|
|
|
|
slot.flags = 0;
|
2018-07-01 23:35:45 +00:00
|
|
|
slot.index = dstc_allocnear(opts.compiler, DSTC_REGTEMP_TARGET);
|
2017-12-21 04:03:34 +00:00
|
|
|
}
|
2018-01-04 02:36:10 +00:00
|
|
|
return slot;
|
2017-12-21 04:03:34 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Get a bunch of slots for function arguments */
|
2018-06-29 03:36:31 +00:00
|
|
|
DstSlot *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len) {
|
2018-01-17 04:18:45 +00:00
|
|
|
int32_t i;
|
2018-06-29 03:36:31 +00:00
|
|
|
DstSlot *ret = NULL;
|
2018-01-17 04:18:45 +00:00
|
|
|
DstFopts subopts = dstc_fopts_default(c);
|
|
|
|
for (i = 0; i < len; i++) {
|
2018-06-29 03:36:31 +00:00
|
|
|
dst_v_push(ret, dstc_value(subopts, vals[i]));
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2017-12-21 04:03:34 +00:00
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Get a bunch of slots for function arguments */
|
2018-06-29 03:36:31 +00:00
|
|
|
DstSlot *dstc_toslotskv(DstCompiler *c, Dst ds) {
|
|
|
|
DstSlot *ret = NULL;
|
2018-01-05 21:17:55 +00:00
|
|
|
const DstKV *kv = NULL;
|
2018-01-17 04:18:45 +00:00
|
|
|
DstFopts subopts = dstc_fopts_default(c);
|
2018-06-17 17:55:02 +00:00
|
|
|
while ((kv = dstc_next(ds, kv))) {
|
2018-06-29 03:36:31 +00:00
|
|
|
dst_v_push(ret, dstc_value(subopts, kv->key));
|
|
|
|
dst_v_push(ret, dstc_value(subopts, kv->value));
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2017-12-21 04:03:34 +00:00
|
|
|
|
2018-01-12 15:41:27 +00:00
|
|
|
/* Push slots load via dstc_toslots. */
|
2018-06-29 03:36:31 +00:00
|
|
|
void dstc_pushslots(DstCompiler *c, DstSlot *slots) {
|
2018-01-05 21:17:55 +00:00
|
|
|
int32_t i;
|
2018-07-01 15:52:15 +00:00
|
|
|
for (i = 0; i < dst_v_count(slots) - 2; i += 3)
|
|
|
|
dstc_emit_sss(c, DOP_PUSH_3, slots[i], slots[i+1], slots[i+2]);
|
|
|
|
if (i == dst_v_count(slots) - 2)
|
|
|
|
dstc_emit_ss(c, DOP_PUSH_2, slots[i], slots[i+1]);
|
|
|
|
else if (i == dst_v_count(slots) - 1)
|
|
|
|
dstc_emit_s(c, DOP_PUSH, slots[i]);
|
2017-12-17 04:11:51 +00:00
|
|
|
}
|
|
|
|
|
2018-01-12 15:41:27 +00:00
|
|
|
/* Free slots loaded via dstc_toslots */
|
2018-06-29 03:36:31 +00:00
|
|
|
void dstc_freeslots(DstCompiler *c, DstSlot *slots) {
|
2018-01-05 21:17:55 +00:00
|
|
|
int32_t i;
|
2018-06-29 03:36:31 +00:00
|
|
|
for (i = 0; i < dst_v_count(slots); i++) {
|
|
|
|
dstc_freeslot(c, slots[i]);
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
2018-06-29 03:36:31 +00:00
|
|
|
dst_v_free(slots);
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
|
|
|
|
2018-01-04 02:36:10 +00:00
|
|
|
/* 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-01-17 04:18:45 +00:00
|
|
|
void dstc_throwaway(DstFopts opts, Dst x) {
|
2018-01-04 02:36:10 +00:00
|
|
|
DstCompiler *c = opts.compiler;
|
2018-07-01 15:52:15 +00:00
|
|
|
DstScope unusedScope;
|
2018-01-05 21:17:55 +00:00
|
|
|
int32_t bufstart = dst_v_count(c->buffer);
|
2018-01-17 04:18:45 +00:00
|
|
|
int32_t mapbufstart = dst_v_count(c->mapbuffer);
|
2018-07-01 15:52:15 +00:00
|
|
|
dstc_scope(&unusedScope, c, DST_SCOPE_UNUSED, "unusued");
|
2018-01-17 04:18:45 +00:00
|
|
|
dstc_value(opts, x);
|
2018-01-05 21:17:55 +00:00
|
|
|
dstc_popscope(c);
|
2018-07-01 15:52:15 +00:00
|
|
|
if (c->buffer) {
|
2018-01-05 21:17:55 +00:00
|
|
|
dst_v__cnt(c->buffer) = bufstart;
|
2018-07-01 15:52:15 +00:00
|
|
|
if (c->mapbuffer)
|
2018-01-17 04:18:45 +00:00
|
|
|
dst_v__cnt(c->mapbuffer) = mapbufstart;
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
|
|
|
|
2018-01-12 15:41:27 +00:00
|
|
|
/* Compile a call or tailcall instruction */
|
2018-06-29 03:36:31 +00:00
|
|
|
static DstSlot dstc_call(DstFopts opts, DstSlot *slots, DstSlot fun) {
|
2018-01-12 15:41:27 +00:00
|
|
|
DstSlot retslot;
|
2018-01-04 02:36:10 +00:00
|
|
|
DstCompiler *c = opts.compiler;
|
2018-01-24 22:59:00 +00:00
|
|
|
int specialized = 0;
|
|
|
|
if (fun.flags & DST_SLOT_CONSTANT) {
|
2018-07-02 04:12:36 +00:00
|
|
|
if (dst_checktype(fun.constant, DST_FUNCTION)) {
|
2018-07-01 23:35:45 +00:00
|
|
|
DstFunction *f = dst_unwrap_function(fun.constant);
|
|
|
|
const DstFunOptimizer *o = dstc_funopt(f->def->flags);
|
|
|
|
if (o && (!o->can_optimize || o->can_optimize(opts, slots))) {
|
2018-01-24 22:59:00 +00:00
|
|
|
specialized = 1;
|
2018-06-29 03:36:31 +00:00
|
|
|
retslot = o->optimize(opts, slots);
|
2018-01-24 22:59:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* TODO dst function inlining (no c functions)*/
|
|
|
|
}
|
|
|
|
if (!specialized) {
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_pushslots(c, slots);
|
2018-01-24 22:59:00 +00:00
|
|
|
if (opts.flags & DST_FOPTS_TAIL) {
|
2018-07-01 16:44:41 +00:00
|
|
|
dstc_emit_s(c, DOP_TAILCALL, fun);
|
2018-01-24 22:59:00 +00:00
|
|
|
retslot = dstc_cslot(dst_wrap_nil());
|
|
|
|
retslot.flags = DST_SLOT_RETURNED;
|
|
|
|
} else {
|
|
|
|
retslot = dstc_gettarget(opts);
|
2018-07-01 19:56:08 +00:00
|
|
|
int32_t fun_register = dstc_regnear(c, fun, DSTC_REGTEMP_0);
|
2018-07-01 15:52:15 +00:00
|
|
|
dstc_emit(c, DOP_CALL |
|
|
|
|
(retslot.index << 8) |
|
|
|
|
(fun_register << 16));
|
|
|
|
/* Don't free ret register */
|
2018-07-01 16:44:41 +00:00
|
|
|
dstc_free_reg(c, fun, fun_register);
|
2018-01-24 22:59:00 +00:00
|
|
|
}
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_freeslots(c, slots);
|
2018-01-12 15:41:27 +00:00
|
|
|
return retslot;
|
|
|
|
}
|
2018-01-04 02:36:10 +00:00
|
|
|
|
2018-06-29 03:36:31 +00:00
|
|
|
static DstSlot dstc_array(DstFopts opts, Dst x) {
|
2018-01-17 04:18:45 +00:00
|
|
|
DstCompiler *c = opts.compiler;
|
|
|
|
DstArray *a = dst_unwrap_array(x);
|
2018-06-29 03:36:31 +00:00
|
|
|
return dstc_call(opts,
|
2018-01-17 04:18:45 +00:00
|
|
|
dstc_toslots(c, a->data, a->count),
|
2018-01-30 04:38:49 +00:00
|
|
|
dstc_cslot(dst_wrap_cfunction(dst_core_array)));
|
2017-12-30 21:46:59 +00:00
|
|
|
}
|
|
|
|
|
2018-06-29 03:36:31 +00:00
|
|
|
static DstSlot dstc_tablector(DstFopts opts, Dst x, DstCFunction cfun) {
|
2018-01-17 04:18:45 +00:00
|
|
|
DstCompiler *c = opts.compiler;
|
2018-06-29 03:36:31 +00:00
|
|
|
return dstc_call(opts, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun)));
|
2018-01-12 15:41:27 +00:00
|
|
|
}
|
2018-01-04 02:36:10 +00:00
|
|
|
|
2018-06-29 03:36:31 +00:00
|
|
|
static DstSlot dstc_bufferctor(DstFopts opts, Dst x) {
|
2018-02-03 23:12:07 +00:00
|
|
|
DstCompiler *c = opts.compiler;
|
|
|
|
DstBuffer *b = dst_unwrap_buffer(x);
|
|
|
|
Dst onearg = dst_stringv(b->data, b->count);
|
2018-06-29 03:36:31 +00:00
|
|
|
return dstc_call(opts,
|
2018-02-03 23:12:07 +00:00
|
|
|
dstc_toslots(c, &onearg, 1),
|
|
|
|
dstc_cslot(dst_wrap_cfunction(dst_core_buffer)));
|
|
|
|
}
|
|
|
|
|
2018-02-03 18:55:55 +00:00
|
|
|
/* Compile a symbol */
|
2018-06-29 03:36:31 +00:00
|
|
|
DstSlot dstc_symbol(DstFopts opts, const uint8_t *sym) {
|
2018-02-03 18:55:55 +00:00
|
|
|
if (dst_string_length(sym) && sym[0] != ':') {
|
|
|
|
/* Non keyword */
|
2018-06-29 03:36:31 +00:00
|
|
|
return dstc_resolve(opts.compiler, sym);
|
2018-02-03 18:55:55 +00:00
|
|
|
} else {
|
|
|
|
/* Keyword */
|
|
|
|
return dstc_cslot(dst_wrap_symbol(sym));
|
2018-05-20 01:16:00 +00:00
|
|
|
}
|
2018-02-03 18:55:55 +00:00
|
|
|
}
|
|
|
|
|
2018-01-12 15:41:27 +00:00
|
|
|
/* Compile a single value */
|
2018-01-17 04:18:45 +00:00
|
|
|
DstSlot dstc_value(DstFopts opts, Dst x) {
|
2018-01-12 15:41:27 +00:00
|
|
|
DstSlot ret;
|
2018-01-28 20:29:47 +00:00
|
|
|
DstCompiler *c = opts.compiler;
|
2018-01-30 04:38:49 +00:00
|
|
|
int macrorecur = 0;
|
2018-07-01 15:52:15 +00:00
|
|
|
DstSourceMapping last_mapping = c->current_mapping;
|
2018-01-28 20:29:47 +00:00
|
|
|
opts.compiler->recursion_guard--;
|
2018-01-30 04:38:49 +00:00
|
|
|
recur:
|
2018-01-12 15:41:27 +00:00
|
|
|
if (dstc_iserr(&opts)) {
|
2018-01-05 21:17:55 +00:00
|
|
|
return dstc_cslot(dst_wrap_nil());
|
|
|
|
}
|
2018-01-12 15:41:27 +00:00
|
|
|
if (opts.compiler->recursion_guard <= 0) {
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_cerror(opts.compiler, "recursed too deeply");
|
2018-01-12 15:41:27 +00:00
|
|
|
return dstc_cslot(dst_wrap_nil());
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
2018-01-17 04:18:45 +00:00
|
|
|
switch (dst_type(x)) {
|
2018-01-12 15:41:27 +00:00
|
|
|
default:
|
2018-01-17 04:18:45 +00:00
|
|
|
ret = dstc_cslot(x);
|
2018-01-12 15:41:27 +00:00
|
|
|
break;
|
|
|
|
case DST_SYMBOL:
|
|
|
|
{
|
2018-01-17 04:18:45 +00:00
|
|
|
const uint8_t *sym = dst_unwrap_symbol(x);
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_symbol(opts, sym);
|
2018-01-12 15:41:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DST_TUPLE:
|
2018-01-28 20:29:47 +00:00
|
|
|
{
|
|
|
|
int compiled = 0;
|
|
|
|
Dst headval;
|
|
|
|
DstSlot head;
|
|
|
|
DstFopts subopts = dstc_fopts_default(c);
|
|
|
|
const Dst *tup = dst_unwrap_tuple(x);
|
2018-07-01 15:52:15 +00:00
|
|
|
/* Get ast mapping */
|
|
|
|
if (dst_tuple_sm_line(tup) > 0) {
|
|
|
|
c->current_mapping.line = dst_tuple_sm_line(tup);
|
|
|
|
c->current_mapping.column = dst_tuple_sm_col(tup);
|
|
|
|
}
|
2018-01-28 20:29:47 +00:00
|
|
|
/* Empty tuple is tuple literal */
|
|
|
|
if (dst_tuple_length(tup) == 0) {
|
|
|
|
compiled = 1;
|
|
|
|
ret = dstc_cslot(x);
|
|
|
|
} else {
|
|
|
|
/* Symbols could be specials */
|
2018-06-29 03:36:31 +00:00
|
|
|
headval = tup[0];
|
2018-01-28 20:29:47 +00:00
|
|
|
if (dst_checktype(headval, DST_SYMBOL)) {
|
2018-06-17 17:55:02 +00:00
|
|
|
const uint8_t *headsym = dst_unwrap_symbol(headval);
|
|
|
|
const DstSpecial *s = dstc_special(headsym);
|
2018-01-28 20:29:47 +00:00
|
|
|
if (NULL != s) {
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = s->compile(opts, dst_tuple_length(tup) - 1, tup + 1);
|
2018-01-28 20:29:47 +00:00
|
|
|
compiled = 1;
|
|
|
|
} else {
|
|
|
|
/* Check macro */
|
2018-06-17 17:55:02 +00:00
|
|
|
Dst macVal;
|
|
|
|
DstBindingType btype = dst_env_resolve(c->env, headsym, &macVal);
|
|
|
|
if (btype == DST_BINDING_MACRO &&
|
|
|
|
dst_checktype(macVal, DST_FUNCTION)) {
|
2018-01-30 04:38:49 +00:00
|
|
|
if (macrorecur++ > DST_RECURSION_GUARD) {
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_cerror(c, "macro expansion recursed too deeply");
|
2018-01-30 04:38:49 +00:00
|
|
|
return dstc_cslot(dst_wrap_nil());
|
|
|
|
} else {
|
2018-06-17 17:55:02 +00:00
|
|
|
DstFunction *f = dst_unwrap_function(macVal);
|
2018-03-11 19:35:23 +00:00
|
|
|
int lock = dst_gclock();
|
2018-05-17 02:09:36 +00:00
|
|
|
DstSignal status = dst_call(f, dst_tuple_length(tup) - 1, tup + 1, &x);
|
2018-03-11 19:35:23 +00:00
|
|
|
dst_gcunlock(lock);
|
2018-05-17 02:09:36 +00:00
|
|
|
if (status != DST_SIGNAL_OK) {
|
2018-04-01 22:24:04 +00:00
|
|
|
const uint8_t *es = dst_formatc("error in macro expansion: %V", x);
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_error(c, es);
|
2018-01-30 04:38:49 +00:00
|
|
|
}
|
|
|
|
/* Tail recur on the value */
|
|
|
|
goto recur;
|
2018-01-28 20:29:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!compiled) {
|
|
|
|
/* Compile the head of the tuple */
|
|
|
|
subopts.flags = DST_FUNCTION | DST_CFUNCTION;
|
|
|
|
head = dstc_value(subopts, tup[0]);
|
2018-06-17 17:55:02 +00:00
|
|
|
/* Add compile function call */
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_call(opts, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head);
|
2018-01-28 20:29:47 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-01 15:52:15 +00:00
|
|
|
/* Pop source mapping */
|
|
|
|
if (c->result.status != DST_COMPILE_ERROR)
|
|
|
|
c->current_mapping = last_mapping;
|
2018-01-28 20:29:47 +00:00
|
|
|
}
|
2018-01-12 15:41:27 +00:00
|
|
|
break;
|
|
|
|
case DST_ARRAY:
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_array(opts, x);
|
2018-01-12 15:41:27 +00:00
|
|
|
break;
|
|
|
|
case DST_STRUCT:
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_tablector(opts, x, dst_core_struct);
|
2018-01-12 15:41:27 +00:00
|
|
|
break;
|
|
|
|
case DST_TABLE:
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_tablector(opts, x, dst_core_table);
|
2018-01-12 15:41:27 +00:00
|
|
|
break;
|
2018-02-03 23:12:07 +00:00
|
|
|
case DST_BUFFER:
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_bufferctor(opts, x);
|
2018-02-03 23:12:07 +00:00
|
|
|
break;
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
2018-01-21 19:39:32 +00:00
|
|
|
if (dstc_iserr(&opts)) {
|
|
|
|
return dstc_cslot(dst_wrap_nil());
|
|
|
|
}
|
2018-01-12 15:41:27 +00:00
|
|
|
if (opts.flags & DST_FOPTS_TAIL) {
|
2018-06-29 03:36:31 +00:00
|
|
|
ret = dstc_return(opts.compiler, ret);
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
2018-07-01 15:52:15 +00:00
|
|
|
if (opts.flags & DST_FOPTS_HINT) {
|
2018-06-29 03:36:31 +00:00
|
|
|
dstc_copy(opts.compiler, opts.hint, ret);
|
2018-01-16 04:31:39 +00:00
|
|
|
ret = opts.hint;
|
|
|
|
}
|
2018-01-12 15:41:27 +00:00
|
|
|
opts.compiler->recursion_guard++;
|
|
|
|
return ret;
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Compile a funcdef */
|
2018-01-12 15:41:27 +00:00
|
|
|
DstFuncDef *dstc_pop_funcdef(DstCompiler *c) {
|
2018-07-01 15:52:15 +00:00
|
|
|
DstScope *scope = c->scope;
|
2018-01-19 21:43:19 +00:00
|
|
|
DstFuncDef *def = dst_funcdef_alloc();
|
2018-07-01 15:52:15 +00:00
|
|
|
def->slotcount = scope->ra.max + 1;
|
2018-01-04 02:36:10 +00:00
|
|
|
|
2018-07-01 15:52:15 +00:00
|
|
|
dst_assert(scope->flags & DST_SCOPE_FUNCTION, "expected function scope");
|
2018-01-21 19:39:32 +00:00
|
|
|
|
2018-01-04 02:36:10 +00:00
|
|
|
/* Copy envs */
|
2018-07-01 15:52:15 +00:00
|
|
|
def->environments_length = dst_v_count(scope->envs);
|
|
|
|
def->environments = dst_v_flatten(scope->envs);
|
2018-01-04 02:36:10 +00:00
|
|
|
|
2018-07-01 15:52:15 +00:00
|
|
|
def->constants_length = dst_v_count(scope->consts);
|
|
|
|
def->constants = dst_v_flatten(scope->consts);
|
2018-01-04 02:36:10 +00:00
|
|
|
|
2018-07-01 15:52:15 +00:00
|
|
|
def->defs_length = dst_v_count(scope->defs);
|
|
|
|
def->defs = dst_v_flatten(scope->defs);
|
2018-01-04 02:36:10 +00:00
|
|
|
|
2018-06-29 03:36:31 +00:00
|
|
|
/* Copy bytecode (only last chunk) */
|
2018-07-01 15:52:15 +00:00
|
|
|
def->bytecode_length = dst_v_count(c->buffer) - scope->bytecode_start;
|
2018-01-04 02:36:10 +00:00
|
|
|
if (def->bytecode_length) {
|
2018-01-05 21:17:55 +00:00
|
|
|
size_t s = sizeof(int32_t) * def->bytecode_length;
|
|
|
|
def->bytecode = malloc(s);
|
2018-01-04 02:36:10 +00:00
|
|
|
if (NULL == def->bytecode) {
|
|
|
|
DST_OUT_OF_MEMORY;
|
|
|
|
}
|
2018-07-01 15:52:15 +00:00
|
|
|
memcpy(def->bytecode, c->buffer + scope->bytecode_start, s);
|
|
|
|
dst_v__cnt(c->buffer) = scope->bytecode_start;
|
2018-01-05 21:17:55 +00:00
|
|
|
if (NULL != c->mapbuffer) {
|
2018-06-29 23:44:33 +00:00
|
|
|
size_t s = sizeof(DstSourceMapping) * def->bytecode_length;
|
2018-03-16 03:27:44 +00:00
|
|
|
def->sourcemap = malloc(s);
|
2018-01-05 21:17:55 +00:00
|
|
|
if (NULL == def->sourcemap) {
|
|
|
|
DST_OUT_OF_MEMORY;
|
|
|
|
}
|
2018-07-01 15:52:15 +00:00
|
|
|
memcpy(def->sourcemap, c->mapbuffer + scope->bytecode_start, s);
|
|
|
|
dst_v__cnt(c->mapbuffer) = scope->bytecode_start;
|
2018-01-04 02:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-29 03:36:31 +00:00
|
|
|
/* Get source from parser */
|
2018-06-29 14:37:50 +00:00
|
|
|
def->source = c->source;
|
2018-06-29 03:36:31 +00:00
|
|
|
|
2018-01-04 02:36:10 +00:00
|
|
|
def->arity = 0;
|
|
|
|
def->flags = 0;
|
2018-07-01 15:52:15 +00:00
|
|
|
if (scope->flags & DST_SCOPE_ENV) {
|
2018-01-04 02:36:10 +00:00
|
|
|
def->flags |= DST_FUNCDEF_FLAG_NEEDSENV;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pop the scope */
|
2018-01-05 21:17:55 +00:00
|
|
|
dstc_popscope(c);
|
2018-01-04 02:36:10 +00:00
|
|
|
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2017-12-21 04:03:34 +00:00
|
|
|
/* Initialize a compiler */
|
2018-06-29 14:37:50 +00:00
|
|
|
static void dstc_init(DstCompiler *c, DstTable *env, const uint8_t *where) {
|
2018-07-01 15:52:15 +00:00
|
|
|
c->scope = NULL;
|
2017-12-21 04:03:34 +00:00
|
|
|
c->buffer = NULL;
|
|
|
|
c->mapbuffer = NULL;
|
|
|
|
c->recursion_guard = DST_RECURSION_GUARD;
|
2017-12-30 21:46:59 +00:00
|
|
|
c->env = env;
|
2018-06-29 14:37:50 +00:00
|
|
|
c->source = where;
|
2018-06-29 15:12:33 +00:00
|
|
|
c->current_mapping.line = 0;
|
|
|
|
c->current_mapping.column = 0;
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Init result */
|
|
|
|
c->result.error = NULL;
|
|
|
|
c->result.status = DST_COMPILE_OK;
|
2018-06-29 05:15:47 +00:00
|
|
|
c->result.funcdef = NULL;
|
2018-06-29 15:12:33 +00:00
|
|
|
c->result.error_mapping.line = 0;
|
|
|
|
c->result.error_mapping.column = 0;
|
2017-12-21 04:03:34 +00:00
|
|
|
}
|
2017-12-17 04:11:51 +00:00
|
|
|
|
|
|
|
/* Deinitialize a compiler struct */
|
2018-01-05 21:17:55 +00:00
|
|
|
static void dstc_deinit(DstCompiler *c) {
|
|
|
|
dst_v_free(c->buffer);
|
|
|
|
dst_v_free(c->mapbuffer);
|
2018-01-18 22:25:45 +00:00
|
|
|
c->env = NULL;
|
2017-12-16 06:17:53 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Compile a form. */
|
2018-06-29 14:37:50 +00:00
|
|
|
DstCompileResult dst_compile(Dst source, DstTable *env, const uint8_t *where) {
|
2018-01-05 21:17:55 +00:00
|
|
|
DstCompiler c;
|
2018-07-01 15:52:15 +00:00
|
|
|
DstScope rootscope;
|
2018-01-06 16:09:15 +00:00
|
|
|
DstFopts fopts;
|
2017-12-16 06:17:53 +00:00
|
|
|
|
2018-06-29 14:37:50 +00:00
|
|
|
dstc_init(&c, env, where);
|
2017-12-16 06:17:53 +00:00
|
|
|
|
2017-12-17 04:11:51 +00:00
|
|
|
/* Push a function scope */
|
2018-07-01 15:52:15 +00:00
|
|
|
dstc_scope(&rootscope, &c, DST_SCOPE_FUNCTION | DST_SCOPE_TOP, "root");
|
2017-12-21 04:03:34 +00:00
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
/* Set initial form options */
|
|
|
|
fopts.compiler = &c;
|
2017-12-17 04:11:51 +00:00
|
|
|
fopts.flags = DST_FOPTS_TAIL | DST_SLOTTYPE_ANY;
|
2018-01-05 21:17:55 +00:00
|
|
|
fopts.hint = dstc_cslot(dst_wrap_nil());
|
2017-12-17 04:11:51 +00:00
|
|
|
|
|
|
|
/* Compile the value */
|
2018-01-18 22:25:45 +00:00
|
|
|
dstc_value(fopts, source);
|
2017-12-21 04:03:34 +00:00
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
if (c.result.status == DST_COMPILE_OK) {
|
2018-01-20 22:19:47 +00:00
|
|
|
DstFuncDef *def = dstc_pop_funcdef(&c);
|
2018-06-29 05:15:47 +00:00
|
|
|
def->name = dst_cstring("_thunk");
|
2018-01-20 22:19:47 +00:00
|
|
|
c.result.funcdef = def;
|
2018-06-29 05:15:47 +00:00
|
|
|
} else {
|
2018-06-29 14:37:50 +00:00
|
|
|
c.result.error_mapping = c.current_mapping;
|
2018-07-01 15:52:15 +00:00
|
|
|
dstc_popscope(&c);
|
2018-01-05 21:17:55 +00:00
|
|
|
}
|
2017-12-17 04:11:51 +00:00
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
dstc_deinit(&c);
|
2017-12-17 04:11:51 +00:00
|
|
|
|
2018-01-05 21:17:55 +00:00
|
|
|
return c.result;
|
2017-12-17 04:11:51 +00:00
|
|
|
}
|
|
|
|
|
2018-01-16 04:31:39 +00:00
|
|
|
/* C Function for compiling */
|
2018-07-01 16:44:41 +00:00
|
|
|
static int cfun(DstArgs args) {
|
2018-01-16 04:31:39 +00:00
|
|
|
DstCompileResult res;
|
|
|
|
DstTable *t;
|
2018-01-18 22:25:45 +00:00
|
|
|
DstTable *env;
|
2018-06-29 03:36:31 +00:00
|
|
|
DST_MINARITY(args, 2);
|
|
|
|
DST_MAXARITY(args, 3);
|
2018-05-13 00:31:28 +00:00
|
|
|
DST_ARG_TABLE(env, args, 1);
|
2018-06-29 14:37:50 +00:00
|
|
|
const uint8_t *source = NULL;
|
2018-06-29 03:36:31 +00:00
|
|
|
if (args.n == 3) {
|
2018-06-29 14:37:50 +00:00
|
|
|
DST_ARG_STRING(source, args, 2);
|
2018-06-29 03:36:31 +00:00
|
|
|
}
|
2018-06-29 14:37:50 +00:00
|
|
|
res = dst_compile(args.v[0], env, source);
|
2018-01-16 04:31:39 +00:00
|
|
|
if (res.status == DST_COMPILE_OK) {
|
2018-05-13 00:31:28 +00:00
|
|
|
DST_RETURN_FUNCTION(args, dst_thunk(res.funcdef));
|
2018-01-16 04:31:39 +00:00
|
|
|
} else {
|
|
|
|
t = dst_table(2);
|
2018-02-07 05:44:51 +00:00
|
|
|
dst_table_put(t, dst_csymbolv(":error"), dst_wrap_string(res.error));
|
2018-06-29 15:12:33 +00:00
|
|
|
dst_table_put(t, dst_csymbolv(":error-line"), dst_wrap_integer(res.error_mapping.line));
|
|
|
|
dst_table_put(t, dst_csymbolv(":error-column"), dst_wrap_integer(res.error_mapping.column));
|
2018-05-13 00:31:28 +00:00
|
|
|
DST_RETURN_TABLE(args, t);
|
2018-01-16 04:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
2018-01-27 20:15:09 +00:00
|
|
|
|
2018-07-01 16:44:41 +00:00
|
|
|
static const DstReg cfuns[] = {
|
|
|
|
{"compile", cfun},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2018-01-27 20:15:09 +00:00
|
|
|
int dst_lib_compile(DstArgs args) {
|
|
|
|
DstTable *env = dst_env_arg(args);
|
2018-07-01 16:44:41 +00:00
|
|
|
dst_env_cfuns(env, cfuns);
|
2018-01-27 20:15:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|