pogo
Version:
A readable, DSL friendly programming language that compiles to JavaScript
163 lines • 7.55 kB
JavaScript
(function() {
var self = this;
var _, codegenUtils;
_ = require("underscore");
codegenUtils = require("../terms/codegenUtils");
module.exports = function(terms) {
var self = this;
var operatorStack, operatorsInDecreasingPrecedenceOrder, operatorTable, createOperatorCall;
operatorStack = function() {
var operators;
operators = [];
return {
push: function(op, popped) {
var self = this;
popped = popped || [];
if (operators.length === 0) {
operators.unshift(op);
return popped;
} else if (!op.precedence || !operators[0].precedence) {
if (!op.precedence) {
throw new Error(op.name + " cannot be used with other operators");
} else if (!operators[0].precedence) {
throw new Error(operators[0].name + " cannot be used with other operators");
}
} else if (op.leftAssociative && op.precedence <= operators[0].precedence) {
popped.push(operators.shift());
return self.push(op, popped);
} else if (op.precedence < operators[0].precedence) {
popped.push(operators.shift());
return self.push(op, popped);
} else {
operators.unshift(op);
return popped;
}
},
pop: function() {
var self = this;
return operators;
}
};
};
operatorsInDecreasingPrecedenceOrder = function(opsString) {
var opLines, precedence, operators, gen1_items, gen2_i, line, match, names, assoc, gen3_items, gen4_i, name;
opLines = opsString.trim().split(/\n/);
precedence = opLines.length + 1;
operators = {};
gen1_items = opLines;
for (gen2_i = 0; gen2_i < gen1_items.length; ++gen2_i) {
line = gen1_items[gen2_i];
match = /\s*((\S+\s+)*)(left|right)/.exec(line);
names = match[1].trim().split(/\s+/);
assoc = match[3];
--precedence;
gen3_items = names;
for (gen4_i = 0; gen4_i < gen3_items.length; ++gen4_i) {
name = gen3_items[gen4_i];
operators[name] = {
name: name,
leftAssociative: assoc === "left",
precedence: precedence
};
}
}
return operators;
};
operatorTable = function() {
var table;
table = operatorsInDecreasingPrecedenceOrder("\n / * % left\n - + left\n << >> >>> left\n > >= < <= left\n == != left\n & left\n ^^ left\n | left\n :: left\n && @and left\n || @or left\n <- left\n ");
return {
findOp: function(op) {
var self = this;
if (table.hasOwnProperty(op)) {
return table[op];
} else {
return {
name: op
};
}
}
};
}();
createOperatorCall = function(name, arguments) {
return terms.functionCall(name, arguments);
};
return terms.term({
constructor: function(complexExpression) {
var self = this;
self.arguments = [ complexExpression ];
return self.name = [];
},
addOperatorExpression: function(operator, expression) {
var self = this;
self.name.push(operator);
return self.arguments.push(expression);
},
expression: function() {
var self = this;
var operands, operators, applyOperators, n, poppedOps;
if (self.arguments.length > 1) {
operands = [ self.arguments[0].expression() ];
operators = operatorStack();
applyOperators = function(ops) {
var gen5_items, gen6_i, op, right, left, name;
gen5_items = ops;
for (gen6_i = 0; gen6_i < gen5_items.length; ++gen6_i) {
op = gen5_items[gen6_i];
right = operands.shift();
left = operands.shift();
name = terms.variable([ codegenUtils.normaliseOperatorName(op.name) ], {
couldBeMacro: false
});
operands.unshift(createOperatorCall(name, [ left, right ]));
}
return void 0;
};
for (n = 0; n < self.name.length; ++n) {
poppedOps = operators.push(operatorTable.findOp(self.name[n]));
applyOperators(poppedOps);
operands.unshift(self.arguments[n + 1].expression());
}
applyOperators(operators.pop());
return operands[0];
} else {
return self.arguments[0].expression();
}
},
hashEntry: function() {
var self = this;
if (self.arguments.length === 1) {
return self.arguments[0].hashEntry();
} else {
return terms.errors.addTermWithMessage(self, "cannot be used as a hash entry");
}
},
definition: function(source, gen7_options) {
var self = this;
var assignment;
assignment = gen7_options !== void 0 && Object.prototype.hasOwnProperty.call(gen7_options, "assignment") && gen7_options.assignment !== void 0 ? gen7_options.assignment : false;
var object, parms;
if (self.arguments.length > 1) {
object = self.arguments[0].expression();
parms = function() {
var gen8_results, gen9_items, gen10_i, arg;
gen8_results = [];
gen9_items = self.arguments.slice(1);
for (gen10_i = 0; gen10_i < gen9_items.length; ++gen10_i) {
arg = gen9_items[gen10_i];
gen8_results.push(arg.expression().parameter());
}
return gen8_results;
}();
return terms.definition(terms.fieldReference(object, self.name), source.blockify(parms, []), {
assignment: assignment
});
} else {
return self.arguments[0].definition(source, {
assignment: assignment
});
}
}
});
};
}).call(this);