123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- "use strict";
- var Cast = require("cast.js");
- var Code = require("code.js");
- var Errors = require("errors.js");
- var Type = require("type.js");
- var precedence = {
- unary: 4,
- mulDivMod: 5,
- addSub: 6,
- shift: 7,
- relational: 8,
- equal: 9,
- bitAnd: 10,
- bitXor: 11,
- bitOr: 12,
- and: 13,
- or: 14,
- conditional: 15,
- assignment: 17
- };
- function makeBinary(op, code, precedence, resultPrecedence){
- return function(left, right, context){
- var leftValue = left.constValue();
- var rightValue = right.constValue();
- var value = (leftValue !== undefined && rightValue !== undefined)
- ? op(leftValue, rightValue) : undefined;
- var leftCode = Code.adjustPrecedence(left.deref(), precedence);
- // right code needs parentheses even if it has the same percedence
- var rightCode = Code.adjustPrecedence(right.deref(), precedence - 1);
- var expCode = (typeof code == "function")
- ? code(leftCode, rightCode, context)
- : leftCode + code + rightCode;
- return new Code.Expression(expCode, left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
- };
- }
- function makeUnary(op, code){
- return function(e){
- var type = e.type();
- var value = e.constValue();
- if (value !== undefined)
- value = op(value, type) ;
- var expCode = code + Code.adjustPrecedence(e.deref(), precedence.unary);
- return new Code.Expression(expCode, type, undefined, value);
- };
- }
- var mul = makeBinary(function(x, y){return x * y;}, " * ", precedence.mulDivMod);
- var div = makeBinary(function(x, y){return x / y;}, " / ", precedence.mulDivMod);
- function pow2(e){
- return new Code.Expression("Math.pow(2, " + e.deref().code() + ")",
- Type.basic.real);
- }
- function log2(e){
- return new Code.Expression("(Math.log(" + e.deref().code() + ") / Math.LN2) | 0",
- Type.basic.integer, undefined, undefined, precedence.bitOr);
- }
- function assign(left, right, context){
- var info = left.designator().info();
- if (!(info instanceof Type.Variable) || info.isReadOnly())
- throw new Errors.Error("cannot assign to " + info.idType());
- var leftCode = left.code();
- var leftType = left.type();
- var rightCode = right.code();
- var rightType = right.type();
- var isArray = leftType instanceof Type.Array;
- if (isArray
- && leftType.elementsType() == Type.basic.ch
- && rightType instanceof Type.String){
- if (leftType.length() === undefined)
- throw new Errors.Error("string cannot be assigned to open " + leftType.description());
- if (rightType.length() > leftType.length())
- throw new Errors.Error(
- leftType.length() + "-character ARRAY is too small for "
- + rightType.length() + "-character string");
- return context.rtl().assignArrayFromString(leftCode, rightCode);
- }
- var castOperation = Cast.implicit(rightType, leftType);
- if (!castOperation)
- throw new Errors.Error("type mismatch: '" + leftCode
- + "' is '" + leftType.description()
- + "' and cannot be assigned to '" + rightType.description() + "' expression");
- if (isArray && rightType instanceof Type.Array){
- if (leftType.length() === undefined)
- throw new Errors.Error("'" + leftCode
- + "' is open '" + leftType.description()
- + "' and cannot be assigned");
- }
-
- if (isArray || rightType instanceof Type.Record)
- return context.rtl().copy(rightCode, leftCode);
- var castCode = castOperation(context, right.deref()).code();
- rightCode = castCode ? castCode : rightCode;
- return leftCode + (info instanceof Type.VariableRef
- ? ".set(" + rightCode + ")"
- : " = " + rightCode);
- }
- function makeInplace(code, altOp){
- return function(left, right){
- var info = left.designator().info();
- if (info instanceof Type.VariableRef)
- return assign(left, altOp(left, right));
- return left.code() + code + right.deref().code();
- };
- }
- function makeBinaryInt(op, code, prec){
- return makeBinary(
- function(x, y){return op(x, y) | 0;},
- function(x, y){return x + code + y + " | 0";},
- prec,
- precedence.bitOr);
- }
- var operators = {
- add: makeBinary( function(x, y){return x + y;}, " + ", precedence.addSub),
- addInt: makeBinaryInt(function(x, y){return x + y;}, " + ", precedence.addSub),
- sub: makeBinary( function(x, y){return x - y;}, " - ", precedence.addSub),
- subInt: makeBinaryInt(function(x, y){return x - y;}, " - ", precedence.addSub),
- mul: mul,
- mulInt: makeBinaryInt(function(x, y){return x * y;}, " * ", precedence.mulDivMod),
- div: div,
- divInt: makeBinaryInt(function(x, y){return x / y;}, " / ", precedence.mulDivMod),
- mod: makeBinary(function(x, y){return x % y;}, " % ", precedence.mulDivMod),
- setUnion: makeBinary(function(x, y){return x | y;}, " | ", precedence.bitOr),
- setDiff: makeBinary(function(x, y){return x & ~y;}, " & ~", precedence.bitAnd),
- setIntersection: makeBinary(function(x, y){return x & y;}, " & ", precedence.bitAnd),
- setSymmetricDiff: makeBinary(function(x, y){return x ^ y;}, " ^ ", precedence.bitXor),
- setInclL: makeBinary(
- function(x, y){return (x & y) == x;},
- function(x, y, context){return context.rtl().setInclL(x, y);}),
- setInclR: makeBinary(
- function(x, y){return (x & y) == y;},
- function(x, y, context){return context.rtl().setInclR(x, y);}),
- or: makeBinary(function(x, y){return x || y;}, " || ", precedence.or),
- and: makeBinary(function(x, y){return x && y;}, " && ", precedence.and),
- equal: makeBinary(function(x, y){return x == y;}, " == ", precedence.equal),
- notEqual: makeBinary(function(x, y){return x != y;}, " != ", precedence.equal),
- less: makeBinary(function(x, y){return x < y;}, " < ", precedence.relational),
- greater: makeBinary(function(x, y){return x > y;}, " > ", precedence.relational),
- eqLess: makeBinary(function(x, y){return x <= y;}, " <= ", precedence.relational),
- eqGreater: makeBinary(function(x, y){return x >= y;}, " >= ", precedence.relational),
- not: makeUnary(function(x){return !x;}, "!"),
- negate: makeUnary(function(x){return -x;}, "-"),
- unaryPlus: makeUnary(function(x){return x;}, ""),
- setComplement: makeUnary(function(x){return ~x;}, "~"),
- lsl: makeBinary(function(x, y){return x << y;}, " << ", precedence.shift),
- asr: makeBinary(function(x, y){return x >> y;}, " >> ", precedence.shift),
- ror: makeBinary(function(x, y){return x >>> y;}, " >>> ", precedence.shift),
- assign: assign,
- mulInplace: makeInplace(" *= ", mul),
- divInplace: makeInplace(" /= ", div),
-
- pow2: pow2,
- log2: log2
- };
- for(var p in operators)
- exports[p] = operators[p];
- exports.precedence = precedence;
|