You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pegjs/spec/api/generated-parser-api.spec.js

131 lines
3.9 KiB
JavaScript

describe("generated parser API", function() {
describe("parse", function() {
it("parses input", function() {
var parser = PEG.buildParser('start = "a"');
expect(parser.parse("a")).toBe("a");
});
it("throws an exception on syntax error", function() {
var parser = PEG.buildParser('start = "a"');
expect(function() { parser.parse("b"); }).toThrow();
});
describe("start rule", function() {
var parser = PEG.buildParser([
'a = "x" { return "a"; }',
'b = "x" { return "b"; }',
'c = "x" { return "c"; }'
].join("\n"), { allowedStartRules: ["b", "c"] });
describe("when |startRule| is not set", function() {
it("starts parsing from the first allowed rule", function() {
expect(parser.parse("x")).toBe("b");
});
});
describe("when |startRule| is set to an allowed rule", function() {
it("starts parsing from specified rule", function() {
expect(parser.parse("x", { startRule: "b" })).toBe("b");
expect(parser.parse("x", { startRule: "c" })).toBe("c");
});
});
describe("when |startRule| is set to a disallowed start rule", function() {
it("throws an exception", function() {
expect(
function() { parser.parse("x", { startRule: "a" }); }
).toThrow();
});
});
});
Implement basic support for tracing Parsers can now be generated with support for tracing using the --trace CLI option or a boolean |trace| option to |PEG.buildParser|. This makes them trace their progress, which can be useful for debugging. Parsers generated with tracing support are called "tracing parsers". When a tracing parser executes, by default it traces the rules it enters and exits by writing messages to the console. For example, a parser built from this grammar: start = a / b a = "a" b = "b" will write this to the console when parsing input "b": 1:1 rule.enter start 1:1 rule.enter a 1:1 rule.fail a 1:1 rule.enter b 1:2 rule.match b 1:2 rule.match start You can customize tracing by passing a custom *tracer* to parser's |parse| method using the |tracer| option: parser.parse(input, { trace: tracer }); This will replace the built-in default tracer (which writes to the console) by the tracer you supplied. The tracer must be an object with a |trace| method. This method is called each time a tracing event happens. It takes one argument which is an object describing the tracing event. Currently, three events are supported: * rule.enter -- triggered when a rule is entered * rule.match -- triggered when a rule matches successfully * rule.fail -- triggered when a rule fails to match These events are triggered in nested pairs -- for each rule.enter event there is a matching rule.match or rule.fail event. The event object passed as an argument to |trace| contains these properties: * type -- event type * rule -- name of the rule the event is related to * offset -- parse position at the time of the event * line -- line at the time of the event * column -- column at the time of the event * result -- rule's match result (only for rule.match event) The whole tracing API is somewhat experimental (which is why it isn't documented properly yet) and I expect it will evolve over time as experience is gained. The default tracer is also somewhat bare-bones. I hope that PEG.js user community will develop more sophisticated tracers over time and I'll be able to integrate their best ideas into the default tracer.
10 years ago
describe("tracing", function() {
var parser = PEG.buildParser([
'start = a / b',
'a = "a"',
'b = "b"'
].join("\n"), { trace: true });
describe("default tracer", function() {
it("traces using console.log", function() {
spyOn(console, "log");
parser.parse("b");
expect(console.log).toHaveBeenCalledWith("1:1 rule.enter start");
expect(console.log).toHaveBeenCalledWith("1:1 rule.enter a");
expect(console.log).toHaveBeenCalledWith("1:1 rule.fail a");
expect(console.log).toHaveBeenCalledWith("1:1 rule.enter b");
expect(console.log).toHaveBeenCalledWith("1:2 rule.match b");
expect(console.log).toHaveBeenCalledWith("1:2 rule.match start");
});
});
describe("custom tracers", function() {
describe("trace", function() {
it("receives tracing events", function() {
var tracer = { trace: function() { } };
spyOn(tracer, "trace");
parser.parse("b", { tracer: tracer });
expect(tracer.trace).toHaveBeenCalledWith({
type: 'rule.enter',
rule: 'start',
offset: 0,
line: 1,
column: 1
});
expect(tracer.trace).toHaveBeenCalledWith({
type: 'rule.enter',
rule: 'a',
offset: 0,
line: 1,
column: 1
});
expect(tracer.trace).toHaveBeenCalledWith({
type: 'rule.fail',
rule: 'a',
offset: 0,
line: 1,
column: 1
});
expect(tracer.trace).toHaveBeenCalledWith({
type: 'rule.enter',
rule: 'b',
offset: 0,
line: 1,
column: 1
});
expect(tracer.trace).toHaveBeenCalledWith({
type: 'rule.match',
rule: 'b',
result: 'b',
offset: 1,
line: 1,
column: 2
});
expect(tracer.trace).toHaveBeenCalledWith({
type: 'rule.match',
rule: 'start',
result: 'b',
offset: 1,
line: 1,
column: 2
});
});
});
});
});
it("accepts custom options", function() {
var parser = PEG.buildParser('start = "a"');
parser.parse("a", { foo: 42 });
});
});
});