diff --git a/docs/SPECIFICATION.html b/docs/SPECIFICATION.html index 7fb2c2b..948629b 100644 --- a/docs/SPECIFICATION.html +++ b/docs/SPECIFICATION.html @@ -54,7 +54,7 @@ Keywords and built-in names MUST be matched case-sensitively and MUST be written in their canonical uppercase forms. If a reserved word is written in any other case, it MUST be tokenized as an identifier instead. -The character `-` MUST be interpreted only as the leading sign of a numeric literal or as the dash used by slice syntax `lo-hi`. Any unsupported use of `-` MUST raise a syntax error. +The character `-` MUST be interpreted only as the leading sign of a numeric literal. Any unsupported use of `-` MUST raise a syntax error. The character `~` MUST be reserved for coerced function parameters and MUST NOT appear inside identifiers. @@ -104,7 +104,7 @@ Indexed assignment to a map MUST use the same form as ordinary map access, such as `map = expression`. Intermediate nested maps MUST be created on demand when assigning to deeper keys. Reassigning an existing key to a value of a different static type MUST raise a runtime error. -If a tensor target uses slice indices such as `lo-hi` or `*`, the right-hand side MUST evaluate to a `TNS` whose shape exactly matches the selected slice, and every written element MUST satisfy the target's static type constraints. +If a tensor target uses slice indices such as `lo:hi` or `*`, the right-hand side MUST evaluate to a `TNS` whose shape exactly matches the selected slice, and every written element MUST satisfy the target's static type constraints. --- @@ -328,7 +328,7 @@ `TNS` indexing MUST use square brackets (`[` and `]`) with a comma-separated list of indices. Indexing MUST be one-based. Negative indices MUST count backwards from the end of the dimension. -Slice indexing MUST be supported in any index position using a range of the form `lo-hi`. The selected slice MUST be inclusive of both endpoints. The symbol `*` MAY be used in an index position to denote a full-dimension slice, selecting every element along that axis. +Slice indexing MUST be supported in any index position using a range of the form `lo:hi`. The selected slice MUST be inclusive of both endpoints. The symbol `*` MAY be used in an index position to denote a full-dimension slice, selecting every element along that axis. --- diff --git a/lib/std/image/init.pre b/lib/std/image/init.pre index 82e96de..c5d3898 100644 --- a/lib/std/image/init.pre +++ b/lib/std/image/init.pre @@ -120,7 +120,7 @@ FUNC TNS CROP(TNS img, TNS corners){ IF(NEQ(SHAPE(corners), [0d4, 0d2])){ THROW("CROP corners must be a 0d4 by 0d2 tensor: [[tl_x, tl_y], [tr_x, tr_y], [bl_x, bl_y], [br_x, br_y]]") } - RETURN(img[MIN(corners[*, 0d1])-MAX(corners[*, 0d1]), MIN(corners[*, 0d2])-MAX(corners[*, 0d2]), *]) + RETURN(img[MIN(corners[*, 0d1]):MAX(corners[*, 0d1]), MIN(corners[*, 0d2]):MAX(corners[*, 0d2]), *]) } FUNC BOOL SHOW(TNS img){ diff --git a/src/parser.c b/src/parser.c index 1306bd8..fd4f39a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -718,16 +718,9 @@ static Expr* parse_call(Parser* parser) { // parse an expression for index or possibly a range Expr* start = parse_expression(parser); if (!start) return NULL; - // Accept either an explicit DASH token or a negative-number token as the range separator - bool is_range = false; - if (parser->current_token.type == TOKEN_DASH) { - is_range = true; - } else if (parser->current_token.type == TOKEN_NUMBER && parser->current_token.literal && parser->current_token.literal[0] == '-') { - is_range = true; - } - if (is_range) { - // If it's a DASH token, consume it; otherwise leave the negative-number token for parse_expression - if (parser->current_token.type == TOKEN_DASH) advance(parser); + // Range separator is ':' inside index expressions + if (parser->current_token.type == TOKEN_COLON) { + advance(parser); // consume ':' Expr* end = parse_expression(parser); if (!end) return NULL; Expr* range = expr_range(start, end, start->line, start->column); @@ -969,20 +962,17 @@ static Stmt* parse_statement(Parser* parser) { Expr* wc = expr_wildcard(parser->previous_token.line, parser->previous_token.column); expr_list_add(&idx->as.index.indices, wc); } else { - Expr* start = parse_expression(parser); - if (!start) return NULL; - bool is_range = false; - if (parser->current_token.type == TOKEN_DASH) is_range = true; - else if (parser->current_token.type == TOKEN_NUMBER && parser->current_token.literal && parser->current_token.literal[0] == '-') is_range = true; - if (is_range) { - if (parser->current_token.type == TOKEN_DASH) advance(parser); - Expr* end = parse_expression(parser); - if (!end) return NULL; - Expr* range = expr_range(start, end, start->line, start->column); - expr_list_add(&idx->as.index.indices, range); - } else { - expr_list_add(&idx->as.index.indices, start); - } + Expr* start = parse_expression(parser); + if (!start) return NULL; + if (parser->current_token.type == TOKEN_COLON) { + advance(parser); // consume ':' + Expr* end = parse_expression(parser); + if (!end) return NULL; + Expr* range = expr_range(start, end, start->line, start->column); + expr_list_add(&idx->as.index.indices, range); + } else { + expr_list_add(&idx->as.index.indices, start); + } } if (parser->current_token.type == TOKEN_COMMA) { advance(parser); continue; } diff --git a/src/token.h b/src/token.h index 9852383..1339112 100644 --- a/src/token.h +++ b/src/token.h @@ -31,7 +31,7 @@ typedef enum { TOKEN_TILDE, // ~ TOKEN_STAR, // * TOKEN_DOT, // . - TOKEN_DASH, // - (when used as slice range separator) + TOKEN_DASH, // - (reserved; negative numeric literals are part of NUMBER/FLOAT; standalone '-' is a syntax error) // Keywords TOKEN_TRY, diff --git a/tests/cases/passing/tns-indexing.pre b/tests/cases/passing/tns-indexing.pre index 8aefd82..990acb2 100644 --- a/tests/cases/passing/tns-indexing.pre +++ b/tests/cases/passing/tns-indexing.pre @@ -15,16 +15,16 @@ ASSERT(EQ(cube[0d2, 0d2, 0d1], 0d7)) ASSERT(EQ(cube[0d1], [[0d1, 0d2], [0d3, 0d4]])) ASSERT(EQ(cube[0d1, *], [[0d1, 0d2], [0d3, 0d4]])) -ASSERT(EQ(vec[0d1-0d2], [0d1, 0d2])) -ASSERT(EQ(vec[0d2-0d2], 0d2)) -ASSERT(EQ(vec[0d1--0d1], [0d1, 0d2, 0d3])) -ASSERT(EQ(vec[0d0-0d4], [0d1, 0d2, 0d3])) +ASSERT(EQ(vec[0d1:0d2], [0d1, 0d2])) +ASSERT(EQ(vec[0d2:0d2], 0d2)) +ASSERT(EQ(vec[0d1:-0d1], [0d1, 0d2, 0d3])) +ASSERT(EQ(vec[0d0:0d4], [0d1, 0d2, 0d3])) ASSERT(EQ(matrix[*, *], matrix)) ASSERT(EQ(matrix[*, 0d1], [0d1, 0d3])) ASSERT(EQ(matrix[0d1, *], [0d1, 0d2])) -ASSERT(EQ(matrix[0d1-0d2, 0d1-0d2], matrix)) -ASSERT(EQ(matrix[0d1--0d1, 0d1], [0d1, 0d3])) +ASSERT(EQ(matrix[0d1:0d2, 0d1:0d2], matrix)) +ASSERT(EQ(matrix[0d1:-0d1, 0d1], [0d1, 0d3])) ASSERT(EQ(cube[*, 0d2, 0d1], [0d3, 0d7])) INT errors_caught = 0d0 @@ -44,7 +44,7 @@ TRY { } TRY { - vec[TRUE-0d1] + vec[TRUE:0d1] } CATCH(err) { ASSERT(EQ(err, 'Range bounds must be INT')) ADD(@errors_caught, 0d1) diff --git a/tests/cases/passing/tns-slice-assign-1d.pre b/tests/cases/passing/tns-slice-assign-1d.pre index 08cb2b4..48c811b 100644 --- a/tests/cases/passing/tns-slice-assign-1d.pre +++ b/tests/cases/passing/tns-slice-assign-1d.pre @@ -1,4 +1,4 @@ TNS vec = [0d1, 0d2, 0d3] -ASSERT(EQ(ASSIGN(vec[0d1-0d2], [0d9, 0d10]), [0d9, 0d10])) +ASSERT(EQ(ASSIGN(vec[0d1:0d2], [0d9, 0d10]), [0d9, 0d10])) ASSERT(EQ(vec, [0d9, 0d10, 0d3]))