diff --git a/documentation/interchange.md b/documentation/interchange.md index aa2e08e6..404df5a8 100644 --- a/documentation/interchange.md +++ b/documentation/interchange.md @@ -109,16 +109,16 @@ To support tempering after interchanging data, the special `1°` basis element i ``` ### Not-a-number -The special token `nan` indicates a value that can't be interpreted as an interval. +The special combination `[1 1>@0.inf` indicates a value that can't be interpreted as an interval. ```c -nan "asin(2)" niente +[1 1>@0.inf "asin(2)" niente ``` ## Example See [examples/interchange.sw](https://github.com/xenharmonic-devs/sonic-weave/blob/main/examples/interchange.sw) for various extreme values supported by the original SonicWeave runtime. ```c -// Created using SonicWeave 0.0.37 +// Created using SonicWeave 0.1.0 "Various values to test the .swi interchange format" @@ -151,5 +151,5 @@ See [examples/interchange.sw](https://github.com/xenharmonic-devs/sonic-weave/bl [-5 1 5/2 1 1>@1°.Hz.2.3.37 "" niente [1>@inf "infinity" niente [1 1>@-1.inf "negative infinity" niente -nan "not-a-number" niente +[1 1>@0.inf "not-a-number" niente ``` diff --git a/src/__tests__/cli.spec.ts b/src/__tests__/cli.spec.ts index 93fd0569..3ec360f6 100644 --- a/src/__tests__/cli.spec.ts +++ b/src/__tests__/cli.spec.ts @@ -14,7 +14,7 @@ describe('Interchange format', () => { it('has representation for nan', () => { const result = toSonicWeaveInterchange('nan'); - expect(result).toContain('nan'); + expect(result).toContain('[1 1>@0.inf'); }); it('has representation for negative infinity Hz', () => { @@ -24,6 +24,6 @@ describe('Interchange format', () => { it('has representation for nan Hz (normalizes)', () => { const result = toSonicWeaveInterchange('nan * 1 Hz'); - expect(result).toContain('nan'); + expect(result).toContain('[1 1>@0.inf'); }); }); diff --git a/src/interval.ts b/src/interval.ts index 2b245784..59c6a33b 100644 --- a/src/interval.ts +++ b/src/interval.ts @@ -1078,7 +1078,7 @@ export class Interval { * @param interchange Boolean flag to format everything explicitly. * @returns A virtual monzo literal. */ - asMonzoLiteral(interchange = false): MonzoLiteral | undefined { + asMonzoLiteral(interchange = false): MonzoLiteral { let node: MonzoLiteral; if ( interchange && @@ -1089,11 +1089,7 @@ export class Interval { clone.numberOfComponents = NUM_INTERCHANGE_COMPONENTS; node = clone.asMonzoLiteral(); } else { - const maybeNode = this.value.asMonzoLiteral(); - if (maybeNode === undefined) { - return undefined; - } - node = maybeNode; + node = this.value.asMonzoLiteral(); } if ( interchange && @@ -1129,11 +1125,7 @@ export class Interval { result = `${this.steps}°`; } else { const node = this.asMonzoLiteral(); - if (node) { - result = literalToString(node); - } else { - result = this.value.toString(); - } + result = literalToString(node); } if (this.domain === 'linear') { return `linear(${result})`; diff --git a/src/monzo.ts b/src/monzo.ts index 1aadd3b5..8c5c10c0 100644 --- a/src/monzo.ts +++ b/src/monzo.ts @@ -745,12 +745,16 @@ export class TimeReal { * @param interchange Boolean flag to use Hz basis for the absolute echelon. * @returns Monzo literal. */ - asMonzoLiteral(interchange = false): MonzoLiteral | undefined { - if (isNaN(this.value)) { - return undefined; - } + asMonzoLiteral(interchange = false): MonzoLiteral { const components: VectorComponent[] = []; const basis: BasisElement[] = []; + if (isNaN(this.value)) { + basis.push({numerator: 0, denominator: null, radical: false}); + components.push({sign: '', left: 1, right: '', exponent: null}); + basis.push('inf'); + components.push({sign: '', left: 1, right: '', exponent: null}); + return {type: 'MonzoLiteral', components, ups: 0, lifts: 0, basis}; + } if (interchange) { if (this.timeExponent) { basis.push('Hz'); @@ -817,7 +821,7 @@ export class TimeReal { * Obtain an AST node representing the time monzo as a monzo literal suitable for interchange between programs. * @returns Monzo literal. */ - asInterchangeLiteral(): MonzoLiteral | undefined { + asInterchangeLiteral(): MonzoLiteral { return this.asMonzoLiteral(true); } diff --git a/src/parser/__tests__/expression.spec.ts b/src/parser/__tests__/expression.spec.ts index c596124e..44cf0556 100644 --- a/src/parser/__tests__/expression.spec.ts +++ b/src/parser/__tests__/expression.spec.ts @@ -2410,4 +2410,10 @@ describe('Poor grammar / Fun with "<"', () => { expect(interval.valueOf()).toBe(0); expect(interval.value).toBeInstanceOf(TimeReal); }); + + it('parses the universal not-a-number', () => { + const interval = evaluate('[1 1>@0.inf') as Interval; + expect(interval.valueOf()).toBeNaN(); + expect(interval.value).toBeInstanceOf(TimeReal); + }); });