type.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. "use strict";
  2. var Class = require("rtl.js").Class;
  3. var Errors = require("errors.js");
  4. var Id = Class.extend({
  5. init: function Id(){}
  6. });
  7. var Type = Id.extend({
  8. init: function Type(){
  9. Id.prototype.init.call(this);
  10. }
  11. });
  12. var TypeId = Id.extend({
  13. init: function TypeId(type){
  14. Id.prototype.init.call(this);
  15. this._type = type;
  16. },
  17. type: function(){return this._type;},
  18. description: function(){return 'type ' + this._type.description();},
  19. strip: function(){
  20. this._type = this._type instanceof Record
  21. ? new NonExportedRecord(this._type.cons(), this._type.scope(), this._type.baseType())
  22. : undefined;
  23. }
  24. });
  25. var ForwardTypeId = TypeId.extend({
  26. init: function Type$ForwardTypeId(resolve){
  27. TypeId.prototype.init.call(this);
  28. this.__resolve = resolve;
  29. },
  30. type: function(){
  31. if (!this._type)
  32. this._type = this.__resolve();
  33. return this._type;
  34. }
  35. });
  36. var LazyTypeId = TypeId.extend({
  37. init: function LazyTypeId(){
  38. TypeId.prototype.init.call(this);
  39. },
  40. define: function(type){return this._type = type;}
  41. });
  42. exports.String = Type.extend({
  43. init: function TypeString(s){
  44. Type.prototype.init.call(this);
  45. this.__s = s;
  46. },
  47. idType: function(){return "string";},
  48. description: function(){return (this.__s.length == 1 ? "single-" : "multi-") + "character string";},
  49. value: function(){return this.__s;},
  50. asChar: function(){return this.__s.length == 1 ? this.__s.charCodeAt(0) : undefined;},
  51. length: function(){return this.__s.length;}
  52. });
  53. var BasicType = Type.extend({
  54. init: function BasicType(name, initValue){
  55. Type.prototype.init.call(this);
  56. this.__name = name;
  57. this.__initValue = initValue;
  58. },
  59. idType: function(){return "type";},
  60. name: function() {return this.__name;},
  61. description: function(){return this.name();},
  62. initializer: function(context){return this.__initValue;}
  63. });
  64. exports.Basic = BasicType;
  65. function foldArrayDimensions(a){
  66. var result = a.length();
  67. var next = a.elementsType();
  68. if (result !== undefined
  69. && next instanceof ArrayType){
  70. var r = foldArrayDimensions(next);
  71. return [result + ", " + r[0], r[1]];
  72. }
  73. return [result, next.description()];
  74. }
  75. var ArrayType = BasicType.extend({
  76. init: function ArrayType(name, initializer, elementsType, size){
  77. BasicType.prototype.init.call(this, name, initializer);
  78. this.__elementsType = elementsType;
  79. this.__size = size;
  80. },
  81. elementsType: function(){return this.__elementsType;},
  82. length: function(){return this.__size;},
  83. description: function(){
  84. if (this.__elementsType === undefined) // special arrays, see procedure "LEN"
  85. return this.name();
  86. var desc = foldArrayDimensions(this);
  87. var sizes = (desc[0] === undefined ? "" : " " + desc[0]);
  88. return "ARRAY" + sizes + " OF " + desc[1];
  89. }
  90. });
  91. exports.Pointer = BasicType.extend({
  92. init: function PointerType(name, base){
  93. BasicType.prototype.init.call(this, name, "null");
  94. this.__base = base;
  95. },
  96. description: function(){
  97. return this.name() || "POINTER TO " + this.baseType().description();
  98. },
  99. baseType: function(){return this.__base.type();}
  100. });
  101. var Record = BasicType.extend({
  102. init: function Type$Record(name, cons, scope){
  103. BasicType.prototype.init.call(this, name);
  104. this.__cons = cons;
  105. this.__scope = scope;
  106. this.__fields = {};
  107. this.__base = undefined;
  108. },
  109. initializer: function(context){
  110. return "new " + context.qualifyScope(this.__scope) + this.__cons + "()";
  111. },
  112. scope: function(){return this.__scope;},
  113. cons: function(){return this.__cons;},
  114. addField: function(field, type){
  115. var name = field.id();
  116. if (this.__fields.hasOwnProperty(name))
  117. throw new Errors.Error("duplicated field: '" + name + "'");
  118. if (this.__base && this.__base.findSymbol(name))
  119. throw new Errors.Error("base record already has field: '" + name + "'");
  120. this.__fields[name] = type;
  121. },
  122. ownFields: function() {return this.__fields;},
  123. findSymbol: function(field){
  124. var result = this.__fields[field];
  125. if ( !result && this.__base)
  126. result = this.__base.findSymbol(field);
  127. return result;
  128. },
  129. baseType: function() {return this.__base;},
  130. setBaseType: function(type) {this.__base = type;},
  131. description: function(){
  132. return this.name() || "anonymous RECORD";
  133. }
  134. });
  135. var NonExportedRecord = Record.extend({
  136. init: function Scope$NonExportedRecord(cons, scope, base){
  137. Record.prototype.init.call(this, undefined, cons, scope);
  138. this.setBaseType(base);
  139. }
  140. });
  141. var NilType = Type.extend({
  142. init: function NilType(){Type.prototype.init.call(this);},
  143. idType: function(){return "NIL";},
  144. description: function(){return "NIL";}
  145. });
  146. var basic = {
  147. bool: new BasicType("BOOLEAN", false),
  148. ch: new BasicType("CHAR", 0),
  149. integer: new BasicType("INTEGER", 0),
  150. real: new BasicType("REAL", 0),
  151. set: new BasicType("SET", 0)
  152. };
  153. exports.basic = basic;
  154. exports.numeric = [basic.integer, basic.real];
  155. exports.nil = new NilType();
  156. exports.Const = Id.extend({
  157. init: function Const(type, value){
  158. Id.prototype.init.call(this);
  159. this.__type = type;
  160. this.__value = value;
  161. },
  162. idType: function(){return "constant";},
  163. type: function(){return this.__type;},
  164. value: function(){return this.__value;}
  165. });
  166. var Variable = Id.extend({
  167. init: function Variable(type, isReadOnly){
  168. Id.prototype.init.call(this);
  169. this.__type = type;
  170. this.__isReadOnly = isReadOnly;
  171. },
  172. idType: function(){return this.__isReadOnly ? "read-only variable" : "variable";},
  173. type: function(){return this.__type;},
  174. isReadOnly: function(){return this.__isReadOnly;}
  175. });
  176. var VariableRef = Variable.extend({
  177. init: function Type$VariableRef(type){
  178. Variable.prototype.init.call(this, type, false);
  179. }
  180. });
  181. var ExportedVariable = Variable.extend({
  182. init: function ExportedVariable(variable){
  183. Variable.prototype.init.call(this, variable.type(), true);
  184. },
  185. idType: function(){return "imported variable";}
  186. });
  187. exports.Procedure = BasicType.extend({
  188. init: function Procedure(name){
  189. BasicType.prototype.init.call(this, name, "null");
  190. },
  191. idType: function(){return "procedure";}
  192. });
  193. var Module = Id.extend({
  194. init: function Type$Module(name){
  195. Id.prototype.init.call(this);
  196. this.__name = name;
  197. },
  198. name: function(){return this.__name;}
  199. });
  200. exports.Array = ArrayType;
  201. exports.Variable = Variable;
  202. exports.VariableRef = VariableRef;
  203. exports.ExportedVariable = ExportedVariable;
  204. exports.Module = Module;
  205. exports.NonExportedRecord = NonExportedRecord;
  206. exports.Record = Record;
  207. exports.Type = Type;
  208. exports.TypeId = TypeId;
  209. exports.ForwardTypeId = ForwardTypeId;
  210. exports.LazyTypeId = LazyTypeId;