|
@@ -320,6 +320,8 @@ typedef struct {
|
|
T_STARASSIGN,
|
|
T_STARASSIGN,
|
|
T_SLASHSLASHASSIGN,
|
|
T_SLASHSLASHASSIGN,
|
|
T_PERCENTASSIGN,
|
|
T_PERCENTASSIGN,
|
|
|
|
+ T_STARSTARASSIGN,
|
|
|
|
+ T_BARASSIGN,
|
|
T_BARBAR,
|
|
T_BARBAR,
|
|
T_ANDAND,
|
|
T_ANDAND,
|
|
T_STARSTAR,
|
|
T_STARSTAR,
|
|
@@ -515,6 +517,21 @@ token_t *next_token(char *source, size_t *pos) {
|
|
(*pos)++;
|
|
(*pos)++;
|
|
|
|
|
|
return token(T_STRING, buffer_read(text));
|
|
return token(T_STRING, buffer_read(text));
|
|
|
|
+ } else if (source[*pos] == '0' && (source[(*pos)+1] == 'x' || source[(*pos)+1] == 'b' || source[(*pos)+1] == 'o')) {
|
|
|
|
+ buffer_t *number = buffer_new();
|
|
|
|
+ buffer_append(number, source[(*pos)++]);
|
|
|
|
+
|
|
|
|
+ char b = source[(*pos)++];
|
|
|
|
+
|
|
|
|
+ buffer_append(number, b);
|
|
|
|
+
|
|
|
|
+ while (source[*pos] && strchr(b == 'x' ? "0123456789abcdefABCDEF": b == 'b' ? "01": "01234567", source[*pos]) != NULL)
|
|
|
|
+ buffer_append(number, source[(*pos)++]);
|
|
|
|
+
|
|
|
|
+ if (number->size < 3)
|
|
|
|
+ LEX_ERROR("illegal number literal (trailing base)");
|
|
|
|
+
|
|
|
|
+ return token(T_NUMBER, buffer_read(number));
|
|
} else if ((source[*pos] == '.' && isdigit(source[(*pos)+1])) || isdigit(source[*pos])) {
|
|
} else if ((source[*pos] == '.' && isdigit(source[(*pos)+1])) || isdigit(source[*pos])) {
|
|
buffer_t *number = buffer_new();
|
|
buffer_t *number = buffer_new();
|
|
int dot = 0;
|
|
int dot = 0;
|
|
@@ -631,6 +648,10 @@ token_t *next_token(char *source, size_t *pos) {
|
|
return TK(SLASHSLASHASSIGN);
|
|
return TK(SLASHSLASHASSIGN);
|
|
else if (strncmp(&source[*pos], "%=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
else if (strncmp(&source[*pos], "%=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
return TK(PERCENTASSIGN);
|
|
return TK(PERCENTASSIGN);
|
|
|
|
+ else if (strncmp(&source[*pos], "**=", 3) == 0 && ++(*pos) && ++(*pos) && ++(*pos))
|
|
|
|
+ return TK(STARSTARASSIGN);
|
|
|
|
+ else if (strncmp(&source[*pos], "|=", 2) == 0 && ++(*pos) && ++(*pos))
|
|
|
|
+ return TK(BARASSIGN);
|
|
else if (strncmp(&source[*pos], "||", 2) == 0 && ++(*pos) && ++(*pos))
|
|
else if (strncmp(&source[*pos], "||", 2) == 0 && ++(*pos) && ++(*pos))
|
|
return TK(BARBAR);
|
|
return TK(BARBAR);
|
|
else if (strncmp(&source[*pos], "&&", 2) == 0 && ++(*pos) && ++(*pos))
|
|
else if (strncmp(&source[*pos], "&&", 2) == 0 && ++(*pos) && ++(*pos))
|
|
@@ -768,6 +789,7 @@ struct _node_t {
|
|
N_ASSIGN_IDIV,
|
|
N_ASSIGN_IDIV,
|
|
N_ASSIGN_MOD,
|
|
N_ASSIGN_MOD,
|
|
N_ASSIGN_POW,
|
|
N_ASSIGN_POW,
|
|
|
|
+ N_ASSIGN_BOR,
|
|
|
|
|
|
N_EQUALS,
|
|
N_EQUALS,
|
|
N_NOTEQUALS,
|
|
N_NOTEQUALS,
|
|
@@ -1472,6 +1494,14 @@ node_t *parse_assignment(list_t *tokens, size_t *pos) {
|
|
node_t *b = parse_assignment(tokens, pos);
|
|
node_t *b = parse_assignment(tokens, pos);
|
|
|
|
|
|
return NODE2(ASSIGN_MOD, a, b);
|
|
return NODE2(ASSIGN_MOD, a, b);
|
|
|
|
+ } else if (MATCH(STARSTARASSIGN)) {
|
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
|
+
|
|
|
|
+ return NODE2(ASSIGN_POW, a, b);
|
|
|
|
+ } else if (MATCH(BARASSIGN)) {
|
|
|
|
+ node_t *b = parse_assignment(tokens, pos);
|
|
|
|
+
|
|
|
|
+ return NODE2(ASSIGN_BOR, a, b);
|
|
}
|
|
}
|
|
|
|
|
|
return a;
|
|
return a;
|
|
@@ -2320,6 +2350,7 @@ const char *STD[][2] = {
|
|
"set_pseudomethod(\"string.slice\", slice)\n"
|
|
"set_pseudomethod(\"string.slice\", slice)\n"
|
|
"set_pseudomethod(\"bytes.slice\", slice)\n"
|
|
"set_pseudomethod(\"bytes.slice\", slice)\n"
|
|
"func Object(t, p=nil): return p !is nil? set_meta_table(p, get_meta_table(p) + t): set_meta_table({}, t)\n"
|
|
"func Object(t, p=nil): return p !is nil? set_meta_table(p, get_meta_table(p) + t): set_meta_table({}, t)\n"
|
|
|
|
+ "func is_object(o): return has_meta_table(o)\n"
|
|
"func __class_wrapper(n, p, t, mt): return Object({\n"
|
|
"func __class_wrapper(n, p, t, mt): return Object({\n"
|
|
" t: t,\n"
|
|
" t: t,\n"
|
|
" mt: mt,\n"
|
|
" mt: mt,\n"
|
|
@@ -2348,6 +2379,40 @@ const char *STD[][2] = {
|
|
"inline `srand(time(NULL))`\n"
|
|
"inline `srand(time(NULL))`\n"
|
|
},
|
|
},
|
|
|
|
|
|
|
|
+ {"utf8",
|
|
|
|
+ "func utf8_chrlen(s) {\n"
|
|
|
|
+ " s = bytes(s)\n"
|
|
|
|
+ " var z = len(s)\n"
|
|
|
|
+ " if z < 2\n"
|
|
|
|
+ " return z\n"
|
|
|
|
+ " var l = 1\n"
|
|
|
|
+ " for var i = 1; i < z && (s[i] & 0xc0) == 0x80; i++\n"
|
|
|
|
+ " l++\n"
|
|
|
|
+ " return l\n"
|
|
|
|
+ "}\n"
|
|
|
|
+ "func utf8_decode(s) {\n"
|
|
|
|
+ " s = bytes(s)\n"
|
|
|
|
+ " var l = utf8_chrlen(s)\n"
|
|
|
|
+ " if !l\n"
|
|
|
|
+ " throw \"malformed sequence\"\n"
|
|
|
|
+ " var c = (s[0] & ((1 << (8 - l)) - 1)) << (l - 1) * 6\n"
|
|
|
|
+ " for var i = 1; i < l; i++\n"
|
|
|
|
+ " c |= (s[i] & 0x3f) << (l - i - 1) * 6\n"
|
|
|
|
+ " return (c, l)\n"
|
|
|
|
+ "}\n"
|
|
|
|
+ "func utf8_encode(c) {\n"
|
|
|
|
+ " if c <= 0x7f\n"
|
|
|
|
+ " return bytes([c & 0xFF])\n"
|
|
|
|
+ " elif c >= 0x80 && c <= 0x7ff\n"
|
|
|
|
+ " return bytes([0xC0 | ((c >> 6) & 0x1f), 0x80 | (c & 0x3f)])\n"
|
|
|
|
+ " elif c >= 0x800 && c <= 0xfff\n"
|
|
|
|
+ " return bytes([0xe0 | ((c >> 12) & 0xf), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)])\n"
|
|
|
|
+ " elif c >= 0x10000 && c <= 0x10ffff\n"
|
|
|
|
+ " return bytes([0xf0 | ((c >> 18) & 0x7), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)])\n"
|
|
|
|
+ " throw \"malformed codepoint\"\n"
|
|
|
|
+ "}\n"
|
|
|
|
+ },
|
|
|
|
+
|
|
{"str",
|
|
{"str",
|
|
"let STR_LETTERS = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n"
|
|
"let STR_LETTERS = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n"
|
|
"let STR_ASCII_LC = \"abcdefghijklmnopqrstuvwxyz\"\n"
|
|
"let STR_ASCII_LC = \"abcdefghijklmnopqrstuvwxyz\"\n"
|
|
@@ -2461,9 +2526,29 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
|
|
|
|
case N_LITERAL:
|
|
case N_LITERAL:
|
|
switch (node->t->tag) {
|
|
switch (node->t->tag) {
|
|
- case T_NUMBER:
|
|
|
|
- EMIT("qi_make_number(state, %s)", node->t->text);
|
|
|
|
- break;
|
|
|
|
|
|
+ case T_NUMBER: {
|
|
|
|
+ char *number = node->t->text;
|
|
|
|
+
|
|
|
|
+ if (strncmp(number, "0o", 2) == 0 || strncmp(number, "0b", 2) == 0) {
|
|
|
|
+ buffer_t *buf = buffer_new();
|
|
|
|
+
|
|
|
|
+ if (number[1] == 'o')
|
|
|
|
+ buffer_fmt(buf, "0%s", number + 2);
|
|
|
|
+ else
|
|
|
|
+ buffer_fmt(buf, "%d", strtol(number + 2, NULL, 2));
|
|
|
|
+
|
|
|
|
+ number = buffer_read(buf);
|
|
|
|
+ } else if (number[0] == '0' && number[1] && isdigit(number[1])) {
|
|
|
|
+ size_t i;
|
|
|
|
+ for (i = 0; i < strlen(number); i++)
|
|
|
|
+ if (number[i] != '0' || number[i+1] == '.')
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ number += i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ EMIT("qi_make_number(state, %s)", number);
|
|
|
|
+ } break;
|
|
|
|
|
|
case T_STRING:
|
|
case T_STRING:
|
|
if (!*(node->t->text)) {
|
|
if (!*(node->t->text)) {
|
|
@@ -2539,6 +2624,7 @@ void compile_node(buffer_t *gbuf, buffer_t *buf, list_t *ctx, stack_t *lstk, lis
|
|
case N_ASSIGN_IDIV: COMPASSIGN(node->a, "idiv", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
case N_ASSIGN_IDIV: COMPASSIGN(node->a, "idiv", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
case N_ASSIGN_MOD: COMPASSIGN(node->a, "mod", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
case N_ASSIGN_MOD: COMPASSIGN(node->a, "mod", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
case N_ASSIGN_POW: COMPASSIGN(node->a, "pow", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
case N_ASSIGN_POW: COMPASSIGN(node->a, "pow", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
|
+ case N_ASSIGN_BOR: COMPASSIGN(node->a, "bor", compile_node(gbuf, buf, ctx, lstk, lbl, node->b)); break;
|
|
|
|
|
|
case N_INC:
|
|
case N_INC:
|
|
COMPASSIGN(node->a, "add", EMIT("state->one"));
|
|
COMPASSIGN(node->a, "add", EMIT("state->one"));
|