2
0

operator.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. "use strict";
  2. var Cast = require("cast.js");
  3. var Code = require("code.js");
  4. var Errors = require("errors.js");
  5. var Type = require("type.js");
  6. var precedence = {
  7. unary: 4,
  8. mulDivMod: 5,
  9. addSub: 6,
  10. shift: 7,
  11. relational: 8,
  12. equal: 9,
  13. bitAnd: 10,
  14. bitXor: 11,
  15. bitOr: 12,
  16. and: 13,
  17. or: 14,
  18. conditional: 15,
  19. assignment: 17
  20. };
  21. function makeBinary(op, code, precedence, resultPrecedence){
  22. return function(left, right, context){
  23. var leftValue = left.constValue();
  24. var rightValue = right.constValue();
  25. var value = (leftValue !== undefined && rightValue !== undefined)
  26. ? op(leftValue, rightValue) : undefined;
  27. var leftCode = Code.adjustPrecedence(left.deref(), precedence);
  28. // right code needs parentheses even if it has the same percedence
  29. var rightCode = Code.adjustPrecedence(right.deref(), precedence - 1);
  30. var expCode = (typeof code == "function")
  31. ? code(leftCode, rightCode, context)
  32. : leftCode + code + rightCode;
  33. return new Code.Expression(expCode, left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
  34. };
  35. }
  36. function makeUnary(op, code){
  37. return function(e){
  38. var type = e.type();
  39. var value = e.constValue();
  40. if (value !== undefined)
  41. value = op(value, type) ;
  42. var expCode = code + Code.adjustPrecedence(e.deref(), precedence.unary);
  43. return new Code.Expression(expCode, type, undefined, value);
  44. };
  45. }
  46. var mul = makeBinary(function(x, y){return x * y;}, " * ", precedence.mulDivMod);
  47. var div = makeBinary(function(x, y){return x / y;}, " / ", precedence.mulDivMod);
  48. function pow2(e){
  49. return new Code.Expression("Math.pow(2, " + e.deref().code() + ")",
  50. Type.basic.real);
  51. }
  52. function log2(e){
  53. return new Code.Expression("(Math.log(" + e.deref().code() + ") / Math.LN2) | 0",
  54. Type.basic.integer, undefined, undefined, precedence.bitOr);
  55. }
  56. function assign(left, right, context){
  57. var info = left.designator().info();
  58. if (!(info instanceof Type.Variable) || info.isReadOnly())
  59. throw new Errors.Error("cannot assign to " + info.idType());
  60. var leftCode = left.code();
  61. var leftType = left.type();
  62. var rightCode = right.code();
  63. var rightType = right.type();
  64. var isArray = leftType instanceof Type.Array;
  65. if (isArray
  66. && leftType.elementsType() == Type.basic.ch
  67. && rightType instanceof Type.String){
  68. if (leftType.length() === undefined)
  69. throw new Errors.Error("string cannot be assigned to open " + leftType.description());
  70. if (rightType.length() > leftType.length())
  71. throw new Errors.Error(
  72. leftType.length() + "-character ARRAY is too small for "
  73. + rightType.length() + "-character string");
  74. return context.rtl().assignArrayFromString(leftCode, rightCode);
  75. }
  76. var castOperation = Cast.implicit(rightType, leftType);
  77. if (!castOperation)
  78. throw new Errors.Error("type mismatch: '" + leftCode
  79. + "' is '" + leftType.description()
  80. + "' and cannot be assigned to '" + rightType.description() + "' expression");
  81. if (isArray && rightType instanceof Type.Array){
  82. if (leftType.length() === undefined)
  83. throw new Errors.Error("'" + leftCode
  84. + "' is open '" + leftType.description()
  85. + "' and cannot be assigned");
  86. }
  87. if (isArray || rightType instanceof Type.Record)
  88. return context.rtl().copy(rightCode, leftCode);
  89. var castCode = castOperation(context, right.deref()).code();
  90. rightCode = castCode ? castCode : rightCode;
  91. return leftCode + (info instanceof Type.VariableRef
  92. ? ".set(" + rightCode + ")"
  93. : " = " + rightCode);
  94. }
  95. function makeInplace(code, altOp){
  96. return function(left, right){
  97. var info = left.designator().info();
  98. if (info instanceof Type.VariableRef)
  99. return assign(left, altOp(left, right));
  100. return left.code() + code + right.deref().code();
  101. };
  102. }
  103. function makeBinaryInt(op, code, prec){
  104. return makeBinary(
  105. function(x, y){return op(x, y) | 0;},
  106. function(x, y){return x + code + y + " | 0";},
  107. prec,
  108. precedence.bitOr);
  109. }
  110. var operators = {
  111. add: makeBinary( function(x, y){return x + y;}, " + ", precedence.addSub),
  112. addInt: makeBinaryInt(function(x, y){return x + y;}, " + ", precedence.addSub),
  113. sub: makeBinary( function(x, y){return x - y;}, " - ", precedence.addSub),
  114. subInt: makeBinaryInt(function(x, y){return x - y;}, " - ", precedence.addSub),
  115. mul: mul,
  116. mulInt: makeBinaryInt(function(x, y){return x * y;}, " * ", precedence.mulDivMod),
  117. div: div,
  118. divInt: makeBinaryInt(function(x, y){return x / y;}, " / ", precedence.mulDivMod),
  119. mod: makeBinary(function(x, y){return x % y;}, " % ", precedence.mulDivMod),
  120. setUnion: makeBinary(function(x, y){return x | y;}, " | ", precedence.bitOr),
  121. setDiff: makeBinary(function(x, y){return x & ~y;}, " & ~", precedence.bitAnd),
  122. setIntersection: makeBinary(function(x, y){return x & y;}, " & ", precedence.bitAnd),
  123. setSymmetricDiff: makeBinary(function(x, y){return x ^ y;}, " ^ ", precedence.bitXor),
  124. setInclL: makeBinary(
  125. function(x, y){return (x & y) == x;},
  126. function(x, y, context){return context.rtl().setInclL(x, y);}),
  127. setInclR: makeBinary(
  128. function(x, y){return (x & y) == y;},
  129. function(x, y, context){return context.rtl().setInclR(x, y);}),
  130. or: makeBinary(function(x, y){return x || y;}, " || ", precedence.or),
  131. and: makeBinary(function(x, y){return x && y;}, " && ", precedence.and),
  132. equal: makeBinary(function(x, y){return x == y;}, " == ", precedence.equal),
  133. notEqual: makeBinary(function(x, y){return x != y;}, " != ", precedence.equal),
  134. less: makeBinary(function(x, y){return x < y;}, " < ", precedence.relational),
  135. greater: makeBinary(function(x, y){return x > y;}, " > ", precedence.relational),
  136. eqLess: makeBinary(function(x, y){return x <= y;}, " <= ", precedence.relational),
  137. eqGreater: makeBinary(function(x, y){return x >= y;}, " >= ", precedence.relational),
  138. not: makeUnary(function(x){return !x;}, "!"),
  139. negate: makeUnary(function(x){return -x;}, "-"),
  140. unaryPlus: makeUnary(function(x){return x;}, ""),
  141. setComplement: makeUnary(function(x){return ~x;}, "~"),
  142. lsl: makeBinary(function(x, y){return x << y;}, " << ", precedence.shift),
  143. asr: makeBinary(function(x, y){return x >> y;}, " >> ", precedence.shift),
  144. ror: makeBinary(function(x, y){return x >>> y;}, " >>> ", precedence.shift),
  145. assign: assign,
  146. mulInplace: makeInplace(" *= ", mul),
  147. divInplace: makeInplace(" /= ", div),
  148. pow2: pow2,
  149. log2: log2
  150. };
  151. for(var p in operators)
  152. exports[p] = operators[p];
  153. exports.precedence = precedence;