Skip to content

Commit

Permalink
Remove lest assignment due to no change possible
Browse files Browse the repository at this point in the history
Add a note about lest associativity.
  • Loading branch information
frostburn committed Apr 30, 2024
1 parent 565684c commit 051ac69
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 15 deletions.
4 changes: 3 additions & 1 deletion documentation/technical.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ All operations are left-associative except exponentiation, recipropower, and log
| `and`, `vand` | Boolean and, vector and |
| `or`, `vor`, `??` | Boolean or, vector or, niente coalescing |
| `x if y else z` | Ternary conditional |
| `lest` | Fallback |
| `lest` | Fallback[^1] |

Parenthesis, `^`, `×`, `÷`, `+`, `-` follow [PEMDAS](https://en.wikipedia.org/wiki/Order_of_operations). The fraction slash `/` represents vertically aligned fractions similar to `$\frac{3}{2}^\frac{1}{2}$` in LaTeX e.g. `3/2 ^ 1/2` evaluates to `sqrt(3 ÷ 2)`.

[^1]: `lest` is a fully associative operation, thus `a() lest b() lest c()` = `(a() lest b()) lest c()` = `a() lest (b() lest c())`. This means that one can always treat a sequence `a() lest b() lest ... lest c()` as if the evaluations occurred from left to right. Any possible parenthesis may be ignored in such a sequence.

## Interval subtypes

TODO: List all interval subtypes
Expand Down
3 changes: 1 addition & 2 deletions src/grammars/sonic-weave.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -552,8 +552,7 @@ Expression
= LestExpression

AssigningOperator
= LestOperator
/ CoalescingOperator
= CoalescingOperator
/ ConjunctOperator
/ RoundingOperator
/ ExtremumOperator
Expand Down
35 changes: 23 additions & 12 deletions src/parser/__tests__/expression.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1472,20 +1472,31 @@ describe('SonicWeave expression evaluator', () => {
expect(pi.valueOf()).toBeCloseTo(Math.PI);
});

it('has an inline analogue of try..catch (right failure)', () => {
const pi = evaluate('fraction(E) lest fraction(PI) lest PI') as Interval;
expect(pi.value.isFractional()).toBe(false);
expect(pi.valueOf()).toBeCloseTo(Math.PI);
it('has an inline analogue of try..catch (ternary fail.fail.fail)', () => {
expect(() =>
evaluate('fraction(E) lest fraction(PI) lest fraction(LN2)')
).toThrow('Input is irrational and no tolerance given.');
});

it('has inline analogue of assignment inside try..catch', () => {
const pi = evaluate(
'let halfTau = PI;halfTau lest= fraction(halfTau);halfTau'
) as Interval;
expect(pi.value.isFractional()).toBe(false);
expect(pi.value.isFractional()).toBe(false);
expect(pi.valueOf()).toBeCloseTo(Math.PI);
expect(pi.valueOf()).toBeCloseTo(Math.PI);
it('has an inline analogue of try..catch (ternary fail.fail.success)', () => {
const {fraction} = parseSingle(
'fraction(E) lest fraction(PI) lest fraction(LN2, 10.)'
);
expect(fraction).toBe('9/13');
});

it('has an inline analogue of try..catch (ternary fail.success.no-eval)', () => {
const {fraction} = parseSingle(
'fraction(E) lest fraction(PI, 10.) lest fraction(LN2)'
);
expect(fraction).toBe('22/7');
});

it('has an inline analogue of try..catch (ternary success.no-eval.no-eval)', () => {
const {fraction} = parseSingle(
'fraction(E, 10.) lest fraction(PI, 10.) lest fraction(LN2)'
);
expect(fraction).toBe('19/7');
});

it('has atan2 with swapped arguments', () => {
Expand Down

0 comments on commit 051ac69

Please sign in to comment.