|
@@ -1529,9 +1529,12 @@ node_t *parse_block(list_t *tokens, size_t *pos) {
|
|
|
EXPECT(LCB, "{");
|
|
|
|
|
|
list_t *stmts = list_new();
|
|
|
- while (!AT(EOF) && !AT(RCB))
|
|
|
+ while (!AT(EOF) && !AT(RCB)) {
|
|
|
list_push(stmts, parse_stmt(tokens, pos));
|
|
|
|
|
|
+ MATCH(SEMI);
|
|
|
+ }
|
|
|
+
|
|
|
EXPECT(RCB, "}");
|
|
|
|
|
|
return NODEL(PROGRAM, stmts);
|
|
@@ -2504,9 +2507,67 @@ const char *STD[][2] = {
|
|
|
"func is_char(c): return type(c) == \"string\" && len(c) == 1\n"
|
|
|
},
|
|
|
|
|
|
+ {"math", NULL},
|
|
|
+
|
|
|
{NULL, NULL}
|
|
|
};
|
|
|
|
|
|
+const struct {
|
|
|
+ const char *name;
|
|
|
+ const char *fname;
|
|
|
+ int arity;
|
|
|
+} MATHFUNCS[] = {
|
|
|
+ { "ceil", NULL, 1 },
|
|
|
+ { "floor", NULL, 1 },
|
|
|
+ { "trunc", NULL, 1 },
|
|
|
+ { "round", NULL, 1 },
|
|
|
+ { "abs", "fabs", 1 },
|
|
|
+ { "exp", NULL, 1 },
|
|
|
+ { "sqrt", NULL, 1 },
|
|
|
+ { "sinh", NULL, 1 },
|
|
|
+ { "cosh", NULL, 1 },
|
|
|
+ { "tanh", NULL, 1 },
|
|
|
+ { "asinh", NULL, 1 },
|
|
|
+ { "acosh", NULL, 1 },
|
|
|
+ { "atanh", NULL, 1 },
|
|
|
+ { "sin", NULL, 1 },
|
|
|
+ { "cos", NULL, 1 },
|
|
|
+ { "tan", NULL, 1 },
|
|
|
+ { "asin", NULL, 1 },
|
|
|
+ { "acos", NULL, 1 },
|
|
|
+ { "atan", NULL, 1 },
|
|
|
+ { "atan2", NULL, 2 },
|
|
|
+ { "hypot", NULL, 2 },
|
|
|
+ { "random", "rand", 0 },
|
|
|
+
|
|
|
+ { NULL, 0 }
|
|
|
+};
|
|
|
+
|
|
|
+void genmathlib(void) {
|
|
|
+ buffer_t *buffer = buffer_new();
|
|
|
+
|
|
|
+ buffer_appends(buffer, "let Math = {\"tau\": 6.283185307179586, \"pi\": 3.141592653589793, \"e\": 2.718281828459045, \"inf\": INFINITY, \"nan\": NAN, ");
|
|
|
+
|
|
|
+ for (size_t i = 0; MATHFUNCS[i].name; i++) {
|
|
|
+ if (MATHFUNCS[i].arity == 0)
|
|
|
+ buffer_fmt(buffer, "\"%s\": func () { inline `return qi_make_number(state, %s())` }", MATHFUNCS[i].name, MATHFUNCS[i].fname? MATHFUNCS[i].fname: MATHFUNCS[i].name);
|
|
|
+ else if (MATHFUNCS[i].arity == 1)
|
|
|
+ buffer_fmt(buffer, "\"%s\": func (x) { if type(x) != \"number\" { throw \"expected first argument to be: number, but got: \" + type(x) } inline `double n = %s(qi_get(state, \"x\")->value.number)`; inline `return qi_make_number(state, n)` }", MATHFUNCS[i].name, MATHFUNCS[i].fname? MATHFUNCS[i].fname: MATHFUNCS[i].name);
|
|
|
+ else
|
|
|
+ buffer_fmt(buffer, "\"%s\": func (x, y) { if type(x) != \"number\" { throw \"expected first argument to be: number, but got: \" + type(x) } if type(y) != \"number\" { throw \"expected second argument to be: number, but got: \" + type(y) } inline `double n = %s(qi_get(state, \"x\")->value.number, qi_get(state, \"y\")->value.number)`; inline `return qi_make_number(state, n)` }", MATHFUNCS[i].name, MATHFUNCS[i].fname? MATHFUNCS[i].fname: MATHFUNCS[i].name);
|
|
|
+
|
|
|
+ if (MATHFUNCS[i + 1].name)
|
|
|
+ buffer_append(buffer, ',');
|
|
|
+ }
|
|
|
+
|
|
|
+ buffer_append(buffer, '}');
|
|
|
+
|
|
|
+ size_t i;
|
|
|
+ for (i = 0; strcmp(STD[i][0], "math") != 0; i++) ;
|
|
|
+
|
|
|
+ STD[i][1] = buffer_read(buffer);
|
|
|
+}
|
|
|
+
|
|
|
char *unescape(char *s) {
|
|
|
buffer_t *buf = buffer_new();
|
|
|
|
|
@@ -3173,6 +3234,8 @@ int main(int argc, char **argv) {
|
|
|
REQUIRED = list_new();
|
|
|
CONSTANTS = table_new();
|
|
|
|
|
|
+ genmathlib();
|
|
|
+
|
|
|
char *out = compile_file("<stdin>", stdin);
|
|
|
|
|
|
fwrite(out, sizeof(char), strlen(out), stdout);
|