Skip to content

Commit e18bd6a

Browse files
committed
Factor out literal parsers to shared static constants
1 parent 0138f72 commit e18bd6a

File tree

6 files changed

+95
-47
lines changed

6 files changed

+95
-47
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ data representation implied by the fact that a value is an atom (e.g. the atom
5151
`2` may be an integer in memory).
5252

5353
Bare words not containing any
54-
[reserved character sequences](./src/language/parsing/atom.ts#L19-L41) are
54+
[reserved character sequences](./src/language/parsing/atom.ts#L33-L57) are
5555
atoms:
5656

5757
```

src/language/parsing/atom.ts

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,54 @@ import {
88
oneOf,
99
oneOrMore,
1010
sequence,
11-
zeroOrMore
11+
zeroOrMore,
1212
} from '@matt.kantor/parsing'
13+
import {
14+
backslash,
15+
closingBlockCommentDelimiter,
16+
closingBrace,
17+
closingParenthesis,
18+
colon,
19+
comma,
20+
escapedBackslash,
21+
escapedQuote,
22+
openingBlockCommentDelimiter,
23+
openingBrace,
24+
openingParenthesis,
25+
quote,
26+
singleLineCommentDelimiter,
27+
} from './literals.js'
1328
import { optionallySurroundedByParentheses } from './parentheses.js'
1429
import { whitespace } from './trivia.js'
1530

1631
export type Atom = string
1732

1833
const atomComponentsRequiringQuotation = [
34+
backslash,
35+
closingBlockCommentDelimiter,
36+
closingBrace,
37+
closingParenthesis,
38+
colon,
39+
comma,
40+
openingBlockCommentDelimiter,
41+
openingBrace,
42+
openingParenthesis,
43+
quote,
44+
singleLineCommentDelimiter,
1945
whitespace,
20-
literal('"'),
21-
literal('{'),
22-
literal('}'),
46+
47+
// Reserved for future use:
2348
literal('['),
2449
literal(']'),
25-
literal('('),
26-
literal(')'),
2750
literal('<'),
2851
literal('>'),
2952
literal('#'),
3053
literal('&'),
3154
literal('|'),
32-
literal('\\'),
3355
literal('='),
34-
literal(':'),
3556
literal(';'),
36-
literal(','),
37-
literal('//'),
38-
literal('/*'),
39-
literal('*/'),
4057
] as const
4158

42-
4359
export const atomWithAdditionalQuotationRequirements = (
4460
additionalQuoteRequiringComponent: Parser<unknown>,
4561
) =>
@@ -75,23 +91,19 @@ export const unquotedAtomParser = map(
7591

7692
const quotedAtomParser = map(
7793
sequence([
78-
literal('"'),
94+
quote,
7995
map(
8096
zeroOrMore(
8197
oneOf([
8298
// `"` and `\` need to be escaped
83-
butNot(
84-
anySingleCharacter,
85-
oneOf([literal('"'), literal('\\')]),
86-
'`"` or `\\`',
87-
),
88-
as(literal('\\"'), '"'),
89-
as(literal('\\\\'), '\\'),
99+
butNot(anySingleCharacter, oneOf([quote, backslash]), '`"` or `\\`'),
100+
as(escapedQuote, '"'),
101+
as(escapedBackslash, '\\'),
90102
]),
91103
),
92104
output => output.join(''),
93105
),
94-
literal('"'),
106+
quote,
95107
]),
96108
([_1, contents, _2]) => contents,
97109
)

src/language/parsing/literals.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { literal } from '@matt.kantor/parsing'
2+
3+
export const arrow = literal('=>')
4+
export const asterisk = literal('*')
5+
export const backslash = literal('\\')
6+
export const closingBlockCommentDelimiter = literal('*/')
7+
export const closingBrace = literal('}')
8+
export const closingParenthesis = literal(')')
9+
export const colon = literal(':')
10+
export const comma = literal(',')
11+
export const dot = literal('.')
12+
export const escapedBackslash = literal('\\\\')
13+
export const escapedQuote = literal('\\"')
14+
export const newline = literal('\n')
15+
export const openingBlockCommentDelimiter = literal('/*')
16+
export const openingBrace = literal('{')
17+
export const openingParenthesis = literal('(')
18+
export const quote = literal('"')
19+
export const singleLineCommentDelimiter = literal('//')
20+
export const slash = literal('/')

src/language/parsing/molecule.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
lazy,
3-
literal,
43
map,
54
nothing,
65
oneOf,
@@ -15,6 +14,16 @@ import {
1514
atomWithAdditionalQuotationRequirements,
1615
type Atom,
1716
} from './atom.js'
17+
import {
18+
arrow,
19+
closingBrace,
20+
closingParenthesis,
21+
colon,
22+
comma,
23+
dot,
24+
openingBrace,
25+
openingParenthesis,
26+
} from './literals.js'
1827
import { optionallySurroundedByParentheses } from './parentheses.js'
1928
import { trivia } from './trivia.js'
2029

@@ -43,7 +52,7 @@ const propertyValue = oneOf([
4352
])
4453

4554
const namedProperty = map(
46-
sequence([propertyKey, literal(':'), optional(trivia), propertyValue]),
55+
sequence([propertyKey, colon, optional(trivia), propertyValue]),
4756
([key, _colon, _trivia, value]) => [key, value] as const,
4857
)
4958

@@ -56,17 +65,17 @@ const property = (index: Indexer) =>
5665
)
5766

