case AST_OP_AND: EMIT(BC_OP_AND); break;
case AST_OP_OR: EMIT(BC_OP_OR); break;
case AST_OP_INDEX: EMIT(BC_OP_INDEX); break;
+ case AST_OP_RANGEINDEX: EMIT(BC_OP_RANGEINDEX); break;
+ /* op range is currently only used in rangeindex; just pass them to it directly */
+ case AST_OP_RANGE: break;
case AST_OP_DIVBY: EMIT(BC_OP_MOD, BC_LD_IMM); EARG(0); EMIT(BC_OP_EQ); break;
default:
PANIC("unknown operation! (%lld / %c)", (long long)op, op);
sbIrExpr *hash = compile_ast_hash(ck, node->seq.left);
return hash;
} else if (node->type == AST_NODE_OP) {
- if (node->op.type == AST_OP_SPLAT) {
+ if (node->op.type == AST_OP_RANGE) {
+ chunk_error(ck, "'..' operator not permitted in this context\n");
+ return NULL;
+ } else if (node->op.type == AST_OP_RANGEINDEX) {
+ return expr_op(ck, AST_OP_RANGEINDEX,
+ compile_ast_expr(ck, node->op.left, FALSE),
+ expr_op(ck, AST_OP_RANGE,
+ compile_ast_expr(ck, node->op.right->op.left, FALSE),
+ compile_ast_expr(ck, node->op.right->op.right, FALSE)
+ )
+ );
+ } else if (node->op.type == AST_OP_SPLAT) {
if (!list_context) {
- chunk_error(ck, "'...' not allowed outside a list");
+ chunk_error(ck, "'...' not allowed outside a list\n");
return NULL;
} else {
return expr_op(ck, AST_OP_SPLAT, compile_ast_expr(ck, node->op.left, FALSE), NULL);
}
}
+i64 sbInteger_get_value(hInteger a) {
+ if (!is_bigint(a)) {
+ return a;
+ } else {
+ PANIC("Integer value out of range");
+ }
+}
+
hInteger sbInteger_sum(hInteger a, hInteger b) {
if (!is_bigint(a) && !is_bigint(b)) {
return sbInteger_new(a + b);
hInteger sbInteger_new(i64 value);
+i64 sbInteger_get_value(hInteger a);
+
void sbInteger_retain(hInteger a);
void sbInteger_release(hInteger a);
#include "gc/gcinfo.h"
#include "vm/exec.h"
+#include "mem/debug.h"
#define LIST_PER_BLOCK 256
#define METHOD_IS(name) (!sbstrncmp(method_name, name, sizeof(name)))
return index;
}
+hList sbList_of(usize length, hV *items) {
+ usize index;
+ usize capacity = length;
+ sbList *l = sbPool_alloc(&g_list_pool, &index);
+ if (capacity < 4) capacity = 4;
+ sbBuffer_initialize(&l->items, capacity * sizeof(hV));
+ sbBuffer_set_size(&l->items, length * sizeof(hV));
+ memcpy(l->items.data, items, length * sizeof(hV));
+ return index;
+}
+
void sbList_append(hList list, hV *item) {
sbList *l = get_list_by_handle(list);
sbV_retain(item);
hList sbList_new(usize capacity);
+hList sbList_of(usize length, hV *items);
+
void sbList_append(hList list, hV *item);
hV *sbList_get_value(hList list, usize *length);
};
}
+hV sbV_empty_string() {
+ return sbV_string((hString)0);
+}
+
flag sbV_c_eq(const hV *a, const hV *b) {
if (a->type != b->type) return FALSE;
if (a->type == ITX_TOMBSTONE || b->type == ITX_TOMBSTONE) return FALSE;
hV sbV_boolean(flag b);
hV sbV_empty_list(usize capacity);
hV sbV_empty_hash(usize capacity);
+hV sbV_empty_string();
flag sbV_c_eq(const hV *a, const hV *b);
flag sbV_c_falsy(const hV *a);
AST_OP_RANGE,
AST_OP_DIVBY,
AST_OP_INDEX,
+ AST_OP_RANGEINDEX,
AST_OP_SCOPE,
AST_OP_UNPLUS,
AST_OP_UNMINUS,
{ T_BACKSLASH, "'\\'" },
{ T_ARROW, "'->'" },
{ T_FATARROW, "'=>'" },
- { T_SQUIGARROW, "'~>'" },
- { T_BACKSQUIGARROW, "'<~'" },
{ T_COLONBRACE, "':{'" },
{ T_PAAMAYIM_NEKUDOTAYIM, "'::'" },
{ T_DOUBLEEQUALS, "'=='" },
static binop binops[] = {
{ T_PIPE, 6, 7, AST_OP_PIPE },
- { T_BACKSQUIGARROW, 8, 9, AST_OP_SEND },
{ T_rOR, 15, 16, AST_OP_OR },
{ T_rAND, 20, 21, AST_OP_AND },
{ T_rIN, 25, 26, AST_OP_IN },
{ T_PERCENT, 60, 61, AST_OP_MOD },
{ T_DOUBLESLASH, 60, 61, AST_OP_FLDIV },
{ T_DOUBLEASTERISK, 71, 70, AST_OP_POW },
- { T_TWODOT, 80, 81, AST_OP_RANGE },
{ T_DOT, 90, 91, AST_OP_NULL },
{ T_ARROW, 90, 91, AST_OP_NULL },
{ T_LPAREN, 90, 91, AST_OP_NULL },
if (!expect(pr, T_RPAREN)) return syntax_error(pr);
sbAst body = parse_block(pr);
lhs = seq_node(pr, AST_VAL_FUNC, params, body);
- } else if (t.type == T_SQUIGARROW) {
- next_token(pr);
- if (!expect(pr, T_LPAREN)) return syntax_error(pr);
- sbAst params = parse_comma_exprs(pr, NULL);
- if (!expect(pr, T_RPAREN)) return syntax_error(pr);
- sbAst body = parse_block(pr);
- lhs = seq_node(pr, AST_VAL_OBJ, params, body);
} else if (t.type == T_COLONBRACE) {
next_token(pr);
sbAst body = parse_stmtseq(pr);
break;
}
+ sbAstOp ast_op = infix->ast_op;
+
next_token(pr); /* consume operator token */
sbAst rhs;
} else if (op.type == T_LBRACKET) {
/* indexing */
rhs = parse_expr(pr, 0);
+ if (rhs == NO_NODE) return syntax_error(pr);
+
+ if (expect(pr, T_TWODOT)) {
+ /* Range indexing */
+ ast_op = AST_OP_RANGEINDEX;
+ sbAst end_range = parse_expr(pr, 0);
+ if (end_range == NO_NODE) return syntax_error(pr);
+ rhs = binop_node(pr, AST_OP_RANGE, rhs, end_range);
+ }
+
if (!expect(pr, T_RBRACKET)) return syntax_error(pr);
} else if (op.type == T_DOT || op.type == T_ARROW) {
/* . and -> parse an identifier to their right as a symbol that will
}
if (ast_type == AST_NODE_OP) {
- lhs = binop_node(pr, infix->ast_op, lhs, rhs);
+ lhs = binop_node(pr, ast_op, lhs, rhs);
} else {
lhs = seq_node(pr, ast_type, lhs, rhs);
}
/* ! on its own is not an operator */
new_token.type = T_ERROR;
}
- } else if (ch == '~') {
- ch = NEXT;
- if (ch == '>') {
- new_token.type = T_SQUIGARROW;
- NEXT;
- } else {
- /* ~ on its own is not an operator */
- new_token.type = T_ERROR;
- }
} else if (ch == '>') {
ch = NEXT;
if (ch == '>') {
} else if (ch == '=') {
new_token.type = T_LESSEQUALS;
NEXT;
- } else if (ch == '~') {
- new_token.type = T_BACKSQUIGARROW;
- NEXT;
} else {
new_token.type = T_LESS;
}
BC_OP_AND, // logical and
BC_OP_OR, // logical or
BC_OP_INDEX, // index [] or ::
+ BC_OP_RANGEINDEX, // index [a..b]
BC_ALLOC_VARS, // create space in rstack for local variables
BC_CLOSURE, // create closure from top elements of stack
BC_LIST_GATHER, // create list from count + list of values on stack
npop_stack(vm, 2);
push_stack(vm, x);
break;
+ case BC_OP_RANGEINDEX:
+ v = peek_stack(vm, 2);
+ w = peek_stack(vm, 1);
+ x = peek_stack(vm, 0);
+ res = sbV_rangeindex(v, w, x);
+ npop_stack(vm, 3);
+ push_stack_immediate(vm, &res);
+ break;
case BC_OP_DEREF:
PANIC("todo");
case BC_ALLOC_VARS:
}
}
+hV sbV_rangeindex(hV *a, hV *b, hV *c) {
+ if (b->type == IT_INTEGER && c->type == IT_INTEGER) {
+ usize length;
+ i64 min = sbInteger_get_value(b->integer);
+ i64 max = sbInteger_get_value(c->integer);
+ if (a->type == IT_LIST) {
+ hV *elements = sbList_get_value(a->list, &length);
+ if (min >= max || min >= length || max < 0) {
+ /* backwards or out of range */
+ return sbV_empty_list(0);
+ } else {
+ /* now we know 0 <= max, min < max, min < length. clip min and max to bounds */
+ if (max >= length) max = length;
+ if (min < 0) min = 0;
+ return HVLIST(sbList_of(max - min, &elements[min]));
+ }
+ } else if (a->type == IT_STRING) {
+ /* substring operation */
+ char scratch[8];
+ const char *strdata = sbString_get_value(a->string, scratch, &length);
+ if (min >= max || min >= length || max < 0) {
+ /* backwards or out of range */
+ return sbV_empty_string(0);
+ } else {
+ /* now we know 0 <= max, min < max, min < length. clip min and max to bounds */
+ if (max >= length) max = length;
+ if (min < 0) min = 0;
+ return HVSTR(sbString_new(&strdata[min], max - min));
+ }
+ } else {
+ PANIC("todo %lld %lld %lld", (long long)a->type, (long long)b->type, (long long)c->type);
+ }
+ } else {
+ PANIC("Only integers are supported for range indexing!");
+ }
+}
+
void sbV_index_set(hV *obj, hV *key, hV *value) {
if (obj->type == IT_LIST) {
PANIC("todo");
hV *sbV_index(hV *a, hV *b);
+hV sbV_rangeindex(hV *a, hV *b, hV *c);
+
void sbV_index_set(hV *obj, hV *key, hV *value);