Skip to content

Commit ea7e604

Browse files
committed
Variadic primitive functions
1 parent d08decb commit ea7e604

File tree

1 file changed

+99
-55
lines changed

1 file changed

+99
-55
lines changed

src/virtual-machines/source-2.js

Lines changed: 99 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ const JOF = 17; // followed by: jump address
279279
const GOTO = 18; // followed by: jump address
280280
const LDF = 19; // followed by: max_stack_size, address, env extensn count
281281
const CALL = 20;
282-
const CALLP = 21;
282+
const CALLVAR = 21;
283283
const LD = 22; // followed by: index of value in environment
284+
const LDV = 23;
284285
const LDNULL = 26;
285286
const RTN = 27;
286287
const DONE = 28;
@@ -295,7 +296,7 @@ const primitives = list(
295296
list("IS_NUM ", 43, is_number , "is_number" , list("any"), "bool"),
296297
list("IS_PAIR", 44, is_pair , "is_pair" , list("any"), "bool"),
297298
list("IS_NULL", 45, is_null , "is_null" , list("any"), "bool"),
298-
list("DISPLAY", 46, display , "display" , list("any"), "undefined"),
299+
list("DISPLAY", 46, display , "display" , list("var"), "undefined"),
299300
list("ERROR ", 47, error , "error" , list("any"), "undefined"),
300301
list("RANDOM ", 48, math_random, "math_random", null, "num"),
301302
list("ABS ", 49, math_abs , "math_abs" , list("num"), "num"),
@@ -328,9 +329,13 @@ const primitives = list(
328329
list("TRUNC ", 76, math_trunc , "math_trunc" , list("num"), "num"),
329330
list("ATAN2 ", 77, math_atan2 , "math_atan2" , list("num", "num"), "num"),
330331
list("IMUL ", 78, math_imul , "math_imul" , list("num", "num"), "num"),
331-
list("POW ", 79, math_pow , "math_pow" , list("num", "num"), "num")
332-
// list("MAX ", 66, math_max , "math_max" , list("var"), "num"),
333-
// list("MIN ", 67, math_min , "math_min" , list("var"), "num")
332+
list("POW ", 79, math_pow , "math_pow" , list("num", "num"), "num"),
333+
list("MAX ", 80, math_max , "math_max" , list("var"), "num"),
334+
list("MIN ", 81, math_min , "math_min" , list("var"), "num"),
335+
list("HYPOT ", 82, math_hypot , "math_hypot" , list("var"), "num"),
336+
list("RUNTIME", 83, runtime , "runtime" , null, "num"),
337+
list("STRINGI", 84, stringify , "stringify" , list("num"), "str")
338+
// list("PROMPT ", 84, prompt , "prompt" , null, "string")
334339
);
335340

336341
// auxiliary functions for injected primitive functions
@@ -362,6 +367,12 @@ function lookup_injected_prim_func_by_string(name) {
362367
}
363368
return lookup(primitives);
364369
}
370+
function is_variadic_function(name) {
371+
// only checks injected primitive
372+
return is_injected_primitive(name) &&
373+
!is_null(member("var",
374+
injected_prim_func_ops_types(lookup_injected_prim_func_by_string(name))));
375+
}
365376
// generate code snippet for primitive function
366377
// to register them in the program
367378
// takes on the form
@@ -423,8 +434,9 @@ const OPCODES = append(
423434
pair(GOTO, "GOTO "),
424435
pair(LDF, "LDF "),
425436
pair(CALL, "CALL "),
426-
pair(CALLP, "CALLP "),
437+
pair(CALLVAR, "CALLVAR"),
427438
pair(LD, "LD "),
439+
pair(LDV, "LDV "),
428440
pair(LDNULL, "LDNULL "),
429441
pair(RTN, "RTN "),
430442
pair(DONE, "DONE ")
@@ -711,7 +723,11 @@ function parse_and_compile(string) {
711723
index_table, false);
712724
const max_stack_operands = compile_arguments(operands(expr),
713725
index_table);
714-
add_unary_instruction(CALL, length(operands(expr)));
726+
if (is_variadic_function(name_of_name(operator(expr)))) {
727+
add_unary_instruction(CALLVAR, length(operands(expr)));
728+
} else {
729+
add_unary_instruction(CALL, length(operands(expr)));
730+
}
715731
return math_max(max_stack_operator, max_stack_operands + 1);
716732
}
717733