5867
const propertyDelimiter = oneOf([
59-
sequence([optional(trivia), literal(','), optional(trivia)]),
68+
sequence([optional(trivia), comma, optional(trivia)]),
6069
trivia,
6170
])
6271

6372
const argument = map(
6473
sequence([
65-
literal('('),
74+
openingParenthesis,
6675
optional(trivia),
6776
propertyValue,
6877
optional(trivia),
69-
literal(')'),
78+
closingParenthesis,
7079
]),
7180
([_openingParenthesis, _trivia1, argument, _trivia2, _closingParenthesis]) =>
7281
argument,
@@ -75,9 +84,9 @@ const argument = map(
7584
const dottedKeyPathComponent = map(
7685
sequence([
7786
optional(trivia),
78-
literal('.'),
87+
dot,
7988
optional(trivia),
80-
atomWithAdditionalQuotationRequirements(literal('.')),
89+
atomWithAdditionalQuotationRequirements(dot),
8190
]),
8291
([_trivia1, _dot, _trivia2, key]) => key,
8392
)
@@ -87,7 +96,7 @@ const moleculeAsEntries = (
8796
): Parser<readonly (readonly [string, string | Molecule])[]> =>
8897
map(
8998
sequence([
90-
literal('{'),
99+
openingBrace,
91100
// Allow initial property not preceded by a delimiter (e.g. `{a b}`).
92101
optional(property(index)),
93102
zeroOrMore(
@@ -97,7 +106,7 @@ const moleculeAsEntries = (
97106
),
98107
),
99108
optional(propertyDelimiter),
100-
literal('}'),
109+
closingBrace,
101110
]),
102111
([
103112
_openingBrace,
@@ -121,17 +130,17 @@ const sugarFreeMolecule: Parser<Molecule> = optionallySurroundedByParentheses(
121130
const sugaredLookup: Parser<Molecule> = optionallySurroundedByParentheses(
122131
map(
123132
sequence([
124-
literal(':'),
133+
colon,
125134
// Reserve `.` so that `:a.b` is parsed as a lookup followed by an index.
126-
atomWithAdditionalQuotationRequirements(literal('.')),
135+
atomWithAdditionalQuotationRequirements(dot),
127136
]),
128137
([_colon, key]) => ({ 0: '@lookup', key }),
129138
),
130139
)
131140

132141
const sugaredFunction: Parser<Molecule> = optionallySurroundedByParentheses(
133142
map(
134-
sequence([atomParser, trivia, literal('=>'), trivia, propertyValue]),
143+
sequence([atomParser, trivia, arrow, trivia, propertyValue]),
135144
([parameter, _trivia1, _arrow, _trivia2, body]) => ({
136145
0: '@function',
137146
parameter,

src/language/parsing/parentheses.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import {
2-
literal,
32
map,
43
oneOf,
54
sequence,
65
zeroOrMore,
76
type Parser,
87
} from '@matt.kantor/parsing'
8+
import { closingParenthesis, openingParenthesis } from './literals.js'
99
import { trivia } from './trivia.js'
1010

1111
const optionallySurroundedBy = <Output>(
@@ -24,13 +24,13 @@ export const optionallySurroundedByParentheses = <Output>(
2424
oneOf([
2525
// This allows `theParser` to greedily consume trivia.
2626
optionallySurroundedBy(
27-
literal('('),
27+
openingParenthesis,
2828
theParser,
29-
sequence([zeroOrMore(trivia), literal(')')]),
29+
sequence([zeroOrMore(trivia), closingParenthesis]),
3030
),
3131
optionallySurroundedBy(
32-
sequence([literal('('), zeroOrMore(trivia)]),
32+
sequence([openingParenthesis, zeroOrMore(trivia)]),
3333
theParser,
34-
sequence([zeroOrMore(trivia), literal(')')]),
34+
sequence([zeroOrMore(trivia), closingParenthesis]),
3535
),
3636
])

src/language/parsing/trivia.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,36 @@
11
import {
22
anySingleCharacter,
33
butNot,
4-
literal,
54
lookaheadNot,
65
oneOf,
76
oneOrMore,
87
regularExpression,
98
sequence,
109
zeroOrMore,
1110
} from '@matt.kantor/parsing'
11+
import {
12+
asterisk,
13+
closingBlockCommentDelimiter,
14+
newline,
15+
openingBlockCommentDelimiter,
16+
singleLineCommentDelimiter,
17+
slash,
18+
} from './literals.js'
1219

1320
const blockComment = sequence([
14-
literal('/*'),
21+
openingBlockCommentDelimiter,
1522
zeroOrMore(
1623
oneOf([
17-
butNot(anySingleCharacter, literal('*'), '*'),
18-
lookaheadNot(literal('*'), literal('/'), '/'),
24+
butNot(anySingleCharacter, asterisk, '*'),
25+
lookaheadNot(asterisk, slash, '/'),
1926
]),
2027
),
21-
literal('*/'),
28+
closingBlockCommentDelimiter,
2229
])
2330

2431
const singleLineComment = sequence([
25-
literal('//'),
26-
zeroOrMore(butNot(anySingleCharacter, literal('\n'), 'newline')),
32+
singleLineCommentDelimiter,
33+
zeroOrMore(butNot(anySingleCharacter, newline, 'newline')),
2734
])
2835

2936
export const whitespace = regularExpression(/^\s+/)

0 commit comments

Comments
 (0)