Skip to content

Commit df1cfa2

Browse files
authored
Merge pull request #56 from mkantor/optimize-molecule-parsers
Micro-optimize parsers in molecule.ts
2 parents 77c515b + 163f602 commit df1cfa2

File tree

1 file changed

+39
-34
lines changed

1 file changed

+39
-34
lines changed

src/language/parsing/molecule.ts

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
zeroOrMore,
99
type Parser,
1010
} from '@matt.kantor/parsing'
11+
import type { Writable } from '../../utility-types.js'
1112
import { keyPathToMolecule } from '../semantics.js'
1213
import {
1314
atomParser,
@@ -57,13 +58,12 @@ const namedProperty = map(
5758
([key, _colon, _trivia, value]) => [key, value] as const,
5859
)
5960

60-
const numberedProperty = (index: Indexer) =>
61-
map(propertyValue, value => [index(), value] as const)
62-
63-
const property = (index: Indexer) =>
64-
optionallySurroundedByParentheses(
65-
oneOf([namedProperty, numberedProperty(index)]),
66-
)
61+
const propertyWithOptionalKey = optionallySurroundedByParentheses(
62+
oneOf([
63+
namedProperty,
64+
map(propertyValue, value => [undefined, value] as const),
65+
]),
66+
)
6767

6868
const propertyDelimiter = oneOf([
6969
sequence([optionalTrivia, comma, optionalTrivia]),
@@ -92,43 +92,48 @@ const dottedKeyPathComponent = map(
9292
([_trivia1, _dot, _trivia2, key]) => key,
9393
)
9494

95-
const moleculeAsEntries = (
96-
index: Indexer,
97-
): Parser<readonly (readonly [string, string | Molecule])[]> =>
95+
const sugarFreeMolecule: Parser<Molecule> = optionallySurroundedByParentheses(
9896
map(
9997
sequence([
10098
openingBrace,
101-
optional(trivia),
102-
// Allow initial property not preceded by a delimiter (e.g. `{a b}`).
103-
optional(property(index)),
104-
zeroOrMore(
105-
map(
106-
sequence([propertyDelimiter, property(index)]),
107-
([_delimiter, property]) => property,
99+
optionalTrivia,
100+
sequence([
101+
// Allow initial property not preceded by a delimiter (e.g. `{a, b}`).
102+
optional(propertyWithOptionalKey),
103+
zeroOrMore(
104+
map(
105+
sequence([propertyDelimiter, propertyWithOptionalKey]),
106+
([_delimiter, property]) => property,
107+
),
108108
),
109-
),
109+
]),
110110
optional(propertyDelimiter),
111-
optional(trivia),
111+
optionalTrivia,
112112
closingBrace,
113113
]),
114114
([
115115
_openingBrace,
116-
_optionalLeadingTrivia,
117-
optionalInitialProperty,
118-
remainingProperties,
119-
_optionalDelimiter,
120-
_optionalTrailingTrivia,
116+
_trivia1,
117+
[optionalInitialProperty, remainingProperties],
118+
_trailingDelimiter,
119+
_trivia2,
121120
_closingBrace,
122-
]) =>
123-
optionalInitialProperty === undefined
124-
? remainingProperties
125-
: [optionalInitialProperty, ...remainingProperties],
126-
)
127-
128-
const sugarFreeMolecule: Parser<Molecule> = optionallySurroundedByParentheses(
129-
map(
130-
lazy(() => moleculeAsEntries(makeIncrementingIndexer())),
131-
Object.fromEntries,
121+
]) => {
122+
const properties =
123+
optionalInitialProperty === undefined
124+
? remainingProperties
125+
: [optionalInitialProperty, ...remainingProperties]
126+
const enumerate = makeIncrementingIndexer()
127+
return properties.reduce((molecule: Writable<Molecule>, [key, value]) => {
128+
if (key === undefined) {
129+
// Note that `enumerate()` increments its internal counter as a side effect.
130+
molecule[enumerate()] = value
131+
} else {
132+
molecule[key] = value
133+
}
134+
return molecule
135+
}, {})
136+
},
132137
),
133138
)
134139

0 commit comments

Comments
 (0)