From 00b4837f845602e02b7ca1e61c7181249ba3edb7 Mon Sep 17 00:00:00 2001 From: Matt Kantor Date: Mon, 27 Jan 2025 17:04:58 -0500 Subject: [PATCH] Fix unparsing immediately-invoked function expressions They were missing parentheses around the function expression. --- src/language/compiling/unparsing.test.ts | 38 ++++++++++++++++++++ src/language/unparsing/plz-utilities.ts | 44 +++++++++++++++--------- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/language/compiling/unparsing.test.ts b/src/language/compiling/unparsing.test.ts index b5513e5..59792ba 100644 --- a/src/language/compiling/unparsing.test.ts +++ b/src/language/compiling/unparsing.test.ts @@ -46,6 +46,18 @@ testCases( }, either.makeRight('{ identity: a => :a, test: :identity("it works!") }'), ], + [ + { + 0: '@apply', + function: { + 0: '@function', + parameter: 'a', + body: { 0: '@lookup', 1: 'a' }, + }, + argument: 'it works!', + }, + either.makeRight('(a => :a)("it works!")'), + ], ]) testCases( @@ -82,6 +94,18 @@ testCases( '{\n identity: a => :a\n test: :identity("it works!")\n}', ), ], + [ + { + 0: '@apply', + function: { + 0: '@function', + parameter: 'a', + body: { 0: '@lookup', 1: 'a' }, + }, + argument: 'it works!', + }, + either.makeRight('(a => :a)("it works!")'), + ], ]) testCases( @@ -120,4 +144,18 @@ testCases( '{\n "identity": {\n "0": "@function",\n "parameter": "a",\n "body": {\n "0": "@lookup",\n "1": "a"\n }\n },\n "test": {\n "0": "@apply",\n "function": {\n "0": "@lookup",\n "1": "identity"\n },\n "argument": "it works!"\n }\n}', ), ], + [ + { + 0: '@apply', + function: { + 0: '@function', + parameter: 'a', + body: { 0: '@lookup', 1: 'a' }, + }, + argument: 'it works!', + }, + either.makeRight( + '{\n "0": "@apply",\n "function": {\n "0": "@function",\n "parameter": "a",\n "body": {\n "0": "@lookup",\n "1": "a"\n }\n },\n "argument": "it works!"\n}', + ), + ], ]) diff --git a/src/language/unparsing/plz-utilities.ts b/src/language/unparsing/plz-utilities.ts index 8c1038c..f641ff5 100644 --- a/src/language/unparsing/plz-utilities.ts +++ b/src/language/unparsing/plz-utilities.ts @@ -128,25 +128,37 @@ const escapeStringContents = (value: string) => const unparseSugaredApply = ( expression: ApplyExpression, unparseAtomOrMolecule: UnparseAtomOrMolecule, -) => - either.flatMap(serializeIfNeeded(expression.function), serializedFunction => +) => { + const functionUnparseResult = either.map( either.flatMap( - unparseAtomOrMolecule(serializedFunction), - functionToApplyAsString => - either.flatMap( - serializeIfNeeded(expression.argument), - serializedArgument => - either.map( - unparseAtomOrMolecule(serializedArgument), - argumentAsString => - functionToApplyAsString - .concat(openParenthesis) - .concat(argumentAsString) - .concat(closeParenthesis), - ), - ), + serializeIfNeeded(expression.function), + unparseAtomOrMolecule, ), + unparsedFunction => + either.isRight(readFunctionExpression(expression.function)) + ? // Immediately-applied function expressions need parentheses. + openParenthesis.concat(unparsedFunction).concat(closeParenthesis) + : unparsedFunction, + ) + if (either.isLeft(functionUnparseResult)) { + return functionUnparseResult + } + + const argumentUnparseResult = either.flatMap( + serializeIfNeeded(expression.argument), + unparseAtomOrMolecule, ) + if (either.isLeft(argumentUnparseResult)) { + return argumentUnparseResult + } + + return either.makeRight( + functionUnparseResult.value + .concat(openParenthesis) + .concat(argumentUnparseResult.value) + .concat(closeParenthesis), + ) +} const unparseSugaredFunction = ( expression: FunctionExpression,