Skip to content

Commit 0ed69f0

Browse files
committed
feat: Handle example comments for default start inside the grammar
1 parent 9302fd3 commit 0ed69f0

File tree

2 files changed

+19
-33
lines changed

2 files changed

+19
-33
lines changed

packages/ohm-js/extras/extractExamples.js

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ export const grammarsSource = String.raw`
99
// Example:
1010
//+ "//+ \"x\"\nG {\n//- \"\"\nstart = \"x\"}"
1111
OhmWithExamples <: Ohm {
12-
// The default start rule for Ohm is 'Grammars', which is syntactic rule.
13-
// When the start rule is a syntactic rule, there's no way to get access to
14-
// leading space (including comments). So, for this grammar to be useful,
15-
// you have to explicit use this rule as the start rule.
16-
grammarsWithExamples = (exampleComments applySyntactic<Grammar>)*
17-
18-
Grammar := ident SuperGrammar? "{" (#exampleComments Rule)* "}"
12+
Grammar := ident SuperGrammar? "{" (#exampleComments Rule)* #exampleComments "}"
1913
2014
exampleComments = (spacesNoExampleComment exampleComment)*
2115
@@ -79,19 +73,10 @@ const semantics = grammars.OhmWithExamples.createSemantics().addOperation('hasEx
7973
});
8074

8175
semantics.addOperation('examples', {
82-
grammarsWithExamples(exampleCommentsIter, grammarIter) {
83-
const result = [];
84-
for (const [i, child] of Object.entries(grammarIter.children)) {
85-
if (exampleCommentsIter.hasExamples()) {
86-
const defaultExamples = exampleCommentsIter.child(i).examples();
87-
const grammar = child.grammarName();
88-
result.push(...defaultExamples.map(ex => ({...ex, grammar, rule: ''})));
89-
}
90-
result.push(...child.examples());
91-
}
92-
return result;
76+
Grammars(grammarIter) {
77+
return grammarIter.children.flatMap(c => c.examples());
9378
},
94-
Grammar(name, _, _open, exampleCommentsIter, ruleIter, _close) {
79+
Grammar(name, _, _open, exampleCommentsIter, ruleIter, trailingCommentsIter, _close) {
9580
const result = [];
9681
const grammar = this.grammarName();
9782
for (let i = 0; i < ruleIter.numChildren; i++) {
@@ -103,6 +88,10 @@ semantics.addOperation('examples', {
10388

10489
result.push(...augmentedExamples);
10590
}
91+
if (trailingCommentsIter.hasExamples()) {
92+
const defaultExamples = trailingCommentsIter.examples();
93+
result.push(...defaultExamples.map(ex => ({...ex, grammar, rule: ''})));
94+
}
10695
return result;
10796
},
10897
exampleComments(_, commentIter) {
@@ -128,7 +117,7 @@ semantics.addOperation('examples', {
128117
});
129118

130119
semantics.addOperation('grammarName', {
131-
Grammar(name, _, _open, exampleCommentsIter, ruleIter, _close) {
120+
Grammar(name, _, _open, exampleCommentsIter, ruleIter, trailingCommentsIter, _close) {
132121
return name.sourceString;
133122
},
134123
});
@@ -152,7 +141,7 @@ semantics.addOperation('ruleName', {
152141
* @return {[Example]}
153142
*/
154143
export function extractExamples(grammarsDef) {
155-
const matchResult = grammars.OhmWithExamples.match(grammarsDef, 'grammarsWithExamples');
144+
const matchResult = grammars.OhmWithExamples.match(grammarsDef);
156145
if (matchResult.failed()) {
157146
throw new Error(matchResult.message);
158147
}

packages/ohm-js/test/extras/test-extractExamples.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,35 +35,32 @@ test('simple positive examples', t => {
3535

3636
test('examples for default start rule', t => {
3737
let examples = extractExamples(`
38-
//+ "hey"
3938
G {
4039
//+ ""
4140
start = ""
41+
//+ "hey"
4242
}
4343
`);
4444
t.deepEqual(examples, [
45-
{grammar: 'G', rule: '', example: 'hey', shouldMatch: true},
4645
{grammar: 'G', rule: 'start', example: '', shouldMatch: true},
46+
{grammar: 'G', rule: '', example: 'hey', shouldMatch: true},
4747
]);
4848

4949
examples = extractExamples(`
50-
//+ "hey"
50+
//+ ""
5151
G {
52-
//+ ""
5352
start = ""
53+
//+ "hey"
5454
}
5555
`);
56-
t.deepEqual(examples, [
57-
{grammar: 'G', rule: '', example: 'hey', shouldMatch: true},
58-
{grammar: 'G', rule: 'start', example: '', shouldMatch: true},
59-
]);
56+
t.deepEqual(examples, [{grammar: 'G', rule: '', example: 'hey', shouldMatch: true}]);
6057
});
6158

62-
test('top-level whitespace', t => {
59+
test('whitespace in trailing example comments', t => {
6360
const expected = [{grammar: 'G', rule: '', example: '', shouldMatch: true}];
64-
t.deepEqual(extractExamples(' //+ ""\n G{}'), expected);
65-
t.deepEqual(extractExamples(' //+ "" \nG{}'), expected);
66-
t.deepEqual(extractExamples('\n\n//+ ""\n\nG{}'), expected);
61+
t.deepEqual(extractExamples('G{ //+ ""\n }'), expected);
62+
t.deepEqual(extractExamples('G{ //+ "" \n}'), expected);
63+
t.deepEqual(extractExamples('G{\n\n//+ ""\n\n}'), expected);
6764
});
6865

6966
function getExamples(input) {

0 commit comments

Comments
 (0)