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,
choice: checkSubnodes("alternatives"),
sequence: checkSubnodes("elements"),
labeled: checkExpression,
and_predicate: checkExpression,
not_predicate: checkExpression,
optional: checkExpression,
@ -340,6 +341,7 @@ PEG.Compiler = {
}
},
labeled: checkExpression,
and_predicate: checkExpression,
not_predicate: checkExpression,
optional: checkExpression,
@ -406,6 +408,7 @@ PEG.Compiler = {
rule: replaceInExpression,
choice: replaceInSubnodes("alternatives"),
sequence: replaceInSubnodes("elements"),
labeled: replaceInExpression,
and_predicate: replaceInExpression,
not_predicate: 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) {
var savedPosVar = PEG.Compiler.generateUniqueIdentifier("savedPos");
var savedReportMatchFailuresVar = PEG.Compiler.generateUniqueIdentifier("savedReportMatchFailuresVar");

File diff suppressed because it is too large Load Diff

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

@ -206,6 +206,7 @@ test("buildParser reports missing referenced rules", function() {
'start = "a" / "b" / missing',
'start = missing "a" "b"',
'start = "a" "b" missing',
'start = label:missing',
'start = &missing',
'start = !missing',
'start = missing?',
@ -230,6 +231,7 @@ test("buildParser reports left recursion", function() {
'start = start / "a" / "b"',
'start = "a" / "b" / start',
'start = start "a" "b"',
'start = label:start',
'start = &start',
'start = !start',
'start = start?',
@ -289,6 +291,12 @@ test("sequences", function() {
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() {
var parser = PEG.buildParser('start = "a" &"b" "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) {
return function(expression) {
return {
@ -100,12 +108,12 @@ var literalIjkl = literal("ijkl");
var optionalLiteral = optional(literalAbcd);
var notAbcd = notPredicate(literalAbcd);
var notEfgh = notPredicate(literalEfgh);
var notIjkl = notPredicate(literalIjkl);
var labeledAbcd = labeled("a", literalAbcd);
var labeledEfgh = labeled("e", literalEfgh);
var labeledIjkl = labeled("i", literalIjkl);
var sequenceEmpty = sequence([]);
var sequenceNots = sequence([notAbcd, notEfgh, notIjkl]);
var sequenceLabeleds = sequence([labeledAbcd, labeledEfgh, labeledIjkl]);
var sequenceLiterals = sequence([literalAbcd, literalEfgh, literalIjkl]);
var choiceLiterals = choice([literalAbcd, literalEfgh, literalIjkl]);
@ -194,19 +202,31 @@ test("parses sequence", function() {
oneRuleGrammar(action(sequenceEmpty, " code "))
);
grammarParserParses(
'start = !"abcd" { code }',
oneRuleGrammar(action(notAbcd, " code "))
'start = a:"abcd" { 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(
'start = !"abcd" !"efgh" !"ijkl" { code }',
oneRuleGrammar(action(sequenceNots, " code "))
'start = a:"abcd" e:"efgh" i:"ijkl"',
oneRuleGrammar(sequenceLabeleds)
);
});
grammarParserParses('start = ', oneRuleGrammar(sequenceEmpty));
grammarParserParses('start = !"abcd"', oneRuleGrammar(notAbcd));
/* Canonical labeled is "label:\"abcd\"". */
test("parses labeled", function() {
grammarParserParses(
'start = label:!"abcd"',
oneRuleGrammar(labeled("label", notPredicate(literalAbcd)))
);
grammarParserParses(
'start = !"abcd" !"efgh" !"ijkl"',
oneRuleGrammar(sequenceNots)
'start = !"abcd"',
oneRuleGrammar(notPredicate(literalAbcd))
);
});

Loading…
Cancel
Save