Skip to content

Commit 65e29fc

Browse files
committed
Fix parsing of infix expressions beginning with an object literal
1 parent 01d4a7c commit 65e29fc

File tree

2 files changed

+46
-95
lines changed

2 files changed

+46
-95
lines changed

src/end-to-end.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ testCases(endToEnd, code => code)('end-to-end tests', [
320320
[`b atom.append c atom.prepend a`, either.makeRight('abc')],
321321
[`(b atom.append c) atom.prepend a`, either.makeRight('abc')],
322322
[`a atom.append (c atom.prepend b)`, either.makeRight('abc')],
323+
[
324+
`{ a: "it works!" } object.lookup a`,
325+
either.makeRight({ tag: 'some', value: 'it works!' }),
326+
],
327+
[`{ a: :identity }.a(1) + 1`, either.makeRight('2')],
323328
[
324329
`1
325330
+ 2

src/language/parsing/expression.ts

Lines changed: 41 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -253,16 +253,13 @@ const infixOperator = sequence([
253253
])
254254

255255
const compactExpression: Parser<Molecule | Atom> = oneOf([
256-
// (a => :b).c(d)
256+
// (a)
257257
// (1 + 1)
258+
// (a => :b)(c)
259+
// ({ a: 1 } |> :identity).a
258260
map(
259261
sequence([
260-
surroundedByParentheses(
261-
oneOf([
262-
lazy(() => precededByAtomThenTrivia),
263-
lazy(() => precededByColonThenAtom),
264-
]),
265-
),
262+
surroundedByParentheses(lazy(() => expression)),
266263
compactTrailingIndexesAndArguments,
267264
]),
268265
([expression, trailingIndexesAndArguments]) =>
@@ -275,18 +272,7 @@ const compactExpression: Parser<Molecule | Atom> = oneOf([
275272
// :a.b(1).c
276273
// :f(x)
277274
// :a.b(1)(2)
278-
map(
279-
sequence([
280-
colon,
281-
atomRequiringDotQuotation,
282-
compactTrailingIndexesAndArguments,
283-
]),
284-
([_colon, key, trailingIndexesAndArguments]) =>
285-
trailingIndexesAndArgumentsToExpression(
286-
{ 0: '@lookup', key },
287-
trailingIndexesAndArguments,
288-
),
289-
),
275+
lazy(() => precededByColonThenAtom),
290276
// {}
291277
lazy(() => precededByOpeningBrace),
292278
// 1
@@ -423,53 +409,13 @@ const precededByAtomThenTrivia = map(
423409
// :a.b(1).c
424410
// :f(x)
425411
// :a.b(1)(2)
426-
// :a b.c :z
427-
// :a b.c z
428-
// :f(g) + b
429-
// :a + :b + :c + :d
430412
const precededByColonThenAtom = map(
431-
sequence([
432-
colon,
433-
atomRequiringDotQuotation,
434-
trailingIndexesAndArguments,
435-
zeroOrMore(
436-
map(
437-
// See note in `trailingInfixTokens` about newlines.
438-
oneOf([
439-
sequence([
440-
trivia,
441-
infixOperator,
442-
triviaExceptNewlines,
443-
compactExpression,
444-
]),
445-
sequence([
446-
triviaExceptNewlines,
447-
infixOperator,
448-
trivia,
449-
compactExpression,
450-
]),
451-
]),
452-
([_trivia1, operator, _trivia2, operand]) =>
453-
[operator, operand] as const,
454-
),
455-
),
456-
]),
457-
([_colon, key, trailingIndexesAndArguments, infixOperationTokens]) => {
458-
const initialExpression = trailingIndexesAndArgumentsToExpression(
413+
sequence([colon, atomRequiringDotQuotation, trailingIndexesAndArguments]),
414+
([_colon, key, trailingIndexesAndArguments]) =>
415+
trailingIndexesAndArgumentsToExpression(
459416
{ 0: '@lookup', key },
460417
trailingIndexesAndArguments,
461-
)
462-
const [firstToken, ...additionalTokens] = infixOperationTokens
463-
if (firstToken === undefined) {
464-
return initialExpression
465-
} else {
466-
return infixTokensToExpression([
467-
initialExpression,
468-
...firstToken,
469-
...additionalTokens.flat(),
470-
])
471-
}
472-
},
418+
),
473419
)
474420

475421
// (1 + 1)
@@ -479,36 +425,21 @@ const precededByColonThenAtom = map(
479425
// (1 + 1).b
480426
// (:x => x)(1)
481427
// (:f >> :g)(1)
482-
// (1 + 1) - (1 + 1)
483-
const precededByOpeningParenthesis = oneOf([
484-
map(
485-
sequence([
486-
surroundedByParentheses(lazy(() => expression)),
487-
trailingInfixTokens,
488-
]),
489-
([initialExpression, trailingInfixTokens]) =>
490-
infixTokensToExpression([
491-
initialExpression,
492-
...trailingInfixTokens.flat(),
493-
]),
494-
),
495-
map(
496-
sequence([
497-
surroundedByParentheses(lazy(() => expression)),
428+
const precededByOpeningParenthesis = map(
429+
sequence([
430+
surroundedByParentheses(lazy(() => expression)),
431+
trailingIndexesAndArguments,
432+
]),
433+
([expression, trailingIndexesAndArguments]) =>
434+
trailingIndexesAndArgumentsToExpression(
435+
expression,
498436
trailingIndexesAndArguments,
499-
]),
500-
([expression, trailingIndexesAndArguments]) =>
501-
trailingIndexesAndArgumentsToExpression(
502-
expression,
503-
trailingIndexesAndArguments,
504-
),
505-
),
506-
])
437+
),
438+
)
507439

508440
// {}
509441
// { a: b }
510442
// { 1, 2, 3 }
511-
// {a::f}.a(1) + 1
512443
const precededByOpeningBrace = map(
513444
sequence([sugarFreeMolecule, trailingIndexesAndArguments]),
514445
([expression, trailingIndexesAndArguments]) =>
@@ -518,10 +449,25 @@ const precededByOpeningBrace = map(
518449
),
519450
)
520451

521-
export const expression: Parser<Atom | Molecule> = oneOf([
522-
precededByOpeningParenthesis,
523-
precededByOpeningBrace,
524-
precededByColonThenAtom,
525-
precededByAtomThenTrivia,
526-
atom,
527-
])
452+
export const expression: Parser<Atom | Molecule> = map(
453+
sequence([
454+
oneOf([
455+
precededByOpeningParenthesis,
456+
precededByOpeningBrace,
457+
precededByColonThenAtom,
458+
precededByAtomThenTrivia,
459+
atom,
460+
]),
461+
optional(trailingInfixTokens),
462+
]),
463+
([initialExpression, trailingInfixTokens]) => {
464+
if (trailingInfixTokens === undefined) {
465+
return initialExpression
466+
} else {
467+
return infixTokensToExpression([
468+
initialExpression,
469+
...trailingInfixTokens.flat(),
470+
])
471+
}
472+
},
473+
)

0 commit comments

Comments
 (0)