mirror of
https://github.com/janet-lang/janet
synced 2024-12-23 15:00:27 +00:00
Remove some c functions in favor of bytecode.
This commit is contained in:
parent
e60c8a9b75
commit
5e2de33ae7
@ -13,7 +13,7 @@ body once, and then memoizes the result."
|
|||||||
(tuple 'do
|
(tuple 'do
|
||||||
(tuple 'var $state nil)
|
(tuple 'var $state nil)
|
||||||
(tuple 'var $loaded nil)
|
(tuple 'var $loaded nil)
|
||||||
(tuple 'fn (array)
|
(tuple 'fn []
|
||||||
(tuple 'if $loaded
|
(tuple 'if $loaded
|
||||||
$state
|
$state
|
||||||
(tuple 'do
|
(tuple 'do
|
||||||
|
@ -1058,7 +1058,7 @@
|
|||||||
(when c (file.write stdout " cfunction"))
|
(when c (file.write stdout " cfunction"))
|
||||||
(if name
|
(if name
|
||||||
(file.write stdout " " name)
|
(file.write stdout " " name)
|
||||||
(when func (file.write stdout " " func)))
|
(when func (file.write stdout " " (string func))))
|
||||||
(if source
|
(if source
|
||||||
(do
|
(do
|
||||||
(file.write stdout " [" source "]")
|
(file.write stdout " [" source "]")
|
||||||
|
@ -114,48 +114,8 @@ static DstSlot genericSSI(DstFopts opts, int op, DstSlot s, int32_t imm) {
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DstSlot add(DstFopts opts, DstSlot *args) {
|
/* Function optimizers */
|
||||||
return opreduce(opts, args, DOP_ADD, dst_wrap_integer(0), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DstSlot mul(DstFopts opts, DstSlot *args) {
|
|
||||||
return opreduce(opts, args, DOP_MULTIPLY, dst_wrap_integer(1), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DstSlot subUnary(DstFopts opts, DstSlot onearg) {
|
|
||||||
return genericSSS(opts, DOP_SUBTRACT, dst_wrap_integer(0), onearg);
|
|
||||||
}
|
|
||||||
static DstSlot sub(DstFopts opts, DstSlot *args) {
|
|
||||||
return opreduce(opts, args, DOP_SUBTRACT, dst_wrap_integer(0), subUnary);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DstSlot divUnary(DstFopts opts, DstSlot onearg) {
|
|
||||||
return genericSSS(opts, DOP_DIVIDE, dst_wrap_integer(1), onearg);
|
|
||||||
}
|
|
||||||
static DstSlot divide(DstFopts opts, DstSlot *args) {
|
|
||||||
return opreduce(opts, args, DOP_DIVIDE, dst_wrap_integer(1), divUnary);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const DstCFunOptimizer coptimizers[] = {
|
|
||||||
{dst_add, NULL, add},
|
|
||||||
{dst_subtract, NULL, sub},
|
|
||||||
{dst_multiply, NULL, mul},
|
|
||||||
{dst_divide, NULL, divide},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Get a cfunction optimizer. Return NULL if none exists. */
|
|
||||||
const DstCFunOptimizer *dstc_cfunopt(DstCFunction cfun) {
|
|
||||||
size_t i;
|
|
||||||
size_t n = sizeof(coptimizers)/sizeof(DstCFunOptimizer);
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
if (coptimizers[i].cfun == cfun)
|
|
||||||
return coptimizers + i;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Normal function optimizers */
|
|
||||||
|
|
||||||
/* Get, put, etc. */
|
|
||||||
static DstSlot do_error(DstFopts opts, DstSlot *args) {
|
static DstSlot do_error(DstFopts opts, DstSlot *args) {
|
||||||
dstc_emit_s(opts.compiler, DOP_ERROR, args[0]);
|
dstc_emit_s(opts.compiler, DOP_ERROR, args[0]);
|
||||||
return dstc_cslot(dst_wrap_nil());
|
return dstc_cslot(dst_wrap_nil());
|
||||||
@ -201,6 +161,54 @@ static DstSlot do_apply1(DstFopts opts, DstSlot *args) {
|
|||||||
dstc_free_reg(opts.compiler, args[0], fun_reg);
|
dstc_free_reg(opts.compiler, args[0], fun_reg);
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
static DstSlot do_add(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_ADD, dst_wrap_integer(0), NULL);
|
||||||
|
}
|
||||||
|
static DstSlot do_sub_unary(DstFopts opts, DstSlot slot) {
|
||||||
|
return genericSSS(opts, DOP_SUBTRACT, dst_wrap_integer(0), slot);
|
||||||
|
}
|
||||||
|
static DstSlot do_sub(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_SUBTRACT, dst_wrap_integer(0), do_sub_unary);
|
||||||
|
}
|
||||||
|
static DstSlot do_mul(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_MULTIPLY, dst_wrap_integer(1), NULL);
|
||||||
|
}
|
||||||
|
static DstSlot do_div_unary(DstFopts opts, DstSlot slot) {
|
||||||
|
return genericSSS(opts, DOP_DIVIDE, dst_wrap_integer(1), slot);
|
||||||
|
}
|
||||||
|
static DstSlot do_div(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_DIVIDE, dst_wrap_integer(1), do_div_unary);
|
||||||
|
}
|
||||||
|
static DstSlot do_band(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_BAND, dst_wrap_integer(-1), NULL);
|
||||||
|
}
|
||||||
|
static DstSlot do_bor(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_BOR, dst_wrap_integer(0), NULL);
|
||||||
|
}
|
||||||
|
static DstSlot do_bxor(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_BXOR, dst_wrap_integer(0), NULL);
|
||||||
|
}
|
||||||
|
static DstSlot do_lshift_unary(DstFopts opts, DstSlot s) {
|
||||||
|
return genericSSS(opts, DOP_SHIFT_LEFT, dst_wrap_integer(1), s);
|
||||||
|
}
|
||||||
|
static DstSlot do_lshift(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_SHIFT_LEFT,
|
||||||
|
dst_wrap_integer(1), do_lshift_unary);
|
||||||
|
}
|
||||||
|
static DstSlot do_rshift_unary(DstFopts opts, DstSlot s) {
|
||||||
|
return genericSSS(opts, DOP_SHIFT_RIGHT, dst_wrap_integer(1), s);
|
||||||
|
}
|
||||||
|
static DstSlot do_rshift(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_SHIFT_RIGHT,
|
||||||
|
dst_wrap_integer(1), do_rshift_unary);
|
||||||
|
}
|
||||||
|
static DstSlot do_rshiftu_unary(DstFopts opts, DstSlot s) {
|
||||||
|
return genericSSS(opts, DOP_SHIFT_RIGHT_UNSIGNED, dst_wrap_integer(1), s);
|
||||||
|
}
|
||||||
|
static DstSlot do_rshiftu(DstFopts opts, DstSlot *args) {
|
||||||
|
return opreduce(opts, args, DOP_SHIFT_RIGHT,
|
||||||
|
dst_wrap_integer(1), do_rshiftu_unary);
|
||||||
|
}
|
||||||
|
|
||||||
/* Arranged by tag */
|
/* Arranged by tag */
|
||||||
static const DstFunOptimizer optimizers[] = {
|
static const DstFunOptimizer optimizers[] = {
|
||||||
@ -212,12 +220,24 @@ static const DstFunOptimizer optimizers[] = {
|
|||||||
{fixarity2, do_resume},
|
{fixarity2, do_resume},
|
||||||
{fixarity2, do_get},
|
{fixarity2, do_get},
|
||||||
{fixarity2, do_put},
|
{fixarity2, do_put},
|
||||||
{fixarity1, do_length}
|
{fixarity1, do_length},
|
||||||
|
{NULL, do_add},
|
||||||
|
{NULL, do_sub},
|
||||||
|
{NULL, do_mul},
|
||||||
|
{NULL, do_div},
|
||||||
|
{NULL, do_band},
|
||||||
|
{NULL, do_bor},
|
||||||
|
{NULL, do_bxor},
|
||||||
|
{NULL, do_lshift},
|
||||||
|
{NULL, do_rshift},
|
||||||
|
{NULL, do_rshiftu},
|
||||||
};
|
};
|
||||||
|
|
||||||
const DstFunOptimizer *dstc_funopt(uint32_t flags) {
|
const DstFunOptimizer *dstc_funopt(uint32_t flags) {
|
||||||
uint32_t tag = flags & DST_FUNCDEF_FLAG_TAG;
|
uint32_t tag = flags & DST_FUNCDEF_FLAG_TAG;
|
||||||
if (tag == 0 || tag > 8) return NULL;
|
if (tag == 0 || tag >=
|
||||||
|
((sizeof(optimizers)/sizeof(uint32_t) - 1)))
|
||||||
|
return NULL;
|
||||||
return optimizers + tag;
|
return optimizers + tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,13 +386,7 @@ static DstSlot dstc_call(DstFopts opts, DstSlot *slots, DstSlot fun) {
|
|||||||
DstCompiler *c = opts.compiler;
|
DstCompiler *c = opts.compiler;
|
||||||
int specialized = 0;
|
int specialized = 0;
|
||||||
if (fun.flags & DST_SLOT_CONSTANT) {
|
if (fun.flags & DST_SLOT_CONSTANT) {
|
||||||
if (dst_checktype(fun.constant, DST_CFUNCTION)) {
|
if (dst_checktype(fun.constant, DST_FUNCTION)) {
|
||||||
const DstCFunOptimizer *o = dstc_cfunopt(dst_unwrap_cfunction(fun.constant));
|
|
||||||
if (o && (!o->can_optimize || o->can_optimize(opts, slots))) {
|
|
||||||
specialized = 1;
|
|
||||||
retslot = o->optimize(opts, slots);
|
|
||||||
}
|
|
||||||
} else if (dst_checktype(fun.constant, DST_FUNCTION)) {
|
|
||||||
DstFunction *f = dst_unwrap_function(fun.constant);
|
DstFunction *f = dst_unwrap_function(fun.constant);
|
||||||
const DstFunOptimizer *o = dstc_funopt(f->def->flags);
|
const DstFunOptimizer *o = dstc_funopt(f->def->flags);
|
||||||
if (o && (!o->can_optimize || o->can_optimize(opts, slots))) {
|
if (o && (!o->can_optimize || o->can_optimize(opts, slots))) {
|
||||||
|
@ -37,6 +37,16 @@
|
|||||||
#define DST_FUN_GET 6
|
#define DST_FUN_GET 6
|
||||||
#define DST_FUN_PUT 7
|
#define DST_FUN_PUT 7
|
||||||
#define DST_FUN_LENGTH 8
|
#define DST_FUN_LENGTH 8
|
||||||
|
#define DST_FUN_ADD 9
|
||||||
|
#define DST_FUN_SUBTRACT 10
|
||||||
|
#define DST_FUN_MULTIPLY 11
|
||||||
|
#define DST_FUN_DIVIDE 12
|
||||||
|
#define DST_FUN_BAND 13
|
||||||
|
#define DST_FUN_BOR 14
|
||||||
|
#define DST_FUN_BXOR 15
|
||||||
|
#define DST_FUN_LSHIFT 16
|
||||||
|
#define DST_FUN_RSHIFT 17
|
||||||
|
#define DST_FUN_RSHIFTU 18
|
||||||
|
|
||||||
/* Compiler typedefs */
|
/* Compiler typedefs */
|
||||||
typedef struct DstCompiler DstCompiler;
|
typedef struct DstCompiler DstCompiler;
|
||||||
@ -45,7 +55,6 @@ typedef struct SlotTracker SlotTracker;
|
|||||||
typedef struct DstScope DstScope;
|
typedef struct DstScope DstScope;
|
||||||
typedef struct DstSlot DstSlot;
|
typedef struct DstSlot DstSlot;
|
||||||
typedef struct DstFopts DstFopts;
|
typedef struct DstFopts DstFopts;
|
||||||
typedef struct DstCFunOptimizer DstCFunOptimizer;
|
|
||||||
typedef struct DstFunOptimizer DstFunOptimizer;
|
typedef struct DstFunOptimizer DstFunOptimizer;
|
||||||
typedef struct DstSpecial DstSpecial;
|
typedef struct DstSpecial DstSpecial;
|
||||||
|
|
||||||
@ -148,15 +157,6 @@ struct DstFopts {
|
|||||||
/* Get the default form options */
|
/* Get the default form options */
|
||||||
DstFopts dstc_fopts_default(DstCompiler *c);
|
DstFopts dstc_fopts_default(DstCompiler *c);
|
||||||
|
|
||||||
/* A grouping of optimizations on a cfunction given certain conditions
|
|
||||||
* on the arguments (such as all constants, or some known types). The appropriate
|
|
||||||
* optimizations should be tried before compiling a normal function call. */
|
|
||||||
struct DstCFunOptimizer {
|
|
||||||
DstCFunction cfun;
|
|
||||||
int (*can_optimize)(DstFopts opts, DstSlot *args);
|
|
||||||
DstSlot (*optimize)(DstFopts opts, DstSlot *args);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* For optimizing builtin normal functions. */
|
/* For optimizing builtin normal functions. */
|
||||||
struct DstFunOptimizer {
|
struct DstFunOptimizer {
|
||||||
int (*can_optimize)(DstFopts opts, DstSlot *args);
|
int (*can_optimize)(DstFopts opts, DstSlot *args);
|
||||||
@ -172,7 +172,6 @@ struct DstSpecial {
|
|||||||
/****************************************************/
|
/****************************************************/
|
||||||
|
|
||||||
/* Get an optimizer if it exists, otherwise NULL */
|
/* Get an optimizer if it exists, otherwise NULL */
|
||||||
const DstCFunOptimizer *dstc_cfunopt(DstCFunction cfun);
|
|
||||||
const DstFunOptimizer *dstc_funopt(uint32_t flags);
|
const DstFunOptimizer *dstc_funopt(uint32_t flags);
|
||||||
|
|
||||||
/* Get a special. Return NULL if none exists */
|
/* Get a special. Return NULL if none exists */
|
||||||
|
@ -77,6 +77,76 @@ static void dst_quick_asm(
|
|||||||
dst_env_def(env, name, dst_wrap_function(dst_thunk(def)));
|
dst_env_def(env, name, dst_wrap_function(dst_thunk(def)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SSS(op, a, b, c) (op | (a << 8) | (b << 16) | (c << 24))
|
||||||
|
#define SS(op, a, b) SSS(op, a, b, 0)
|
||||||
|
#define S(op, a) SSS(op, a, 0, 0)
|
||||||
|
/* Variadic operator assembly. Must be templatized for each different opcode. */
|
||||||
|
/* Reg 0: Argument tuple (args) */
|
||||||
|
/* Reg 1: Argument count (argn) */
|
||||||
|
/* Reg 2: Jump flag (jump?) */
|
||||||
|
/* Reg 3: Accumulator (accum) */
|
||||||
|
/* Reg 4: Next operand (operand) */
|
||||||
|
/* Reg 5: Loop iterator (i) */
|
||||||
|
static DST_THREAD_LOCAL uint32_t varop_asm[] = {
|
||||||
|
DOP_LENGTH | (1 << 8), /* Put number of arguments in register 1 -> argn = count(args) */
|
||||||
|
|
||||||
|
/* Cheack nullary */
|
||||||
|
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (0 << 24), /* Check if numargs equal to 0 */
|
||||||
|
DOP_JUMP_IF_NOT | (2 << 8) | (3 << 16), /* If not 0, jump to next check */
|
||||||
|
/* Nullary */
|
||||||
|
DOP_LOAD_INTEGER | (3 << 8), /* accum = nullary value */
|
||||||
|
DOP_RETURN | (3 << 8), /* return accum */
|
||||||
|
|
||||||
|
/* Check unary */
|
||||||
|
DOP_EQUALS_IMMEDIATE | (2 << 8) | (1 << 16) | (1 << 24), /* Check if numargs equal to 1 */
|
||||||
|
DOP_JUMP_IF_NOT | (2 << 8) | (5 << 16), /* If not 1, jump to next check */
|
||||||
|
/* Unary */
|
||||||
|
DOP_LOAD_INTEGER | (3 << 8), /* accum = unary value */
|
||||||
|
DOP_GET_INDEX | (4 << 8) | (0 << 16) | (0 << 24), /* operand = args[0] */
|
||||||
|
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */
|
||||||
|
DOP_RETURN | (3 << 8), /* return accum */
|
||||||
|
|
||||||
|
/* Mutli (2 or more) arity */
|
||||||
|
/* Prime loop */
|
||||||
|
DOP_GET_INDEX | (3 << 8) | (0 << 16) | (0 << 24), /* accum = args[0] */
|
||||||
|
DOP_LOAD_INTEGER | (5 << 8) | (1 << 16), /* i = 1 */
|
||||||
|
/* Main loop */
|
||||||
|
DOP_GET | (4 << 8) | (0 << 16) | (5 << 24), /* operand = args[i] */
|
||||||
|
DOP_NOOP | (3 << 8) | (3 << 16) | (4 << 24), /* accum = accum op operand */
|
||||||
|
DOP_ADD_IMMEDIATE | (5 << 8) | (5 << 16) | (1 << 24), /* i++ */
|
||||||
|
DOP_EQUALS_INTEGER | (2 << 8) | (5 << 16) | (1 << 24), /* jump? = (i == argn) */
|
||||||
|
DOP_JUMP_IF_NOT | (2 << 8) | ((uint32_t)(-4) << 16), /* if not jump? go back 4 */
|
||||||
|
/* Done, do last and return accumulator */
|
||||||
|
DOP_RETURN | (3 << 8) /* return accum */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VAROP_NULLARY_LOC 3
|
||||||
|
#define VAROP_UNARY_LOC 7
|
||||||
|
#define VAROP_OP_LOC1 9
|
||||||
|
#define VAROP_OP_LOC2 14
|
||||||
|
|
||||||
|
/* Templatize a varop */
|
||||||
|
static void templatize_varop(
|
||||||
|
DstTable *env,
|
||||||
|
int32_t flags,
|
||||||
|
const char *name,
|
||||||
|
int32_t nullary,
|
||||||
|
int32_t unary,
|
||||||
|
uint32_t op) {
|
||||||
|
varop_asm[VAROP_NULLARY_LOC] = SS(DOP_LOAD_INTEGER, 3, nullary);
|
||||||
|
varop_asm[VAROP_UNARY_LOC] = SS(DOP_LOAD_INTEGER, 3, unary);
|
||||||
|
varop_asm[VAROP_OP_LOC1] = SSS(op, 3, 3, 4);
|
||||||
|
varop_asm[VAROP_OP_LOC2] = SSS(op, 3, 3, 4);
|
||||||
|
dst_quick_asm(
|
||||||
|
env,
|
||||||
|
flags | DST_FUNCDEF_FLAG_VARARG,
|
||||||
|
name,
|
||||||
|
0,
|
||||||
|
6,
|
||||||
|
varop_asm,
|
||||||
|
sizeof(varop_asm));
|
||||||
|
}
|
||||||
|
|
||||||
DstTable *dst_stl_env(int flags) {
|
DstTable *dst_stl_env(int flags) {
|
||||||
static uint32_t error_asm[] = {
|
static uint32_t error_asm[] = {
|
||||||
DOP_ERROR
|
DOP_ERROR
|
||||||
@ -125,6 +195,18 @@ DstTable *dst_stl_env(int flags) {
|
|||||||
dst_quick_asm(env, DST_FUN_PUT, "put", 3, 3, put_asm, sizeof(put_asm));
|
dst_quick_asm(env, DST_FUN_PUT, "put", 3, 3, put_asm, sizeof(put_asm));
|
||||||
dst_quick_asm(env, DST_FUN_LENGTH, "length", 1, 1, length_asm, sizeof(length_asm));
|
dst_quick_asm(env, DST_FUN_LENGTH, "length", 1, 1, length_asm, sizeof(length_asm));
|
||||||
|
|
||||||
|
/* Variadic ops */
|
||||||
|
templatize_varop(env, DST_FUN_ADD, "+", 0, 0, DOP_ADD);
|
||||||
|
templatize_varop(env, DST_FUN_SUBTRACT, "-", 0, 0, DOP_SUBTRACT);
|
||||||
|
templatize_varop(env, DST_FUN_MULTIPLY, "*", 1, 1, DOP_MULTIPLY);
|
||||||
|
templatize_varop(env, DST_FUN_DIVIDE, "/", 1, 1, DOP_DIVIDE);
|
||||||
|
templatize_varop(env, DST_FUN_BAND, "&", -1, -1, DOP_BAND);
|
||||||
|
templatize_varop(env, DST_FUN_BOR, "|", 0, 0, DOP_BOR);
|
||||||
|
templatize_varop(env, DST_FUN_BXOR, "^", 0, 0, DOP_BXOR);
|
||||||
|
templatize_varop(env, DST_FUN_LSHIFT, "<<", 1, 1, DOP_SHIFT_LEFT);
|
||||||
|
templatize_varop(env, DST_FUN_RSHIFT, ">>", 1, 1, DOP_SHIFT_RIGHT);
|
||||||
|
templatize_varop(env, DST_FUN_RSHIFTU, ">>>", 1, 1, DOP_SHIFT_RIGHT_UNSIGNED);
|
||||||
|
|
||||||
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
|
dst_env_def(env, "VERSION", dst_cstringv(DST_VERSION));
|
||||||
|
|
||||||
/* Set as gc root */
|
/* Set as gc root */
|
||||||
|
@ -112,6 +112,7 @@ static const DstInstructionDef dst_ops[] = {
|
|||||||
{"lds", DOP_LOAD_SELF},
|
{"lds", DOP_LOAD_SELF},
|
||||||
{"ldt", DOP_LOAD_TRUE},
|
{"ldt", DOP_LOAD_TRUE},
|
||||||
{"ldu", DOP_LOAD_UPVALUE},
|
{"ldu", DOP_LOAD_UPVALUE},
|
||||||
|
{"length", DOP_LENGTH},
|
||||||
{"lt", DOP_LESS_THAN},
|
{"lt", DOP_LESS_THAN},
|
||||||
{"lti", DOP_LESS_THAN_INTEGER},
|
{"lti", DOP_LESS_THAN_INTEGER},
|
||||||
{"ltim", DOP_LESS_THAN_IMMEDIATE},
|
{"ltim", DOP_LESS_THAN_IMMEDIATE},
|
||||||
|
198
src/core/math.c
198
src/core/math.c
@ -72,100 +72,6 @@ int dst_real(DstArgs args) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ADD(x, y) ((x) + (y))
|
|
||||||
#define SUB(x, y) ((x) - (y))
|
|
||||||
#define MUL(x, y) ((x) * (y))
|
|
||||||
#define MOD(x, y) ((x) % (y))
|
|
||||||
#define DIV(x, y) ((x) / (y))
|
|
||||||
|
|
||||||
#define DST_DEFINE_BINOP(name, op, rop, onerr)\
|
|
||||||
Dst dst_op_##name(Dst lhs, Dst rhs) {\
|
|
||||||
if (!(dst_checktype(lhs, DST_INTEGER) || dst_checktype(lhs, DST_REAL))) onerr;\
|
|
||||||
if (!(dst_checktype(rhs, DST_INTEGER) || dst_checktype(rhs, DST_REAL))) onerr;\
|
|
||||||
return dst_checktype(lhs, DST_INTEGER)\
|
|
||||||
? (dst_checktype(rhs, DST_INTEGER)\
|
|
||||||
? dst_wrap_integer(op(dst_unwrap_integer(lhs), dst_unwrap_integer(rhs)))\
|
|
||||||
: dst_wrap_real(rop((double)dst_unwrap_integer(lhs), dst_unwrap_real(rhs))))\
|
|
||||||
: (dst_checktype(rhs, DST_INTEGER)\
|
|
||||||
? dst_wrap_real(rop(dst_unwrap_real(lhs), (double)dst_unwrap_integer(rhs)))\
|
|
||||||
: dst_wrap_real(rop(dst_unwrap_real(lhs), dst_unwrap_real(rhs))));\
|
|
||||||
}
|
|
||||||
|
|
||||||
DST_DEFINE_BINOP(add, ADD, ADD, return dst_wrap_nil())
|
|
||||||
DST_DEFINE_BINOP(subtract, SUB, SUB, return dst_wrap_nil())
|
|
||||||
DST_DEFINE_BINOP(multiply, MUL, MUL, return dst_wrap_nil())
|
|
||||||
|
|
||||||
#define DST_DEFINE_DIVIDER_OP(name, op, rop)\
|
|
||||||
Dst dst_op_##name(Dst lhs, Dst rhs) {\
|
|
||||||
if (!(dst_checktype(lhs, DST_INTEGER) || dst_checktype(lhs, DST_REAL))) return dst_wrap_nil();\
|
|
||||||
if (!(dst_checktype(rhs, DST_INTEGER) || dst_checktype(rhs, DST_REAL))) return dst_wrap_nil();\
|
|
||||||
return dst_checktype(lhs, DST_INTEGER)\
|
|
||||||
? (dst_checktype(rhs, DST_INTEGER)\
|
|
||||||
? (dst_unwrap_integer(rhs) == 0 || ((dst_unwrap_integer(lhs) == INT32_MIN) && (dst_unwrap_integer(rhs) == -1)))\
|
|
||||||
? dst_wrap_nil()\
|
|
||||||
: dst_wrap_integer(op(dst_unwrap_integer(lhs), dst_unwrap_integer(rhs)))\
|
|
||||||
: dst_wrap_real(rop((double)dst_unwrap_integer(lhs), dst_unwrap_real(rhs))))\
|
|
||||||
: (dst_checktype(rhs, DST_INTEGER)\
|
|
||||||
? dst_wrap_real(rop(dst_unwrap_real(lhs), (double)dst_unwrap_integer(rhs)))\
|
|
||||||
: dst_wrap_real(rop(dst_unwrap_real(lhs), dst_unwrap_real(rhs))));\
|
|
||||||
}
|
|
||||||
|
|
||||||
DST_DEFINE_DIVIDER_OP(divide, DIV, DIV)
|
|
||||||
DST_DEFINE_DIVIDER_OP(modulo, MOD, fmod)
|
|
||||||
|
|
||||||
#define DST_DEFINE_REDUCER(name, fop, start)\
|
|
||||||
int dst_##name(DstArgs args) {\
|
|
||||||
int32_t i;\
|
|
||||||
Dst accum = dst_wrap_integer(start);\
|
|
||||||
for (i = 0; i < args.n; i++) {\
|
|
||||||
accum = fop(accum, args.v[i]);\
|
|
||||||
}\
|
|
||||||
if (dst_checktype(accum, DST_NIL)) {\
|
|
||||||
*args.ret = dst_cstringv("expected number");\
|
|
||||||
return 1;\
|
|
||||||
}\
|
|
||||||
*args.ret = accum;\
|
|
||||||
return 0;\
|
|
||||||
}
|
|
||||||
|
|
||||||
DST_DEFINE_REDUCER(add, dst_op_add, 0)
|
|
||||||
DST_DEFINE_REDUCER(multiply, dst_op_multiply, 1)
|
|
||||||
|
|
||||||
#define DST_DEFINE_DIVIDER(name, unarystart)\
|
|
||||||
int dst_##name(DstArgs args) {\
|
|
||||||
int32_t i;\
|
|
||||||
Dst accum;\
|
|
||||||
if (args.n < 1) {\
|
|
||||||
*args.ret = dst_cstringv("expected at least one argument");\
|
|
||||||
return 1;\
|
|
||||||
} else if (args.n == 1) {\
|
|
||||||
accum = unarystart;\
|
|
||||||
i = 0;\
|
|
||||||
} else {\
|
|
||||||
accum = args.v[0];\
|
|
||||||
i = 1;\
|
|
||||||
}\
|
|
||||||
for (; i < args.n; i++) {\
|
|
||||||
accum = dst_op_##name(accum, args.v[i]);\
|
|
||||||
}\
|
|
||||||
if (dst_checktype(accum, DST_NIL)) {\
|
|
||||||
*args.ret = dst_cstringv("expected number or division error");\
|
|
||||||
return 1;\
|
|
||||||
}\
|
|
||||||
*args.ret = accum;\
|
|
||||||
return 0;\
|
|
||||||
}
|
|
||||||
|
|
||||||
DST_DEFINE_DIVIDER(divide, dst_wrap_real(1))
|
|
||||||
DST_DEFINE_DIVIDER(modulo, dst_wrap_real(1))
|
|
||||||
DST_DEFINE_DIVIDER(subtract, dst_wrap_integer(0))
|
|
||||||
|
|
||||||
#undef ADD
|
|
||||||
#undef SUB
|
|
||||||
#undef MUL
|
|
||||||
#undef MOD
|
|
||||||
#undef DST_DEFINE_BINOP
|
|
||||||
|
|
||||||
int dst_bnot(DstArgs args) {
|
int dst_bnot(DstArgs args) {
|
||||||
if (args.n != 1) {
|
if (args.n != 1) {
|
||||||
*args.ret = dst_cstringv("expected 1 argument");
|
*args.ret = dst_cstringv("expected 1 argument");
|
||||||
@ -179,48 +85,20 @@ int dst_bnot(DstArgs args) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DST_DEFINE_BITOP(name, op, start)\
|
int dst_remainder(DstArgs args) {
|
||||||
int dst_##name(DstArgs args) {\
|
|
||||||
int32_t i;\
|
|
||||||
int32_t accum = start;\
|
|
||||||
for (i = 0; i < args.n; i++) {\
|
|
||||||
Dst arg = args.v[i];\
|
|
||||||
if (!dst_checktype(arg, DST_INTEGER)) {\
|
|
||||||
*args.ret = dst_cstringv("expected integer");\
|
|
||||||
return -1;\
|
|
||||||
}\
|
|
||||||
accum op dst_unwrap_integer(arg);\
|
|
||||||
}\
|
|
||||||
*args.ret = dst_wrap_integer(accum);\
|
|
||||||
return 0;\
|
|
||||||
}
|
|
||||||
|
|
||||||
DST_DEFINE_BITOP(band, &=, -1)
|
|
||||||
DST_DEFINE_BITOP(bor, |=, 0)
|
|
||||||
DST_DEFINE_BITOP(bxor, ^=, 0)
|
|
||||||
|
|
||||||
int dst_lshift(DstArgs args) {
|
|
||||||
int32_t lhs, rhs;
|
|
||||||
DST_FIXARITY(args, 2);
|
DST_FIXARITY(args, 2);
|
||||||
DST_ARG_INTEGER(lhs, args, 0);
|
if (dst_checktype(args.v[0], DST_INTEGER) &&
|
||||||
DST_ARG_INTEGER(rhs, args, 1);
|
dst_checktype(args.v[1], DST_INTEGER)) {
|
||||||
DST_RETURN_INTEGER(args, lhs >> rhs);
|
int32_t x, y;
|
||||||
|
x = dst_unwrap_integer(args.v[0]);
|
||||||
|
y = dst_unwrap_integer(args.v[1]);
|
||||||
|
DST_RETURN_INTEGER(args, x % y);
|
||||||
|
} else {
|
||||||
|
double x, y;
|
||||||
|
DST_ARG_NUMBER(x, args, 0);
|
||||||
|
DST_ARG_NUMBER(y, args, 1);
|
||||||
|
DST_RETURN_REAL(args, fmod(x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
int dst_rshift(DstArgs args) {
|
|
||||||
int32_t lhs, rhs;
|
|
||||||
DST_FIXARITY(args, 2);
|
|
||||||
DST_ARG_INTEGER(lhs, args, 0);
|
|
||||||
DST_ARG_INTEGER(rhs, args, 1);
|
|
||||||
DST_RETURN_INTEGER(args, lhs << rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dst_lshiftu(DstArgs args) {
|
|
||||||
int32_t lhs, rhs;
|
|
||||||
DST_FIXARITY(args, 2);
|
|
||||||
DST_ARG_INTEGER(lhs, args, 0);
|
|
||||||
DST_ARG_INTEGER(rhs, args, 1);
|
|
||||||
DST_RETURN_INTEGER(args, (int32_t)((uint32_t)lhs << rhs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DST_DEFINE_MATHOP(name, fop)\
|
#define DST_DEFINE_MATHOP(name, fop)\
|
||||||
@ -337,15 +215,7 @@ DEF_NUMERIC_COMP(eq, ==)
|
|||||||
DEF_NUMERIC_COMP(neq, !=)
|
DEF_NUMERIC_COMP(neq, !=)
|
||||||
|
|
||||||
static const DstReg cfuns[] = {
|
static const DstReg cfuns[] = {
|
||||||
{"random", dst_rand},
|
{"%", dst_remainder},
|
||||||
{"seedrandom", dst_srand},
|
|
||||||
{"int", dst_int},
|
|
||||||
{"real", dst_real},
|
|
||||||
{"+", dst_add},
|
|
||||||
{"-", dst_subtract},
|
|
||||||
{"*", dst_multiply},
|
|
||||||
{"/", dst_divide},
|
|
||||||
{"%", dst_modulo},
|
|
||||||
{"=", dst_strict_equal},
|
{"=", dst_strict_equal},
|
||||||
{"not=", dst_strict_notequal},
|
{"not=", dst_strict_notequal},
|
||||||
{"order<", dst_ascending},
|
{"order<", dst_ascending},
|
||||||
@ -358,27 +228,25 @@ static const DstReg cfuns[] = {
|
|||||||
{">", dst_numeric_gt},
|
{">", dst_numeric_gt},
|
||||||
{"<=", dst_numeric_lte},
|
{"<=", dst_numeric_lte},
|
||||||
{">=", dst_numeric_gte},
|
{">=", dst_numeric_gte},
|
||||||
{"|", dst_bor},
|
|
||||||
{"&", dst_band},
|
|
||||||
{"^", dst_bxor},
|
|
||||||
{"~", dst_bnot},
|
{"~", dst_bnot},
|
||||||
{">>", dst_lshift},
|
|
||||||
{"<<", dst_rshift},
|
|
||||||
{">>>", dst_lshiftu},
|
|
||||||
{"not", dst_not},
|
{"not", dst_not},
|
||||||
{"cos", dst_cos},
|
{"int", dst_int},
|
||||||
{"sin", dst_sin},
|
{"real", dst_real},
|
||||||
{"tan", dst_tan},
|
{"math.random", dst_rand},
|
||||||
{"acos", dst_acos},
|
{"math.seedrandom", dst_srand},
|
||||||
{"asin", dst_asin},
|
{"math.cos", dst_cos},
|
||||||
{"atan", dst_atan},
|
{"math.sin", dst_sin},
|
||||||
{"exp", dst_exp},
|
{"math.tan", dst_tan},
|
||||||
{"log", dst_log},
|
{"math.acos", dst_acos},
|
||||||
{"log10", dst_log10},
|
{"math.asin", dst_asin},
|
||||||
{"sqrt", dst_sqrt},
|
{"math.atan", dst_atan},
|
||||||
{"floor", dst_floor},
|
{"math.exp", dst_exp},
|
||||||
{"ceil", dst_ceil},
|
{"math.log", dst_log},
|
||||||
{"pow", dst_pow},
|
{"math.log10", dst_log10},
|
||||||
|
{"math.sqrt", dst_sqrt},
|
||||||
|
{"math.floor", dst_floor},
|
||||||
|
{"math.ceil", dst_ceil},
|
||||||
|
{"math.pow", dst_pow},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -387,8 +255,8 @@ int dst_lib_math(DstArgs args) {
|
|||||||
DstTable *env = dst_env_arg(args);
|
DstTable *env = dst_env_arg(args);
|
||||||
dst_env_cfuns(env, cfuns);
|
dst_env_cfuns(env, cfuns);
|
||||||
|
|
||||||
dst_env_def(env, "pi", dst_wrap_real(3.1415926535897931));
|
dst_env_def(env, "math.pi", dst_wrap_real(3.1415926535897931));
|
||||||
dst_env_def(env, "e", dst_wrap_real(2.7182818284590451));
|
dst_env_def(env, "math.e", dst_wrap_real(2.7182818284590451));
|
||||||
dst_env_def(env, "inf", dst_wrap_real(INFINITY));
|
dst_env_def(env, "math.inf", dst_wrap_real(INFINITY));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -336,10 +336,10 @@ static void *op_lookup[255] = {
|
|||||||
vm_assert(dst_checktype(op1, DST_INTEGER) || dst_checktype(op1, DST_REAL), "expected number");
|
vm_assert(dst_checktype(op1, DST_INTEGER) || dst_checktype(op1, DST_REAL), "expected number");
|
||||||
vm_assert(dst_checktype(op2, DST_INTEGER) || dst_checktype(op2, DST_REAL), "expected number");
|
vm_assert(dst_checktype(op2, DST_INTEGER) || dst_checktype(op2, DST_REAL), "expected number");
|
||||||
if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == 0)
|
if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == 0)
|
||||||
vm_throw("integer divide error");
|
vm_throw("integer divide by zero");
|
||||||
if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == -1 &&
|
if (dst_checktype(op2, DST_INTEGER) && dst_unwrap_integer(op2) == -1 &&
|
||||||
dst_checktype(op1, DST_INTEGER) && dst_unwrap_integer(op1) == INT32_MIN)
|
dst_checktype(op1, DST_INTEGER) && dst_unwrap_integer(op1) == INT32_MIN)
|
||||||
vm_throw("integer divide error");
|
vm_throw("integer divide out of range");
|
||||||
stack[oparg(1, 0xFF)] = dst_checktype(op1, DST_INTEGER)
|
stack[oparg(1, 0xFF)] = dst_checktype(op1, DST_INTEGER)
|
||||||
? (dst_checktype(op2, DST_INTEGER)
|
? (dst_checktype(op2, DST_INTEGER)
|
||||||
? dst_wrap_integer(dst_unwrap_integer(op1) / dst_unwrap_integer(op2))
|
? dst_wrap_integer(dst_unwrap_integer(op1) / dst_unwrap_integer(op2))
|
||||||
|
@ -35,20 +35,9 @@ int dst_core_native(DstArgs args);
|
|||||||
/* Arithmetic */
|
/* Arithmetic */
|
||||||
int dst_int(DstArgs args);
|
int dst_int(DstArgs args);
|
||||||
int dst_real(DstArgs args);
|
int dst_real(DstArgs args);
|
||||||
int dst_add(DstArgs args);
|
|
||||||
int dst_subtract(DstArgs args);
|
|
||||||
int dst_multiply(DstArgs args);
|
|
||||||
int dst_divide(DstArgs args);
|
|
||||||
int dst_modulo(DstArgs args);
|
|
||||||
int dst_rand(DstArgs args);
|
int dst_rand(DstArgs args);
|
||||||
int dst_srand(DstArgs args);
|
int dst_srand(DstArgs args);
|
||||||
int dst_bor(DstArgs args);
|
int dst_remainder(DstArgs args);
|
||||||
int dst_band(DstArgs args);
|
|
||||||
int dst_bxor(DstArgs args);
|
|
||||||
int dst_bnot(DstArgs args);
|
|
||||||
int dst_lshift(DstArgs args);
|
|
||||||
int dst_rshift(DstArgs args);
|
|
||||||
int dst_lshiftu(DstArgs args);
|
|
||||||
|
|
||||||
/* Math */
|
/* Math */
|
||||||
int dst_cos(DstArgs args);
|
int dst_cos(DstArgs args);
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
(struct 1 2 3 4)
|
(struct 1 2 3 4)
|
||||||
(buffer "hi")
|
(buffer "hi")
|
||||||
(fn [x] (+ x x))
|
(fn [x] (+ x x))
|
||||||
+) "type ordering")
|
print) "type ordering")
|
||||||
|
|
||||||
(assert (= (string (buffer "123" "456")) (string @"123456")) "buffer literal")
|
(assert (= (string (buffer "123" "456")) (string @"123456")) "buffer literal")
|
||||||
(assert (= (get {} 1) nil) "get nil from empty struct")
|
(assert (= (get {} 1) nil) "get nil from empty struct")
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
(import test.helper :prefix "" :exit true)
|
(import test.helper :prefix "" :exit true)
|
||||||
(start-suite 1)
|
(start-suite 1)
|
||||||
|
|
||||||
(assert (= 400.0 (sqrt 160000)) "sqrt(160000)=400")
|
(assert (= 400.0 (math.sqrt 160000)) "sqrt(160000)=400")
|
||||||
(assert (= (real 400) (sqrt 160000)) "sqrt(160000)=400")
|
(assert (= (real 400) (math.sqrt 160000)) "sqrt(160000)=400")
|
||||||
|
|
||||||
(def test-struct {'def 1 'bork 2 'sam 3 'a 'b 'het @[1 2 3 4 5]})
|
(def test-struct {'def 1 'bork 2 'sam 3 'a 'b 'het @[1 2 3 4 5]})
|
||||||
(assert (= (get test-struct 'def) 1) "struct get")
|
(assert (= (get test-struct 'def) 1) "struct get")
|
||||||
@ -47,7 +47,7 @@
|
|||||||
(:= good false)))
|
(:= good false)))
|
||||||
(assert good e))
|
(assert good e))
|
||||||
|
|
||||||
(assert-many (fn [] (>= 1 (random) 0)) 200 "(random) between 0 and 1")
|
(assert-many (fn [] (>= 1 (math.random) 0)) 200 "(random) between 0 and 1")
|
||||||
|
|
||||||
## Table prototypes
|
## Table prototypes
|
||||||
|
|
||||||
@ -167,4 +167,16 @@
|
|||||||
(def f (compile (tuple.prepend manydefs 'do) *env*))
|
(def f (compile (tuple.prepend manydefs 'do) *env*))
|
||||||
(assert (= (f) (* 10000 3 5 7 9)) "long function compilation")
|
(assert (= (f) (* 10000 3 5 7 9)) "long function compilation")
|
||||||
|
|
||||||
|
# Some higher order functions and macros
|
||||||
|
|
||||||
|
(def my-array @[1 2 3 4 5 6])
|
||||||
|
(def x (if-let [x (get my-array 5)] x))
|
||||||
|
(assert (= x 6) "if-let")
|
||||||
|
(def x (if-let [y (get @{} :key)] 10 nil))
|
||||||
|
(assert (not x) "if-let 2")
|
||||||
|
|
||||||
|
(assert (= 14 (sum (map inc @[1 2 3 4]))) "sum map")
|
||||||
|
(def myfun (juxt + - * /))
|
||||||
|
(assert (= '[2 -2 2 0] (myfun 2)) "juxt")
|
||||||
|
|
||||||
(end-suite)
|
(end-suite)
|
||||||
|
Loading…
Reference in New Issue
Block a user