Allow labeled expressions in the metagrammar (without any meaning yet)

redux
David Majda 14 years ago
parent 409ddf2ae8
commit 52704593cd

@ -275,6 +275,7 @@ PEG.Compiler = {
rule: checkExpression, rule: checkExpression,
choice: checkSubnodes("alternatives"), choice: checkSubnodes("alternatives"),
sequence: checkSubnodes("elements"), sequence: checkSubnodes("elements"),
labeled: checkExpression,
and_predicate: checkExpression, and_predicate: checkExpression,
not_predicate: checkExpression, not_predicate: checkExpression,
optional: checkExpression, optional: checkExpression,
@ -340,6 +341,7 @@ PEG.Compiler = {
} }
}, },
labeled: checkExpression,
and_predicate: checkExpression, and_predicate: checkExpression,
not_predicate: checkExpression, not_predicate: checkExpression,
optional: checkExpression, optional: checkExpression,
@ -406,6 +408,7 @@ PEG.Compiler = {
rule: replaceInExpression, rule: replaceInExpression,
choice: replaceInSubnodes("alternatives"), choice: replaceInSubnodes("alternatives"),
sequence: replaceInSubnodes("elements"), sequence: replaceInSubnodes("elements"),
labeled: replaceInExpression,
and_predicate: replaceInExpression, and_predicate: replaceInExpression,
not_predicate: replaceInExpression, not_predicate: replaceInExpression,
optional: replaceInExpression, optional: replaceInExpression,
@ -596,6 +599,10 @@ PEG.Compiler = {
); );
}, },
labeled: function(node, resultVar) {
return PEG.Compiler.compileNode(node.expression, resultVar);
},
and_predicate: function(node, resultVar) { and_predicate: function(node, resultVar) {
var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos"); var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos");
var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar"); var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar");

File diff suppressed because it is too large Load Diff

