Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/SPECIFICATION.html
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -104,7 +104,7 @@

Indexed assignment to a map MUST use the same form as ordinary map access, such as `map<k1, k2> = 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.

---

Expand Down Expand Up @@ -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.

---

Expand Down
2 changes: 1 addition & 1 deletion lib/std/image/init.pre
Original file line number Diff line number Diff line change
Expand Up @@ -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){
Expand Down
38 changes: 14 additions & 24 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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; }
Expand Down
2 changes: 1 addition & 1 deletion src/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
14 changes: 7 additions & 7 deletions tests/cases/passing/tns-indexing.pre
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/passing/tns-slice-assign-1d.pre
Original file line number Diff line number Diff line change
@@ -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]))
Loading