From 3dcbf2d80a6d1289f7887a29b8d4b6e0732d380d Mon Sep 17 00:00:00 2001 From: Lumi Pakkanen Date: Sun, 12 May 2024 16:53:29 +0300 Subject: [PATCH] Document intrinsic calls Fix intrinsic calls. ref #296, #306 --- documentation/advanced-dsl.md | 32 +++++++++++++++++++++---- src/parser/__tests__/expression.spec.ts | 5 ++++ src/parser/expression.ts | 7 +++--- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/documentation/advanced-dsl.md b/documentation/advanced-dsl.md index e31b0944..5342ddb8 100644 --- a/documentation/advanced-dsl.md +++ b/documentation/advanced-dsl.md @@ -440,12 +440,34 @@ Pitch can be declared as a period of oscillation, but it's coearced to Hz to pre E.g. `C4 = 10ms` has the same effect as `C4 = 100 Hz`. +## Implicit intrinsic calls +Associating two values like `3/2 "fif"` invokes intrinsic behavior between the interval `3/2` and the string `"fif"` resulting in an interval with the value 3/2 and the label "fif". + +Semantics of the expression `left right` follow this matrix depending on the types of the operands. Booleans are converted to `0` or `1` and follow interval semantics. Question marks indicate undefined behavior. +| left↓ right→ | Niente | String | Color | Interval | Val | Function | +| ------------ | ------------- | ------------- | ------------- | -------------- | -------------- | ------------- | +| **Niente** | ? | ? | ? | bleach | ? | `right(left)` | +| **String** | ? | concatenate | ? | label | ? | `right(left)` | +| **Color** | ? | ? | ? | paint | ? | `right(left)` | +| **Interval** | bleach | label | paint | `left × right` | `left × right` | `right(left)` | +| **Val** | ? | ? | ? | `left × right` | ? | `right(left)` | +| **Function** | `left(right)` | `left(right)` | `left(right)` | `left(right)` | `left(right)` | `left(right)` | + +Intrinsic behavior vectorizes and broadcasts like other binary operations. + +Intrinsic behavior may be evoked explicitly by simply calling a value e.g. `3/2("fif")` and `"fif"(3/2)` both work. + +Some expressions like `440Hz` or `440 Hz` appear similar to intrinsic calls and would correspond to `440 × (1 Hz)` but `600.0 Hz` is actually `600.0e × (1 Hz)` instead of cents multiplied by Hertz. + +It's legal to declare `let Hz = 'whatever'`, but the grammar prevents the `Hz` variable from invoking intrinsic behavior of integer literals from the right. + ### Obscure types -| Type | Literal | Meaning | -| ------------ | ------- | ------------------------------------------------------ | -| Second | `1s` | Inverse of `1Hz` i.e. `1s * 1Hz` evaluates to `1` | -| Jorp | `€` | Geometric inverse of `c` i.e. `€` is equal to `<1200]` | -| Pilcrowspoob | `¶` | Geometric inverse of `logarithmic(1Hz)` | +| Type | Literal | Meaning | +| ----------------- | ---------- | ---------------------------------------------------------- | +| Second | `1s` | Inverse of `1Hz` i.e. `1s * 1Hz` evaluates to `1` | +| Jorp | `€` | Geometric inverse of `c` i.e. `€` is equal to `<1200]` | +| Pilcrowspoob | `¶` | Geometric inverse of `logarithmic(1Hz)` | +| Template argument | `¥0`, `¥1` | Arguments passed to the `sw\`${arg0} ${arg1}\`` tag in JS. | ### Obscure operations | Name | Linear | Result | Logarithmic | Result | diff --git a/src/parser/__tests__/expression.spec.ts b/src/parser/__tests__/expression.spec.ts index 2cd7feda..5bec3566 100644 --- a/src/parser/__tests__/expression.spec.ts +++ b/src/parser/__tests__/expression.spec.ts @@ -2367,4 +2367,9 @@ describe('Poor grammar / Fun with "<"', () => { const {fraction} = parseSingle('<12 19]@√2.√3 dot P5'); expect(fraction).toBe('14'); }); + + it('evokes intrinsic behavior between PI and E', () => { + const product = evaluateExpression('PI(E)', false) as Interval; + expect(product.valueOf()).toBeCloseTo(8.5397); + }); }); diff --git a/src/parser/expression.ts b/src/parser/expression.ts index 03656083..bb979279 100644 --- a/src/parser/expression.ts +++ b/src/parser/expression.ts @@ -1806,11 +1806,12 @@ export class ExpressionVisitor { protected visitCallExpression(node: CallExpression) { const args = this.spread(node.args); + let callee: SonicWeaveValue; if (node.callee.type === 'Identifier') { - const callee = this.get(node.callee.id) as SonicWeaveFunction; - return callee.bind(this)(...args); + callee = this.get(node.callee.id); + } else { + callee = this.visit(node.callee); } - const callee = this.visit(node.callee); if (typeof callee === 'function') { return (callee as SonicWeaveFunction).bind(this)(...args); }