@ -35,7 +35,7 @@ choice
} }
sequence sequence
= prefixed* action { = labeled* action {
var expression = $1.length != 1 var expression = $1.length != 1
? { ? {
type: "sequence", type: "sequence",
@ -48,7 +48,7 @@ sequence
action: $2 action: $2
}; };
} }
/ prefixed* { / labeled* {
return $1.length != 1 return $1.length != 1
? { ? {
type: "sequence", type: "sequence",
@ -57,6 +57,16 @@ sequence
: $1[0]; : $1[0];
} }
labeled
= identifier colon prefixed {
return {
type: "labeled",
label: $1,
expression: $3
};
}
/ prefixed
prefixed prefixed
= and suffixed { return { type: "and_predicate", expression: $2 }; } = and suffixed { return { type: "and_predicate", expression: $2 }; }
/ not suffixed { return { type: "not_predicate", expression: $2 }; } / not suffixed { return { type: "not_predicate", expression: $2 }; }
@ -90,6 +100,7 @@ nonBraceCharacter
= [^{}] = [^{}]
equals = "=" __ { return $1; } equals = "=" __ { return $1; }
colon = ":" __ { return $1; }
slash = "/" __ { return $1; } slash = "/" __ { return $1; }
and = "&" __ { return $1; } and = "&" __ { return $1; }
not = "!" __ { return $1; } not = "!" __ { return $1; }

@ -206,6 +206,7 @@ test("buildParser reports missing referenced rules", function() {
'start = "a" / "b" / missing', 'start = "a" / "b" / missing',
'start = missing "a" "b"', 'start = missing "a" "b"',
'start = "a" "b" missing', 'start = "a" "b" missing',
'start = label:missing',
'start = &missing', 'start = &missing',
'start = !missing', 'start = !missing',
'start = missing?', 'start = missing?',
@ -230,6 +231,7 @@ test("buildParser reports left recursion", function() {
'start = start / "a" / "b"', 'start = start / "a" / "b"',
'start = "a" / "b" / start', 'start = "a" / "b" / start',
'start = start "a" "b"', 'start = start "a" "b"',
'start = label:start',
'start = &start', 'start = &start',
'start = !start', 'start = !start',
'start = start?', 'start = start?',
@ -289,6 +291,12 @@ test("sequences", function() {
parses(posTestParser, "a", "a"); parses(posTestParser, "a", "a");
}); });
test("labels", function() {
var parser = PEG.buildParser('start = label:"a"');
parses(parser, "a", "a");
doesNotParse(parser, "b");
});
test("and predicate", function() { test("and predicate", function() {
var parser = PEG.buildParser('start = "a" &"b" "b"'); var parser = PEG.buildParser('start = "a" &"b" "b"');
parses(parser, "ab", ["a", "", "b"]); parses(parser, "ab", ["a", "", "b"]);

@ -43,6 +43,14 @@ function sequence(elements) {
}; };
} }
function labeled(label, expression) {
return {
type: "labeled",
label: label,
expression: expression
};
}
function nodeWithExpressionConstructor(type) { function nodeWithExpressionConstructor(type) {
return function(expression) { return function(expression) {
return { return {
@ -100,12 +108,12 @@ var literalIjkl = literal("ijkl");
var optionalLiteral = optional(literalAbcd); var optionalLiteral = optional(literalAbcd);
var notAbcd = notPredicate(literalAbcd); var labeledAbcd = labeled("a", literalAbcd);
var notEfgh = notPredicate(literalEfgh); var labeledEfgh = labeled("e", literalEfgh);
var notIjkl = notPredicate(literalIjkl); var labeledIjkl = labeled("i", literalIjkl);
var sequenceEmpty = sequence([]); var sequenceEmpty = sequence([]);
var sequenceNots = sequence([notAbcd, notEfgh, notIjkl]); var sequenceLabeleds = sequence([labeledAbcd, labeledEfgh, labeledIjkl]);
var sequenceLiterals = sequence([literalAbcd, literalEfgh, literalIjkl]); var sequenceLiterals = sequence([literalAbcd, literalEfgh, literalIjkl]);
var choiceLiterals = choice([literalAbcd, literalEfgh, literalIjkl]); var choiceLiterals = choice([literalAbcd, literalEfgh, literalIjkl]);
@ -194,19 +202,31 @@ test("parses sequence", function() {
oneRuleGrammar(action(sequenceEmpty, " code ")) oneRuleGrammar(action(sequenceEmpty, " code "))
); );
grammarParserParses( grammarParserParses(
'start = !"abcd" { code }', 'start = a:"abcd" { code }',
oneRuleGrammar(action(notAbcd, " code ")) oneRuleGrammar(action(labeledAbcd, " code "))
);
grammarParserParses(
'start = a:"abcd" e:"efgh" i:"ijkl" { code }',
oneRuleGrammar(action(sequenceLabeleds, " code "))
); );
grammarParserParses('start = ', oneRuleGrammar(sequenceEmpty));
grammarParserParses('start = a:"abcd"', oneRuleGrammar(labeledAbcd));
grammarParserParses( grammarParserParses(
'start = !"abcd" !"efgh" !"ijkl" { code }', 'start = a:"abcd" e:"efgh" i:"ijkl"',
oneRuleGrammar(action(sequenceNots, " code ")) oneRuleGrammar(sequenceLabeleds)
); );
});
grammarParserParses('start = ', oneRuleGrammar(sequenceEmpty)); /* Canonical labeled is "label:\"abcd\"". */
grammarParserParses('start = !"abcd"', oneRuleGrammar(notAbcd)); test("parses labeled", function() {
grammarParserParses(
'start = label:!"abcd"',
oneRuleGrammar(labeled("label", notPredicate(literalAbcd)))
);
grammarParserParses( grammarParserParses(
'start = !"abcd" !"efgh" !"ijkl"', 'start = !"abcd"',
oneRuleGrammar(sequenceNots) oneRuleGrammar(notPredicate(literalAbcd))
); );
}); });

Loading…
Cancel
Save