mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +00:00
Add variadic arithmetic special forms
This commit is contained in:
parent
0d066d8754
commit
40b52dbe70
128
compile.c
128
compile.c
@ -470,35 +470,47 @@ static void tracker_init_tuple(GstCompiler *c, FormOptions opts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Define some flags for operators */
|
||||||
|
#define OP_REVERSE 1
|
||||||
|
#define OP_FOLD 2
|
||||||
|
#define OP_DEFAULT_INT 4
|
||||||
|
#define OP_1_REPEAT 8
|
||||||
|
#define OP_1_BOOLEAN 16
|
||||||
|
#define OP_0_BOOLEAN 32
|
||||||
|
|
||||||
/* Compile a special form in the form of an operator. There
|
/* Compile a special form in the form of an operator. There
|
||||||
* are four choices for opcodes - when the operator is called
|
* are four choices for opcodes - when the operator is called
|
||||||
* with 0, 1, 2, or n arguments. When the operator form is
|
* with 0, 1, 2, or n arguments. When the operator form is
|
||||||
* called with n arguments, the number of arguments is written
|
* called with n arguments, the number of arguments is written
|
||||||
* after the op code, followed by those arguments.
|
* after the op code, followed by those arguments.
|
||||||
*
|
*
|
||||||
* This makes a few assumptions about the operators. One, no side
|
* This function also takes flags to modify the behavior of the operators
|
||||||
* effects. With this assumptions, if the result of the operator
|
* And give them capabilities beyond binary and unary operator. */
|
||||||
* is unused, it's calculation can be ignored (the evaluation of
|
|
||||||
* its argument is still carried out, but their results can
|
|
||||||
* also be ignored). */
|
|
||||||
static Slot compile_operator(GstCompiler *c, FormOptions opts, GstValue *form,
|
static Slot compile_operator(GstCompiler *c, FormOptions opts, GstValue *form,
|
||||||
int16_t op0, int16_t op1, int16_t op2, int16_t opn, int reverseOperands) {
|
int16_t op0, int16_t op1, int16_t op2, int16_t opn, int flags) {
|
||||||
GstScope *scope = c->tail;
|
GstScope *scope = c->tail;
|
||||||
GstBuffer *buffer = c->buffer;
|
GstBuffer *buffer = c->buffer;
|
||||||
Slot ret;
|
Slot ret;
|
||||||
SlotTracker tracker;
|
SlotTracker tracker;
|
||||||
uint32_t count = gst_tuple_length(form);
|
uint32_t count = gst_tuple_length(form);
|
||||||
/* Compile operands */
|
/* Check for some early exit conditions */
|
||||||
tracker_init_tuple(c, opts, &tracker, form, 1, 0);
|
if (count == 2 && (flags & OP_1_REPEAT)) {
|
||||||
/* Free up space */
|
return compile_value(c, opts, form[1]);
|
||||||
compiler_tracker_free(c, scope, &tracker);
|
}
|
||||||
if (opts.resultUnused) {
|
if (opts.resultUnused) {
|
||||||
ret = nil_slot();
|
ret = nil_slot();
|
||||||
} else {
|
} else {
|
||||||
ret = compiler_get_target(c, opts);
|
ret = compiler_get_target(c, opts);
|
||||||
/* Write the correct opcode */
|
/* Write the correct opcode */
|
||||||
if (count < 2) {
|
if (count < 2) {
|
||||||
if (op0 < 0) {
|
if (flags & OP_DEFAULT_INT) {
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, GST_OP_I16);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
gst_buffer_push_i16(c->vm, buffer, op0);
|
||||||
|
} else if (flags & OP_0_BOOLEAN) {
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, op0 ? GST_OP_TRU : GST_OP_FLS);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
} else if (op0 < 0) {
|
||||||
if (opn < 0) c_error(c, "this operator does not take 0 arguments");
|
if (opn < 0) c_error(c, "this operator does not take 0 arguments");
|
||||||
goto opn;
|
goto opn;
|
||||||
} else {
|
} else {
|
||||||
@ -506,72 +518,88 @@ static Slot compile_operator(GstCompiler *c, FormOptions opts, GstValue *form,
|
|||||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
}
|
}
|
||||||
} else if (count == 2) {
|
} else if (count == 2) {
|
||||||
if (op1 < 0) {
|
if (flags & OP_1_BOOLEAN) {
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, op1 ? GST_OP_TRU : GST_OP_FLS);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
return ret;
|
||||||
|
} else if (op1 < 0) {
|
||||||
if (opn < 0) c_error(c, "this operator does not take 1 argument");
|
if (opn < 0) c_error(c, "this operator does not take 1 argument");
|
||||||
goto opn;
|
goto opn;
|
||||||
} else {
|
} else {
|
||||||
|
tracker_init_tuple(c, opts, &tracker, form, 1, 0);
|
||||||
|
compiler_tracker_free(c, scope, &tracker);
|
||||||
gst_buffer_push_u16(c->vm, buffer, op1);
|
gst_buffer_push_u16(c->vm, buffer, op1);
|
||||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
compiler_tracker_write(c, &tracker, flags & OP_REVERSE);
|
||||||
}
|
}
|
||||||
} else if (count == 3) {
|
} else if (count == 3) {
|
||||||
if (op2 < 0) {
|
if (op2 < 0) {
|
||||||
if (opn < 0) c_error(c, "this operator does not take 2 arguments");
|
if (opn < 0) c_error(c, "this operator does not take 2 arguments");
|
||||||
goto opn;
|
goto opn;
|
||||||
} else {
|
} else {
|
||||||
|
tracker_init_tuple(c, opts, &tracker, form, 1, 0);
|
||||||
|
compiler_tracker_free(c, scope, &tracker);
|
||||||
gst_buffer_push_u16(c->vm, buffer, op2);
|
gst_buffer_push_u16(c->vm, buffer, op2);
|
||||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
compiler_tracker_write(c, &tracker, flags & OP_REVERSE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
opn:
|
opn:
|
||||||
|
/* Use a left-fold for arithmetic operators */
|
||||||
|
if (flags & OP_FOLD) {
|
||||||
|
uint32_t i;
|
||||||
|
FormOptions subOpts = form_options_default();
|
||||||
|
Slot lhs = compile_value(c, subOpts, form[1]);
|
||||||
|
Slot rhs = compile_value(c, subOpts, form[2]);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, op2);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, lhs.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, rhs.index);
|
||||||
|
compiler_drop_slot(c, scope, lhs);
|
||||||
|
compiler_drop_slot(c, scope, rhs);
|
||||||
|
for (i = 3; i < count; ++i) {
|
||||||
|
rhs = compile_value(c, subOpts, form[i]);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, op2);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, rhs.index);
|
||||||
|
compiler_drop_slot(c, scope, rhs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (opn < 0) c_error(c, "this operator does not take n arguments");
|
if (opn < 0) c_error(c, "this operator does not take n arguments");
|
||||||
|
tracker_init_tuple(c, opts, &tracker, form, 1, 0);
|
||||||
|
compiler_tracker_free(c, scope, &tracker);
|
||||||
gst_buffer_push_u16(c->vm, buffer, opn);
|
gst_buffer_push_u16(c->vm, buffer, opn);
|
||||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
gst_buffer_push_u16(c->vm, buffer, count - 1);
|
gst_buffer_push_u16(c->vm, buffer, count - 1);
|
||||||
|
compiler_tracker_write(c, &tracker, flags & OP_REVERSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Write the location of all of the arguments */
|
|
||||||
compiler_tracker_write(c, &tracker, reverseOperands);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Math specials */
|
/* Quickly define some specials */
|
||||||
static Slot compile_addition(GstCompiler *c, FormOptions opts, GstValue *form) {
|
#define MAKE_SPECIAL(name, op0, op1, op2, opn, flags) \
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_ADD, -1, 0);
|
static Slot compile_##name (GstCompiler *c, FormOptions opts, GstValue *form) {\
|
||||||
}
|
return compile_operator(c, opts, form, (op0), (op1), (op2), (opn), (flags));\
|
||||||
static Slot compile_subtraction(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_SUB, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_multiplication(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_MUL, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_division(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_DIV, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_equals(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_EQL, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_lt(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_LTN, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_lte(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_LTE, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_gt(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_LTN, -1, 1);
|
|
||||||
}
|
|
||||||
static Slot compile_gte(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_LTE, -1, 1);
|
|
||||||
}
|
|
||||||
static Slot compile_not(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, GST_OP_NOT, -1, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_get(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, GST_OP_GET, -1, 0);
|
|
||||||
}
|
|
||||||
static Slot compile_make_tuple(GstCompiler *c, FormOptions opts, GstValue *form) {
|
|
||||||
return compile_operator(c, opts, form, -1, -1, -1, GST_OP_TUP, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MAKE_SPECIAL(addition, 0, -1, GST_OP_ADD, -1, OP_FOLD | OP_DEFAULT_INT | OP_1_REPEAT)
|
||||||
|
MAKE_SPECIAL(subtraction, 0, GST_OP_NEG, GST_OP_SUB, -1, OP_FOLD | OP_DEFAULT_INT)
|
||||||
|
MAKE_SPECIAL(multiplication, 1, -1, GST_OP_MUL, -1, OP_FOLD | OP_DEFAULT_INT | OP_1_REPEAT)
|
||||||
|
MAKE_SPECIAL(division, 1, GST_OP_INV, GST_OP_DIV, -1, OP_FOLD | OP_DEFAULT_INT)
|
||||||
|
MAKE_SPECIAL(equals, 1, 1, GST_OP_EQL, -1, OP_0_BOOLEAN | OP_1_BOOLEAN)
|
||||||
|
MAKE_SPECIAL(lt, 1, 1, GST_OP_LTN, -1, OP_0_BOOLEAN | OP_1_BOOLEAN)
|
||||||
|
MAKE_SPECIAL(lte, 1, 1, GST_OP_LTE, -1, OP_0_BOOLEAN | OP_1_BOOLEAN)
|
||||||
|
MAKE_SPECIAL(gt, 1, 1, GST_OP_LTN, -1, OP_0_BOOLEAN | OP_1_BOOLEAN | OP_REVERSE)
|
||||||
|
MAKE_SPECIAL(gte, 1, 1, GST_OP_LTE, -1, OP_0_BOOLEAN | OP_1_BOOLEAN | OP_REVERSE)
|
||||||
|
MAKE_SPECIAL(not, -1, GST_OP_NOT, -1, -1, 0)
|
||||||
|
MAKE_SPECIAL(get, -1, -1, GST_OP_GET, -1, 0)
|
||||||
|
MAKE_SPECIAL(make_tuple, -1, -1, -1, GST_OP_TUP, 0)
|
||||||
|
|
||||||
|
#undef MAKE_SPECIAL
|
||||||
|
|
||||||
/* Associative set */
|
/* Associative set */
|
||||||
static Slot compile_set(GstCompiler *c, FormOptions opts, GstValue *form) {
|
static Slot compile_set(GstCompiler *c, FormOptions opts, GstValue *form) {
|
||||||
GstBuffer *buffer = c->buffer;
|
GstBuffer *buffer = c->buffer;
|
||||||
|
@ -216,7 +216,9 @@ enum GstOpCode {
|
|||||||
GST_OP_IDV, /* Integer division */
|
GST_OP_IDV, /* Integer division */
|
||||||
GST_OP_EXP, /* Exponentiation */
|
GST_OP_EXP, /* Exponentiation */
|
||||||
GST_OP_CCT, /* Concatenation */
|
GST_OP_CCT, /* Concatenation */
|
||||||
GST_OP_NOT, /* Invert */
|
GST_OP_NOT, /* Boolean invert */
|
||||||
|
GST_OP_NEG, /* Unary negation */
|
||||||
|
GST_OP_INV, /* Unary multiplicative inverse */
|
||||||
GST_OP_LEN, /* Length */
|
GST_OP_LEN, /* Length */
|
||||||
GST_OP_TYP, /* Type */
|
GST_OP_TYP, /* Type */
|
||||||
GST_OP_FLS, /* Load false */
|
GST_OP_FLS, /* Load false */
|
||||||
|
5
macros.gst
Normal file
5
macros.gst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Some basic macros
|
||||||
|
|
||||||
|
(defmacro for [bindings ...]
|
||||||
|
|
||||||
|
)
|
18
vm.c
18
vm.c
@ -111,6 +111,24 @@ int gst_start(Gst *vm) {
|
|||||||
pc += 3;
|
pc += 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GST_OP_NEG: /* Unary negation */
|
||||||
|
v1 = stack[pc[2]];
|
||||||
|
gst_assert(vm, v1.type == GST_NUMBER, GST_EXPECTED_NUMBER_LOP);
|
||||||
|
temp.type = GST_NUMBER;
|
||||||
|
temp.data.number = -v1.data.number;
|
||||||
|
stack[pc[1]] = temp;
|
||||||
|
pc += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_OP_INV: /* Unary multiplicative inverse */
|
||||||
|
v1 = stack[pc[2]];
|
||||||
|
gst_assert(vm, v1.type == GST_NUMBER, GST_EXPECTED_NUMBER_LOP);
|
||||||
|
temp.type = GST_NUMBER;
|
||||||
|
temp.data.number = 1 / v1.data.number;
|
||||||
|
stack[pc[1]] = temp;
|
||||||
|
pc += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
case GST_OP_FLS: /* Load False */
|
case GST_OP_FLS: /* Load False */
|
||||||
temp.type = GST_BOOLEAN;
|
temp.type = GST_BOOLEAN;
|
||||||
temp.data.boolean = 0;
|
temp.data.boolean = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user