Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
Add support for the slice operator.
Browse files Browse the repository at this point in the history
The slice operator extracts a section of the input `string` or `Array`,
and it follows the semantics of Array.prototype.slice.

Signed-off-by: Roberto Raggi <roberto.raggi@here.com>
  • Loading branch information
robertoraggi committed Nov 27, 2020
1 parent b5525fe commit f46fc6b
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
9 changes: 9 additions & 0 deletions @here/harp-datasource-protocol/StyleExpressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,15 @@ Returns the element of the array at the given position.
["at", number, array]
```

## slice

Extracts a section of the input `string` or `Array`.

```javascript
["slice", input, start, end]
["slice", input, start]
```

## concat

Concatenates the given string values.
Expand Down
24 changes: 24 additions & 0 deletions @here/harp-datasource-protocol/lib/operators/ArrayOperators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,30 @@ const operators = {
}
return index >= 0 && index < value.length ? value[index] : null;
}
},

slice: {
call: (context: ExprEvaluatorContext, call: CallExpr) => {
if (call.args.length < 2) {
throw new Error("not enough arguments");
}
const input = context.evaluate(call.args[0]);
if (!(typeof input === "string" || Array.isArray(input))) {
throw new Error("input must be a string or an array");
}
const start = context.evaluate(call.args[1]);
if (typeof start !== "number") {
throw new Error("expected an index");
}
let end: number | undefined;
if (call.args.length > 2) {
end = context.evaluate(call.args[2]) as any;
if (typeof end !== "number") {
throw new Error("expected an index");
}
}
return input.slice(start, end);
}
}
};

Expand Down
72 changes: 72 additions & 0 deletions @here/harp-datasource-protocol/test/ExprEvaluatorTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2002,4 +2002,76 @@ describe("ExprEvaluator", function() {
);
});
});

describe("Operator 'slice'", () => {
it("parse", () => {
assert.throw(() => evaluate(["slice"]), "not enough arguments");
assert.throw(() => evaluate(["slice", "abc"]), "not enough arguments");
assert.throw(() => evaluate(["slice", 123, 0]), "input must be a string or an array");
});

it("slice of strings", () => {
assert.deepStrictEqual(evaluate(["slice", "abc", 0]), "abc");
assert.deepStrictEqual(evaluate(["slice", "abc", 1]), "bc");
assert.deepStrictEqual(evaluate(["slice", "abc", 2]), "c");
assert.deepStrictEqual(evaluate(["slice", "abc", 3]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", 4]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", -1]), "c");
assert.deepStrictEqual(evaluate(["slice", "abc", -2]), "bc");
assert.deepStrictEqual(evaluate(["slice", "abc", -3]), "abc");
assert.deepStrictEqual(evaluate(["slice", "abc", -4]), "abc");
});

it("empty string slices", () => {
assert.deepStrictEqual(evaluate(["slice", "abc", 0, 0]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", 1, 1]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", 2, 2]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", 3, 3]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", 4, 4]), "");
});

it("extracts slices of one character from strings", () => {
assert.deepStrictEqual(evaluate(["slice", "abc", 0, 1]), "a");
assert.deepStrictEqual(evaluate(["slice", "abc", 1, 2]), "b");
assert.deepStrictEqual(evaluate(["slice", "abc", 2, 3]), "c");
assert.deepStrictEqual(evaluate(["slice", "abc", 3, 4]), "");
assert.deepStrictEqual(evaluate(["slice", "abc", 4, 5]), "");
});

it("slice of arrays", () => {
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 0]), [10, 20, 30]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 1]), [20, 30]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 2]), [30]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 3]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 4]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], -1]), [30]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], -2]), [20, 30]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], -3]), [
10,
20,
30
]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], -4]), [
10,
20,
30
]);
});

it("extracts empty slices", () => {
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 0, 0]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 1, 1]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 2, 2]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 3, 3]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 4, 4]), []);
});

it("extracts slices of one element from arrays", () => {
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 0, 1]), [10]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 1, 2]), [20]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 2, 3]), [30]);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 3, 4]), []);
assert.deepStrictEqual(evaluate(["slice", ["literal", [10, 20, 30]], 4, 5]), []);
});
});
});

0 comments on commit f46fc6b

Please sign in to comment.