diff --git a/documentation/advanced-dsl.md b/documentation/advanced-dsl.md index cf76db4c..74744676 100644 --- a/documentation/advanced-dsl.md +++ b/documentation/advanced-dsl.md @@ -50,6 +50,17 @@ Blocks are valid expressions and evaluate to arrays. They have the lowest preced (* $ = [10, 20, 30] *) ``` +#### Block expression return value +Use a `return` statement inside a block expression to evaluate to the returned value. +```ocaml +const foo = { + const bar = 2 + const baz = 3 + return bar + baz +} +(* const foo = 5 *) +``` + ### Parent scale The current scale of the parent block can be accessed using `$$`. diff --git a/src/parser/__tests__/expression.spec.ts b/src/parser/__tests__/expression.spec.ts index 03d5ad38..79349cba 100644 --- a/src/parser/__tests__/expression.spec.ts +++ b/src/parser/__tests__/expression.spec.ts @@ -2460,6 +2460,18 @@ describe('SonicWeave expression evaluator', () => { expect(interval.value).toBeInstanceOf(TimeReal); expect(interval.valueOf()).toBeCloseTo(1.000000745, 10); }); + + it('allows return from block expressions', () => { + const foo = evaluate(` + const foo = ({ + const ba = "ba" + return ba "r" + throw "not executed" + }) + foo + `); + expect(foo).toBe('bar'); + }); }); describe('Poor grammar / Fun with "<"', () => { diff --git a/src/parser/expression.ts b/src/parser/expression.ts index efa5d503..04184c45 100644 --- a/src/parser/expression.ts +++ b/src/parser/expression.ts @@ -429,7 +429,9 @@ export class ExpressionVisitor { const scale = this.currentScale; subVisitor.mutables.set('$$', scale); const interrupt = subVisitor.executeStatements(node.body); - if (interrupt) { + if (interrupt?.type === 'ReturnStatement') { + return interrupt.value; + } else if (interrupt) { throw new Error('Illegal interupt.'); } return subVisitor.currentScale;