use :node;
var Node = module.require('./Node').Node;
fn Range(start, operator, to)
extends Node { this.type = 'Range'; this.operator = operator; this.start = start; if this.start? { this.start.parent = this; } this.to = to; if this.to? { this.to.parent = this; }
}
Range.prototype.codegen = () -> {
if !super.codegen() { return; } var isNumber = (n) -> !::isNaN(::parseFloat(n)) && ::isFinite(n); var isNumeric = isNumber(this.start.value) && isNumber(this.to.value); this.start = this.start.codegen(); this.to = this.to.codegen(); var updateOperator, testOperator; if isNumeric { updateOperator = '++' if this.start.value < this.to.value else '--'; testOperator = '<' if this.start.value < this.to.value else '>'; if this.operator == '..' { testOperator += '='; } } if isNumeric && ::Math.abs(this.to.value - this.start.value) <= 20 { this.type = 'ArrayExpression'; this.elements = []; var test = (i) -> { switch testOperator { case '>': { return i > this.to.value; }, case '<': { return i < this.to.value; }, case '>=': { return i >= this.to.value; }, case '<=': { return i <= this.to.value; } } }; for var i = this.start.value; test.call(this, i); i++ if updateOperator == '++' else i-- { this.elements.push({ "type": "Literal", "value": i }); } } else { var testExpression, updateExpression; var declarations = [{ "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "_results" }, "init": { "type": "ArrayExpression", "elements": [] } }]; if isNumeric { testExpression = { "type": "BinaryExpression", "operator": testOperator, "left": { "type": "Identifier", "name": "_i" }, "right": this.to }; updateExpression = { "type": "UpdateExpression", "operator": updateOperator, "argument": { "type": "Identifier", "name": "_i" }, "prefix": false }; } else { if this.start.hasCallExpression() { var startId = { "type": "Identifier", "name": "_start" }; declarations.push({ "type": "VariableDeclarator", "id": startId, "init": this.start }); this.start = startId; } if this.to.hasCallExpression() { var endId = { "type": "Identifier", "name": "_end" }; declarations.push({ "type": "VariableDeclarator", "id": endId, "init": this.to }); this.to = endId; } testExpression = { "type": "ConditionalExpression", "test": { "type": "BinaryExpression", "operator": "<=", "left": this.start, "right": this.to }, "consequent": { "type": "BinaryExpression", "operator": "<" + ('=' if this.operator == '..' else ''), "left": { "type": "Identifier", "name": "_i" }, "right": this.to }, "alternate": { "type": "BinaryExpression", "operator": ">" + ('=' if this.operator == '..' else ''), "left": { "type": "Identifier", "name": "_i" }, "right": this.to } }; updateExpression = { "type": "ConditionalExpression", "test": { "type": "BinaryExpression", "operator": "<=", "left": this.start, "right": this.to }, "consequent": { "type": "UpdateExpression", "operator": "++", "argument": { "type": "Identifier", "name": "_i" }, "prefix": false }, "alternate": { "type": "UpdateExpression", "operator": "--", "argument": { "type": "Identifier", "name": "_i" }, "prefix": false } }; } this.type = 'CallExpression'; this.callee = { "type": "MemberExpression", "computed": false, "object": { "type": "FunctionExpression", "id": null, "params": [], "defaults": [], "body": { "type": "BlockStatement", "body": [ { "type": "VariableDeclaration", "declarations": declarations, "kind": "let" }, { "type": "ForStatement", "init": { "type": "VariableDeclaration", "declarations": [{ "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "_i" }, "init": this.start }], "kind": "let" }, "test": testExpression, "update": updateExpression, "body": { "type": "BlockStatement", "body": [{ "type": "ExpressionStatement", "expression": { "type": "CallExpression", "callee": { "type": "MemberExpression", "computed": false, "object": { "type": "Identifier", "name": "_results" }, "property": { "type": "Identifier", "name": "push" } }, "arguments": [{ "type": "Identifier", "name": "_i" }] } }] } }, { "type": "ReturnStatement", "argument": { "type": "Identifier", "name": "_results" } } ] }, "rest": null, "generator": false, "expression": false }, "property": { "type": "Identifier", "name": "apply" } }; ::Object.defineProperty(this, 'arguments', { value: [{ "type": "ThisExpression" }], enumerable: true }); } return this;
};
Range.prototype.hasCallExpression = () -> true;
exports.Range = Range;