-
Notifications
You must be signed in to change notification settings - Fork 7
/
operators.js
86 lines (84 loc) · 3.34 KB
/
operators.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
(function (root, factory) { if (typeof define === 'function' && define.amd) {
define(['./Variable'], factory) } else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('./Variable')) // Node
}}(this, function (VariableExports) {
var VBoolean = VariableExports.VBoolean
var VNumber = VariableExports.VNumber
var operatingFunctions = {};
var operators = {};
function getOperatingFunction(expression){
// jshint evil: true
return operatingFunctions[expression] ||
(operatingFunctions[expression] =
new Function('a', 'b', 'return ' + expression));
}
function operator(operator, type, name, precedence, forward, reverseA, reverseB){
// defines the standard operators
var reverse = function(output, inputs){
var a = inputs[0],
b = inputs[1]
var firstError
if(a && a.put){
try {
return a.put(reverseA(output, b && b.valueOf()))
} catch(error) {
if (error.deniedPut) {
firstError = error
} else {
throw error
}
}
}
if(b && b.put){
b.put(reverseB(output, a && a.valueOf()))
} else {
throw (firstError && firstError.message ? firstError : new Error('Can not assign change value to constant operators'))
}
};
// define a function that can lazily ensure the operating function
// is available
var operatorHandler = {
apply: function(instance, args){
forward = getOperatingFunction(forward);
reverseA = reverseA && getOperatingFunction(reverseA);
reverseB = reverseB && getOperatingFunction(reverseB);
forward.reverse = reverse;
operators[operator] = operatorHandler = new VariableExports.Variable(forward);
addFlags(operatorHandler);
args = Array.prototype.slice.call(args);
return operatorHandler.apply(instance, args);
}
};
function addFlags(operatorHandler){
operatorHandler.precedence = precedence;
operatorHandler.infix = reverseB !== false;
}
addFlags(operatorHandler);
operators[operator] = operatorHandler;
operators[name] = function() {
var result = operatorHandler.apply(null, arguments)
return type ? result.as(type) : result
}
}
// using order precedence from:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
operator('+', VNumber, 'add', 6, 'a+b', 'a-b', 'a-b');
operator('-', VNumber, 'subtract', 6, 'a-b', 'a+b', 'b-a');
operator('*', VNumber, 'multiply', 5, 'a*b', 'a/b', 'a/b');
operator('/', VNumber, 'divide', 5, 'a/b', 'a*b', 'b/a');
// operator('^', 7, 'a^b', 'a^(-b)', 'Math.log(a)/Math.log(b)');
operator('?', null, 'if', 16, 'b[a?0:1]', 'a===b[0]||(a===b[1]?false:(function(){throw new Error()})())', '[a,b]');
operator(':', null, 'choose', 15, '[a,b]', 'a[0]?a[1]:(function(){throw new Error()})()', 'a[1]');
operator('!', VBoolean, 'not', 4, '!a', '!a', false);
operator('%', VNumber, 'remainder', 5, 'a%b');
operator('>', VBoolean, 'greater', 8, 'a>b');
operator('>=', VBoolean, 'greaterOrEqual', 8, 'a>=b');
operator('<', VBoolean, 'less', 8, 'a<b');
operator('<=', VBoolean, 'lessOrEqual', 8, 'a<=b');
operator('===', VBoolean, 'strictEqual', 9, 'a===b');
operator('==', VBoolean, 'equal', 9, 'a==b');
operator('&', VBoolean, 'and', 8, 'a&&b');
operator('|', VBoolean, 'or', 8, 'a||b');
operator('nint', VNumber, 'round', 8, 'Math.round(a*Math.pow(10,b||1)/Math.pow(10,b||1))', 'a', 'a');
return operators;
}))