Skip to content

Commit

Permalink
issue pegjs#30: begin implementing ranges support. Changes in grammar…
Browse files Browse the repository at this point in the history
… and handling in passes.
  • Loading branch information
Mingun committed Jan 1, 2014
1 parent 93d3c6a commit 252b43e
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 4 deletions.
7 changes: 6 additions & 1 deletion lib/compiler/opcodes.js
Expand Up @@ -42,5 +42,10 @@ module.exports = {
/* Failure Reporting */

SILENT_FAILS_ON: 24, // SILENT_FAILS_ON
SILENT_FAILS_OFF: 25 // SILENT_FAILS_FF
SILENT_FAILS_OFF: 25, // SILENT_FAILS_FF

/* Checking array length */

CHECK_MIN_LEN: 27, // CHECK_MIN_LEN len
CHECK_MAX_LEN: 28 // CHECK_MAX_LEN len
};
37 changes: 36 additions & 1 deletion lib/compiler/passes/generate-bytecode.js
Expand Up @@ -168,10 +168,21 @@ var utils = require("../../utils"),
* [25] SILENT_FAILS_OFF
*
* silentFails--;
*
* Checking array length
* ---------------------
*
* [27] CHECK_MIN_LEN len
*
* stack.push(len !== undefined && stack.top().length < len)
*
* [28] CHECK_MAX_LEN len
*
* stack.push(len !== undefined && stack.top().length >=len)
*/
module.exports = function(ast) {
var consts = [];

/// Add new constant to constant list, if it not exist, and return they index in that list.
function addConst(value) {
var index = utils.indexOf(consts, function(c) { return c === value; });

Expand Down Expand Up @@ -512,6 +523,30 @@ module.exports = function(ast) {
);
},

range: function(node, context) {
var emptyArrayIndex = addConst('[]');
expressionCode = generate(node.expression, {
sp: context.sp + 1,
env: { },
action: null
});

return buildSequence(
[op.PUSH, emptyArrayIndex], // var result = []
expressionCode, // var elem = expr();
buildLoop(
[op.WHILE_NOT_ERROR], // while (elem !== null) {
buildSequence(
[op.APPEND], // result.push(elem);
/*TODO: new opcode*/ // if (max !== undefined && result.length >= max) break;
expressionCode // elem = expr();
)
), // }
/*TODO: new opcode*/ // if (min !== undefined && result.length < min) result = null;
[op.POP] // return result;
);
},

rule_ref: function(node) {
return [op.RULE, utils.indexOfRuleByName(ast, node.name)];
},
Expand Down
6 changes: 4 additions & 2 deletions lib/compiler/passes/generate-javascript.js
Expand Up @@ -773,7 +773,7 @@ module.exports = function(ast, options) {
}

parts.push([
'',
' //{ Helper functions',
' function text() {',
' return input.substring(peg$reportedPos, peg$currPos);',
' }',
Expand Down Expand Up @@ -936,17 +936,19 @@ module.exports = function(ast, options) {
' posDetails.column',
' );',
' }',
''
' //}'
].join('\n'));

if (options.optimize === "size") {
parts.push(indent4(generateInterpreter()));
parts.push('');
} else {
parts.push(' //{ Parse rule functions')
utils.each(ast.rules, function(rule) {
parts.push(indent4(generateRuleFunction(rule)));
parts.push('');
});
parts.push(' //}')
}

if (ast.initializer) {
Expand Down
1 change: 1 addition & 0 deletions lib/compiler/passes/report-left-recursion.js
Expand Up @@ -45,6 +45,7 @@ module.exports = function(ast) {
optional: checkExpression,
zero_or_more: checkExpression,
one_or_more: checkExpression,
range: checkExpression,

rule_ref:
function(node, appliedRules) {
Expand Down
1 change: 1 addition & 0 deletions lib/compiler/passes/report-missing-rules.js
Expand Up @@ -27,6 +27,7 @@ module.exports = function(ast) {
optional: checkExpression,
zero_or_more: checkExpression,
one_or_more: checkExpression,
range: checkExpression,

rule_ref:
function(node) {
Expand Down
46 changes: 46 additions & 0 deletions src/parser.pegjs
Expand Up @@ -138,6 +138,38 @@ suffixed
expression: expression
};
}
/ expression:primary r:range {
if (!(r.delimiter !== undefined)) {
if (!(r.max !== undefined)) {// unbounded
if (r.min === 0) {
return {
type: "zero_or_more",
expression: expression
};
} else
if (r.min === 1) {
return {
type: "one_or_more",
expression: expression
};
}
} else
if (r.max === 1) {
if (r.min === 0) {
return {
type: "optional",
expression: expression
};
} else
if (r.min === 1) {
return expression
}
}
}
r.type = "range";
r.expression = expression;
return r;
}
/ primary

primary
Expand All @@ -152,6 +184,16 @@ primary
/ dot { return { type: "any" }; }
/ lparen expression:expression rparen { return expression; }

range
= range_open r:range2 delimiter:(comma primary)? range_close {
r.delimiter = delimiter !== "" ? delimiter[1] : undefined;
return r;
}
range2
= min:int? dots max:int? {return {min:min!==""?min:0, max:max!==""?max:undefined};}
/ val:int {return {min:val, max:val};}
int = n:digit+ __ {return parseInt(n.join(''),10);}

/* "Lexical" elements */

action "action"
Expand Down Expand Up @@ -179,6 +221,10 @@ plus = "+" __ { return "+"; }
lparen = "(" __ { return "("; }
rparen = ")" __ { return ")"; }
dot = "." __ { return "."; }
comma = "," __ { return ","; }
dots = ".." __{ return ".."; }
range_open= "|" __ { return "|"; }
range_close="|" __ { return "|"; }

/*
* Modeled after ECMA-262, 5th ed., 7.6, but much simplified:
Expand Down

0 comments on commit 252b43e

Please sign in to comment.