From d98c51ec37cee9734d5904741621f6004421844e Mon Sep 17 00:00:00 2001 From: Matt Kantor Date: Tue, 28 Jan 2025 17:15:18 -0500 Subject: [PATCH 1/2] Fix a bug with unparsing keywords They do not need quotes. --- src/language/compiling/unparsing.test.ts | 3 +++ src/language/unparsing/plz-utilities.ts | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/language/compiling/unparsing.test.ts b/src/language/compiling/unparsing.test.ts index 59792ba..ae79468 100644 --- a/src/language/compiling/unparsing.test.ts +++ b/src/language/compiling/unparsing.test.ts @@ -24,6 +24,7 @@ testCases( [{}, either.makeRight('{}')], ['a', either.makeRight('a')], ['Hello, world!', either.makeRight('"Hello, world!"')], + ['@test', either.makeRight('@test')], [{ 0: 'a' }, either.makeRight('{ a }')], [{ 1: 'a' }, either.makeRight('{ 1: a }')], [ @@ -67,6 +68,7 @@ testCases( [{}, either.makeRight('{}')], ['a', either.makeRight('a')], ['Hello, world!', either.makeRight('"Hello, world!"')], + ['@test', either.makeRight('@test')], [{ 0: 'a' }, either.makeRight('{\n a\n}')], [{ 1: 'a' }, either.makeRight('{\n 1: a\n}')], [ @@ -115,6 +117,7 @@ testCases( [{}, either.makeRight('{}')], ['a', either.makeRight('"a"')], ['Hello, world!', either.makeRight('"Hello, world!"')], + ['@test', either.makeRight('"@test"')], [{ 0: 'a' }, either.makeRight('{\n "0": "a"\n}')], [{ 1: 'a' }, either.makeRight('{\n "1": "a"\n}')], [ diff --git a/src/language/unparsing/plz-utilities.ts b/src/language/unparsing/plz-utilities.ts index f641ff5..3b80222 100644 --- a/src/language/unparsing/plz-utilities.ts +++ b/src/language/unparsing/plz-utilities.ts @@ -113,9 +113,9 @@ export const sugarFreeMoleculeAsKeyValuePairStrings = ( export const unparseAtom = (atom: string): Right => either.makeRight( - quoteIfNecessary( - /^@[^@]/.test(atom) ? kleur.bold(kleur.underline(atom)) : atom, - ), + /^@[^@]/.test(atom) + ? kleur.bold(kleur.underline(quoteIfNecessary(atom))) + : quoteIfNecessary(atom), ) type UnparseAtomOrMolecule = ( From 3c4e626481c3f2409cc7f9f3ebb049b9563c06ad Mon Sep 17 00:00:00 2001 From: Matt Kantor Date: Thu, 30 Jan 2025 16:47:51 -0500 Subject: [PATCH 2/2] Check for specific keyword while reading expressions This fixes some more unparsing bugs. --- src/language/compiling/unparsing.test.ts | 24 +++++++++++++++++++ src/language/semantics/expression.ts | 8 +++++++ .../semantics/expressions/apply-expression.ts | 4 ++-- .../semantics/expressions/check-expression.ts | 4 ++-- .../expressions/function-expression.ts | 4 ++-- .../expressions/lookup-expression.ts | 4 ++-- .../expressions/runtime-expression.ts | 4 ++-- 7 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/language/compiling/unparsing.test.ts b/src/language/compiling/unparsing.test.ts index ae79468..8a1bb31 100644 --- a/src/language/compiling/unparsing.test.ts +++ b/src/language/compiling/unparsing.test.ts @@ -59,6 +59,17 @@ testCases( }, either.makeRight('(a => :a)("it works!")'), ], + [ + { + 0: '@runtime', + 1: { + 0: '@function', + parameter: 'context', + body: { 0: '@lookup', query: 'context.program.start_time' }, + }, + }, + either.makeRight('{ @runtime, context => :context.program.start_time }'), + ], ]) testCases( @@ -108,6 +119,19 @@ testCases( }, either.makeRight('(a => :a)("it works!")'), ], + [ + { + 0: '@runtime', + 1: { + 0: '@function', + parameter: 'context', + body: { 0: '@lookup', query: 'context.program.start_time' }, + }, + }, + either.makeRight( + '{\n @runtime\n context => :context.program.start_time\n}', + ), + ], ]) testCases( diff --git a/src/language/semantics/expression.ts b/src/language/semantics/expression.ts index 56bbf9d..4573b28 100644 --- a/src/language/semantics/expression.ts +++ b/src/language/semantics/expression.ts @@ -9,3 +9,11 @@ export const isExpression = ( node: SemanticGraph | Molecule, ): node is Expression => typeof node === 'object' && typeof node[0] === 'string' && node[0][0] === '@' + +export const isSpecificExpression = ( + keyword: Keyword, + node: SemanticGraph | Molecule, +): node is { + readonly 0: Keyword +} => + typeof node === 'object' && typeof node[0] === 'string' && node[0] === keyword diff --git a/src/language/semantics/expressions/apply-expression.ts b/src/language/semantics/expressions/apply-expression.ts index dc62309..d74b203 100644 --- a/src/language/semantics/expressions/apply-expression.ts +++ b/src/language/semantics/expressions/apply-expression.ts @@ -1,7 +1,7 @@ import either, { type Either } from '@matt.kantor/either' import type { ElaborationError } from '../../errors.js' import type { Molecule } from '../../parsing.js' -import { isExpression } from '../expression.js' +import { isSpecificExpression } from '../expression.js' import { makeUnelaboratedObjectNode, type ObjectNode } from '../object-node.js' import { type SemanticGraph, type unelaboratedKey } from '../semantic-graph.js' import { readArgumentsFromExpression } from './expression-utilities.js' @@ -15,7 +15,7 @@ export type ApplyExpression = ObjectNode & { export const readApplyExpression = ( node: SemanticGraph | Molecule, ): Either => - isExpression(node) + isSpecificExpression('@apply', node) ? either.map( readArgumentsFromExpression(node, [ ['function', '1'], diff --git a/src/language/semantics/expressions/check-expression.ts b/src/language/semantics/expressions/check-expression.ts index 4af79b3..69d37f7 100644 --- a/src/language/semantics/expressions/check-expression.ts +++ b/src/language/semantics/expressions/check-expression.ts @@ -1,7 +1,7 @@ import either, { type Either } from '@matt.kantor/either' import type { ElaborationError } from '../../errors.js' import type { Molecule } from '../../parsing.js' -import { isExpression } from '../expression.js' +import { isSpecificExpression } from '../expression.js' import { makeUnelaboratedObjectNode, type ObjectNode } from '../object-node.js' import { type SemanticGraph, type unelaboratedKey } from '../semantic-graph.js' import { readArgumentsFromExpression } from './expression-utilities.js' @@ -15,7 +15,7 @@ export type CheckExpression = ObjectNode & { export const readCheckExpression = ( node: SemanticGraph | Molecule, ): Either => - isExpression(node) + isSpecificExpression('@check', node) ? either.map( readArgumentsFromExpression(node, [ ['value', '1'], diff --git a/src/language/semantics/expressions/function-expression.ts b/src/language/semantics/expressions/function-expression.ts index 96fd5d4..b67e469 100644 --- a/src/language/semantics/expressions/function-expression.ts +++ b/src/language/semantics/expressions/function-expression.ts @@ -1,7 +1,7 @@ import either, { type Either } from '@matt.kantor/either' import type { ElaborationError } from '../../errors.js' import type { Atom, Molecule } from '../../parsing.js' -import { isExpression } from '../expression.js' +import { isSpecificExpression } from '../expression.js' import { makeUnelaboratedObjectNode, type ObjectNode } from '../object-node.js' import { serialize, @@ -22,7 +22,7 @@ export type FunctionExpression = ObjectNode & { export const readFunctionExpression = ( node: SemanticGraph | Molecule, ): Either => - isExpression(node) + isSpecificExpression('@function', node) ? either.flatMap( readArgumentsFromExpression(node, [ ['parameter', '1'], diff --git a/src/language/semantics/expressions/lookup-expression.ts b/src/language/semantics/expressions/lookup-expression.ts index 241ddb6..a2801b7 100644 --- a/src/language/semantics/expressions/lookup-expression.ts +++ b/src/language/semantics/expressions/lookup-expression.ts @@ -1,7 +1,7 @@ import either, { type Either } from '@matt.kantor/either' import type { ElaborationError, InvalidExpressionError } from '../../errors.js' import type { Molecule } from '../../parsing.js' -import { isExpression } from '../expression.js' +import { isSpecificExpression } from '../expression.js' import { isFunctionNode } from '../function-node.js' import { keyPathToMolecule, type KeyPath } from '../key-path.js' import { @@ -23,7 +23,7 @@ export type LookupExpression = ObjectNode & { export const readLookupExpression = ( node: SemanticGraph | Molecule, ): Either => - isExpression(node) + isSpecificExpression('@lookup', node) ? either.flatMap( readArgumentsFromExpression(node, [['query', '1']]), ([q]) => { diff --git a/src/language/semantics/expressions/runtime-expression.ts b/src/language/semantics/expressions/runtime-expression.ts index f9ccf09..b8cd1b9 100644 --- a/src/language/semantics/expressions/runtime-expression.ts +++ b/src/language/semantics/expressions/runtime-expression.ts @@ -1,7 +1,7 @@ import either, { type Either } from '@matt.kantor/either' import type { ElaborationError } from '../../errors.js' import type { Molecule } from '../../parsing.js' -import { isExpression } from '../expression.js' +import { isSpecificExpression } from '../expression.js' import { isFunctionNode } from '../function-node.js' import { makeUnelaboratedObjectNode, type ObjectNode } from '../object-node.js' import { @@ -22,7 +22,7 @@ export type RuntimeExpression = ObjectNode & { export const readRuntimeExpression = ( node: SemanticGraph | Molecule, ): Either => - isExpression(node) + isSpecificExpression('@runtime', node) ? either.flatMap( readArgumentsFromExpression(node, [['function', '1']]), ([f]) => {