@@ -775,8 +791,12 @@ function parse_and_compile(string) {
775791
const entry = lookup_injected_prim_func_by_string(name);
776792
const ops_types = injected_prim_func_ops_types(entry);
777793
const OP = injected_prim_func_opcode(entry);
778-
for (let i = length(ops_types) - 1; i >= 0; i = i - 1) {
779-
add_unary_instruction(LD, index_of(index_table, "x" + stringify(i)));
794+
if (is_variadic_function(name)) {
795+
add_nullary_instruction(LDV);
796+
} else {
797+
for (let i = length(ops_types) - 1; i >= 0; i = i - 1) {
798+
add_unary_instruction(LD, index_of(index_table, "x" + stringify(i)));
799+
}
780800
}
781801
add_nullary_instruction(OP);
782802
return 1;
@@ -860,7 +880,7 @@ function parse_and_compile(string) {
860880
}
861881

862882
// primitive functions according to source 2 specifications
863-
// TODO: variadic functions: math_hypot, math_max, math_min, list etc.
883+
// TODO: variadic functions: math_hypot, list etc.
864884
const math_consts = "\
865885
const math_E = 2.718281828459045;\
866886
const math_LN10 = 2.302585092994046;\
@@ -1567,7 +1587,6 @@ M[TIMES] = () => { POP_OS();
15671587
M[EQUAL] = () => { POP_OS();
15681588
A = HEAP[RES + NUMBER_VALUE_SLOT];
15691589
POP_OS();
1570-
show_registers("");
15711590
A = HEAP[RES + NUMBER_VALUE_SLOT] === A;
15721591
NEW_BOOL();
15731592
A = RES;
@@ -1671,6 +1690,15 @@ M[LD] = () => { A = HEAP[ENV + HEAP[ENV + FIRST_CHILD_SLOT]
16711690
PC = PC + 2;
16721691
};
16731692

1693+
M[LDV] = () => { E = HEAP[OS + SIZE_SLOT] - 4; // get the number of arguments
1694+
C = ENV + HEAP[ENV + SIZE_SLOT] - 1; // addr of last argument
1695+
for (D = 0; D < E; D = D + 1) {
1696+
A = HEAP[C - D];
1697+
PUSH_OS();
1698+
}
1699+
PC = PC + 1;
1700+
};
1701+
16741702
M[CALL] = () => { G = P[PC + 1]; // lets keep number of arguments in G
16751703
// we peek down OS to get the closure
16761704
F = HEAP[OS + HEAP[OS + LAST_CHILD_SLOT] - G];
@@ -1700,35 +1728,34 @@ M[CALL] = () => { G = P[PC + 1]; // lets keep number of arguments in G
17001728
ENV = E;
17011729
};
17021730

1703-
// M[CALLP] = () => { G = P[PC + 1]; // lets keep number of arguments in G
1704-
// H = P[PC + 2]; // keep the opcode to call in H
1705-
// // we peek down OS to get the closure
1706-
// F = HEAP[OS + HEAP[OS + LAST_CHILD_SLOT] - G];
1707-
// // prep for EXTEND
1708-
// A = HEAP[F + CLOSURE_ENV_SLOT];
1709-
// // A is now env to be extended
1710-
// H = HEAP[A + LAST_CHILD_SLOT];
1711-
// // H is now offset of last child slot
1712-
// B = HEAP[F + CLOSURE_ENV_EXTENSION_COUNT_SLOT];
1713-
// // B is now the environment extension count
1714-
// EXTEND(); // after this, RES is new env
1715-
// E = RES;
1716-
// H = E + H + G;
1717-
// // H is now address where last argument goes in new env
1718-
// for (C = H; C > H - G; C = C - 1) {
1719-
// POP_OS(); // now RES has the address of the next arg
1720-
// HEAP[C] = RES; // copy argument into new env
1721-
// }
1722-
// POP_OS(); // closure is on top of OS; pop it as not needed
1723-
// NEW_RTS_FRAME(); // saves PC+2, ENV, OS
1724-
// A = RES;
1725-
// PUSH_RTS();
1726-
// PC = HEAP[F + CLOSURE_ADDRESS_SLOT];
1727-
// A = HEAP[F + CLOSURE_OS_SIZE_SLOT]; // closure stack size
1728-
// NEW_OS(); // uses B and C
1729-
// OS = RES;
1730-
// ENV = E;
1731-
// };
1731+
M[CALLVAR] = () => { G = P[PC + 1]; // lets keep number of arguments in G
1732+
// we peek down OS to get the closure
1733+
F = HEAP[OS + HEAP[OS + LAST_CHILD_SLOT] - G];
1734+
// prep for EXTEND
1735+
A = HEAP[F + CLOSURE_ENV_SLOT];
1736+
// A is now env to be extended
1737+
H = HEAP[A + LAST_CHILD_SLOT];
1738+
// H is now offset of last child slot
1739+
B = HEAP[F + CLOSURE_ENV_EXTENSION_COUNT_SLOT] + G - 1;
1740+
// B is now the environment extension count
1741+
EXTEND(); // after this, RES is new env
1742+
E = RES;
1743+
H = E + H + G;
1744+
// H is now address where last argument goes in new env
1745+
for (C = H; C > H - G; C = C - 1) {
1746+
POP_OS(); // now RES has the address of the next arg
1747+
HEAP[C] = RES; // copy argument into new env
1748+
}
1749+
POP_OS(); // closure is on top of OS; pop it as not needed
1750+
NEW_RTS_FRAME(); // saves PC+2, ENV, OS
1751+
A = RES;
1752+
PUSH_RTS();
1753+
PC = HEAP[F + CLOSURE_ADDRESS_SLOT];
1754+
A = HEAP[F + CLOSURE_OS_SIZE_SLOT] + G - 1; // closure stack size
1755+
NEW_OS(); // uses B and C
1756+
OS = RES;
1757+
ENV = E;
1758+
};
17321759

17331760
M[LDNULL] = () => { NEW_NULL();
17341761
A = RES;
@@ -1758,7 +1785,7 @@ function insert_primitive(p) {
17581785
const ops_types = injected_prim_func_ops_types(p);
17591786
const rtn_type = injected_prim_func_return_type(p);
17601787
M[OP] = () => {
1761-
// gets arguments based on list of types
1788+
// handle special cases of primitives
17621789
if (injected_prim_func_string(p) === "is_pair") {
17631790
POP_OS(); // get address of the node being tested
17641791
A = HEAP[RES + TAG_SLOT] === PAIR_TAG;
@@ -1774,22 +1801,39 @@ function insert_primitive(p) {
17741801
POP_OS();
17751802
RES = HEAP[RES + TAIL_VALUE_SLOT];
17761803
} else {
1777-
const args =
1778-
map(x => {
1779-
if (x === "num") {
1780-
POP_OS(); // get number node and extract value
1781-
return HEAP[RES + NUMBER_VALUE_SLOT];
1782-
} else if (x === "addr") {
1783-
POP_OS(); // get address of the node and return
1784-
return RES;
1785-
} else {}
1786-
},
1787-
ops_types);
1788-
A = apply_in_underlying_javascript(f, args);
1804+
if (is_variadic_function(injected_prim_func_string(p))) {
1805+
const num_of_args = HEAP[OS + SIZE_SLOT] - 4;
1806+
let args = null;
1807+
for (C = 0; C < num_of_args; C = C + 1) {
1808+
POP_OS();
1809+
args = pair(HEAP[RES + NUMBER_VALUE_SLOT], args);
1810+
}
1811+
A = apply_in_underlying_javascript(f, reverse(args));
1812+
} else {
1813+
// gets arguments based on list of types
1814+
const args =
1815+
map(x => {
1816+
if (x === "num") {
1817+
POP_OS(); // get number node and extract value
1818+
return HEAP[RES + NUMBER_VALUE_SLOT];
1819+
} else if (x === "str") {
1820+
POP_OS();
1821+
return HEAP[RES + STRING_VALUE_SLOT];
1822+
} else if (x === "addr") {
1823+
POP_OS(); // get address of the node and return
1824+
return RES;
1825+
} else {
1826+
}
1827+
},
1828+
ops_types);
1829+
A = apply_in_underlying_javascript(f, args);
1830+
}
17891831
if (rtn_type === "num") {
17901832
NEW_NUMBER();
17911833
} else if (rtn_type === "bool") {
17921834
NEW_BOOL();
1835+
} else if (rtn_type === "str") {
1836+
NEW_STRING();
17931837
} else if (rtn_type === "pair") {
17941838
B = tail(A);
17951839
A = head(A);
@@ -1866,8 +1910,8 @@ run();
18661910
// run();
18671911

18681912
P = parse_and_compile("\
1869-
function foo() { return pair;}\
1870-
foo()(1, 2);\
1913+
stringify(1000000000000000000000000000000000000000000000000000000);\
1914+
\
18711915
");
18721916
print_program(P);
18731917
run();

0 commit comments

Comments
 (0)