context.js 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043
  1. "use strict";
  2. var Cast = require("js/Cast.js");
  3. var Code = require("js/Code.js");
  4. var CodeGenerator = require("js/CodeGenerator.js");
  5. var Errors = require("js/Errors.js");
  6. var Module = require("js/Module.js");
  7. var op = require("js/Operator.js");
  8. var ObContext = require("js/Context.js");
  9. var Parser = require("parser.js");
  10. var Procedure = require("js/Procedure.js");
  11. var Class = require("rtl.js").Class;
  12. var Scope = require("js/Scope.js");
  13. var Symbol = require("js/Symbols.js");
  14. var Type = require("js/Types.js");
  15. var basicTypes = Type.basic();
  16. var nullCodeGenerator = CodeGenerator.nullGenerator();
  17. var nilType = Type.nil();
  18. var castOperations = op.castOperations();
  19. function log(s){
  20. console.info(s);
  21. }
  22. function getSymbolAndScope(context, id){
  23. var s = context.findSymbol(id);
  24. if (!s)
  25. throw new Errors.Error(
  26. context instanceof Type.Module
  27. ? "identifier '" + id + "' is not exported by module '" + Type.moduleName(context) + "'"
  28. : "undeclared identifier: '" + id + "'");
  29. return s;
  30. }
  31. function getQIdSymbolAndScope(context, q){
  32. return getSymbolAndScope(q.module ? q.module : context, q.id);
  33. }
  34. function getSymbol(context, id){
  35. return getSymbolAndScope(context, id).symbol();
  36. }
  37. function unwrapTypeId(type){
  38. if (!(type instanceof Type.TypeId))
  39. throw new Errors.Error("type name expected");
  40. return type;
  41. }
  42. function unwrapType(type){
  43. return unwrapTypeId(type).type();
  44. }
  45. function getTypeSymbol(context, id){
  46. return unwrapType(getSymbol(context, id).info());
  47. }
  48. function throwTypeMismatch(from, to){
  49. throw new Errors.Error("type mismatch: expected '" + to.description() +
  50. "', got '" + from.description() + "'");
  51. }
  52. function checkTypeMatch(from, to){
  53. if (!Cast.areTypesMatch(from, to))
  54. throwTypeMismatch(from, to);
  55. }
  56. function checkImplicitCast(types, from, to){
  57. var op;
  58. if (types.implicitCast(from, to, false, castOperations, {set: function(v){op = v;}, get:function(){return op;}}))
  59. throwTypeMismatch(from, to);
  60. }
  61. function promoteTypeInExpression(e, type){
  62. var fromType = e.type();
  63. if (type == basicTypes.ch && fromType instanceof Type.String){
  64. var v;
  65. if (Type.stringAsChar(fromType, {set: function(value){v = value;}}))
  66. return Code.makeExpression(v, type);
  67. }
  68. return e;
  69. }
  70. function promoteExpressionType(context, left, right){
  71. var rightType = right.type();
  72. if (!left)
  73. return;
  74. var leftType = left.type();
  75. if (!rightType)
  76. return;
  77. checkImplicitCast(context.language().types, rightType, leftType);
  78. }
  79. function checkTypeCast(fromInfo, fromType, toType, msg){
  80. var prefix = "invalid " + msg;
  81. var pointerExpected = fromType instanceof Type.Pointer;
  82. if (!pointerExpected && !(fromType instanceof Type.Record))
  83. throw new Errors.Error(
  84. prefix + ": POINTER to type or RECORD expected, got '"
  85. + fromType.description() + "'");
  86. if (fromType instanceof Type.Record){
  87. if (!fromInfo.isReference())
  88. throw new Errors.Error(
  89. prefix + ": a value variable cannot be used");
  90. if (!(toType instanceof Type.Record))
  91. throw new Errors.Error(
  92. prefix + ": RECORD type expected as an argument of RECORD " + msg + ", got '"
  93. + toType.description() + "'");
  94. }
  95. else if (fromType instanceof Type.Pointer)
  96. if (!(toType instanceof Type.Pointer))
  97. throw new Errors.Error(
  98. prefix + ": POINTER type expected as an argument of POINTER " + msg + ", got '"
  99. + toType.description() + "'");
  100. if (fromType instanceof Type.Pointer)
  101. fromType = Type.pointerBase(fromType);
  102. if (toType instanceof Type.Pointer)
  103. toType = Type.pointerBase(toType);
  104. var t = Type.recordBase(toType);
  105. while (t && t != fromType)
  106. t = Type.recordBase(t);
  107. if (!t)
  108. throw new Errors.Error(prefix + ": '" + toType.description()
  109. + "' is not an extension of '" + fromType.description() + "'");
  110. }
  111. var ChainedContext = Class.extend({
  112. init: function ChainedContext(parent){this.__parent = parent;},
  113. parent: function(){return this.__parent;},
  114. handleMessage: function(msg){return this.__parent.handleMessage(msg);},
  115. language: function(){return this.__parent.language();},
  116. codeGenerator: function(){return this.__parent.codeGenerator();},
  117. findSymbol: function(id){return this.__parent.findSymbol(id);},
  118. currentScope: function(s){return this.__parent.currentScope();},
  119. pushScope: function(scope){this.__parent.pushScope(scope);},
  120. popScope: function(){this.__parent.popScope();},
  121. setType: function(type){this.__parent.setType(type);},
  122. setDesignator: function(d){this.__parent.setDesignator(d);},
  123. handleExpression: function(e){this.__parent.handleExpression(e);},
  124. handleLiteral: function(s){this.__parent.handleLiteral(s);},
  125. handleConst: function(type, value, code){this.__parent.handleConst(type, value, code);},
  126. genTypeName: function(){return this.__parent.genTypeName();},
  127. genVarName: function(id){return this.__parent.genVarName(id);},
  128. qualifyScope: function(scope){return this.__parent.qualifyScope(scope);}
  129. });
  130. exports.Integer = ChainedContext.extend({
  131. init: function IntegerContext(context){
  132. ChainedContext.prototype.init.call(this, context);
  133. this.__result = "";
  134. this.__isHex = false;
  135. },
  136. isLexem: function(){return true;},
  137. handleChar: function(c){this.__result += String.fromCharCode(c);},
  138. handleLiteral: function(){this.__isHex = true;},
  139. toInt: function(s){return parseInt(this.__result, 10);},
  140. endParse: function(){
  141. var n = this.toInt();
  142. this.parent().handleConst(basicTypes.integer, Code.makeIntConst(n), n.toString());
  143. }
  144. });
  145. exports.HexInteger = exports.Integer.extend({
  146. init: function HexIntegerContext(context){
  147. exports.Integer.prototype.init.call(this, context);
  148. },
  149. toInt: function(s){return parseInt(this.__result, 16);}
  150. });
  151. exports.Real = ChainedContext.extend({
  152. init: function RealContext(context){
  153. ChainedContext.prototype.init.call(this, context);
  154. this.__result = "";
  155. },
  156. isLexem: function(){return true;},
  157. handleChar: function(c){this.__result += String.fromCharCode(c);},
  158. handleLiteral: function(s){
  159. if (s == "D") // LONGREAL
  160. s = "E";
  161. this.__result += s;
  162. },
  163. endParse: function(){
  164. var n = Number(this.__result);
  165. this.parent().handleConst(basicTypes.real, Code.makeRealConst(n), n.toString());
  166. }
  167. });
  168. function escapeString(s){
  169. var escapeChars = {"\\": "\\\\",
  170. "\"": "\\\"",
  171. "\n": "\\n",
  172. "\r": "\\r",
  173. "\t": "\\t",
  174. "\b": "\\b",
  175. "\f": "\\f"
  176. };
  177. var result = "\"";
  178. for(var i = 0; i < s.length; ++i){
  179. var c = s[i];
  180. var escape = escapeChars[c];
  181. result += escape !== undefined ? escape : c;
  182. }
  183. return result + "\"";
  184. }
  185. exports.String = ChainedContext.extend({
  186. init: function StringContext(context){
  187. ChainedContext.prototype.init.call(this, context);
  188. this.__result = undefined;
  189. },
  190. handleString: function(s){this.__result = s;},
  191. toStr: function(s){return s;},
  192. endParse: function(){
  193. var s = this.toStr(this.__result);
  194. this.parent().handleConst(new Type.String(s), Code.makeStringConst(s), escapeString(s));
  195. }
  196. });
  197. exports.Char = exports.String.extend({
  198. init: function CharContext(context){
  199. exports.String.prototype.init.call(this, context);
  200. this.__result = "";
  201. },
  202. handleChar: function(c){this.__result += String.fromCharCode(c);},
  203. toStr: function(s){return String.fromCharCode(parseInt(s, 16));}
  204. });
  205. exports.BaseType = ChainedContext.extend({
  206. init: function BaseTypeContext(context){
  207. ChainedContext.prototype.init.call(this, context);
  208. },
  209. handleQIdent: function(q){
  210. var s = getQIdSymbolAndScope(this, q);
  211. this.parent().setBaseType(unwrapType(s.symbol().info()));
  212. }
  213. });
  214. exports.QualifiedIdentificator = ChainedContext.extend({
  215. init: function QualifiedIdentificator(context){
  216. ChainedContext.prototype.init.call(this, context);
  217. this.__module = undefined;
  218. this.__id = undefined;
  219. this.__code = "";
  220. },
  221. handleIdent: function(id){
  222. this.__id = id;
  223. },
  224. handleLiteral: function(){
  225. var s = getSymbol(this, this.__id);
  226. if (!s.isModule())
  227. return false; // stop parsing
  228. this.__module = s.info();
  229. this.__code = this.__id + ".";
  230. return undefined;
  231. },
  232. endParse: function(){
  233. var code = this.__code ? this.__code + Type.mangleJSProperty(this.__id) : this.__id;
  234. this.parent().handleQIdent({
  235. module: this.__module,
  236. id: this.__id,
  237. code: code
  238. });
  239. }
  240. });
  241. exports.Identdef = ChainedContext.extend({
  242. init: function IdentdefContext(context){
  243. ChainedContext.prototype.init.call(this, context);
  244. this._id = undefined;
  245. this._export = false;
  246. },
  247. handleIdent: function(id){this._id = id;},
  248. handleLiteral: function(){this._export = true;},
  249. endParse: function(){
  250. this.parent().handleIdentdef(this._makeIdendef());
  251. },
  252. _makeIdendef: function(){
  253. return new ObContext.IdentdefInfo(this._id, this._export);
  254. }
  255. });
  256. function castCode(type, context){
  257. var baseType = type instanceof Type.Pointer ? Type.pointerBase(type) : type;
  258. return context.qualifyScope(Type.recordScope(baseType)) + Type.recordConstructor(baseType);
  259. }
  260. exports.Designator = ChainedContext.extend({
  261. init: function Context$Designator(context){
  262. ChainedContext.prototype.init.call(this, context);
  263. this.__currentType = undefined;
  264. this.__info = undefined;
  265. this.__scope = undefined;
  266. this.__code = "";
  267. this.__lval = undefined;
  268. this.__indexExpression = undefined;
  269. this.__derefCode = undefined;
  270. this.__propCode = undefined;
  271. },
  272. handleQIdent: function(q){
  273. var found = getQIdSymbolAndScope(this, q);
  274. this.__scope = found.scope();
  275. var s = found.symbol();
  276. var info = s.info();
  277. var code = q.code;
  278. if (info instanceof Type.Type || s.isType())
  279. this.__currentType = info;
  280. else if (s.isConst())
  281. this.__currentType = Type.constType(info);
  282. else if (s.isVariable()){
  283. this.__currentType = info.type();
  284. if (q.module)
  285. code += "()";
  286. }
  287. else if (s.isProcedure()){
  288. this.__currentType = Type.procedureType(info);
  289. code = this.__currentType.designatorCode(code);
  290. }
  291. this.__info = info;
  292. this.__code += code;
  293. },
  294. handleIdent: function(id){
  295. var t = this.__currentType;
  296. var isReadOnly = this.__info instanceof Type.Variable
  297. && this.__info.isReadOnly();
  298. if (t instanceof Type.Pointer){
  299. this.__handleDeref();
  300. isReadOnly = false;
  301. }
  302. var field = t.denote(id);
  303. this.__currentType = field.type();
  304. this.__derefCode = this.__code;
  305. var codeId = this.__currentType instanceof Type.Procedure
  306. ? this.__currentType.designatorCode(id)
  307. : Type.mangleField(id, this.__currentType);
  308. this.__propCode = "\"" + codeId + "\"";
  309. this.__info = field.asVar(isReadOnly, this);
  310. this.__code += "." + codeId;
  311. this.__scope = undefined;
  312. },
  313. _currentType: function(){return this.__currentType;},
  314. _currentInfo: function(){return this.__info;},
  315. _discardCode: function(){this.__code = "";},
  316. _makeDerefVar: function(){
  317. return Type.makeVariableRef(this.__currentType, false);
  318. },
  319. handleExpression: function(e){this.__indexExpression = e;},
  320. __handleIndexExpression: function(){
  321. var e = this.__indexExpression;
  322. var expType = e.type();
  323. if (!Type.isInt(expType))
  324. throw new Errors.Error(
  325. Type.intsDescription() + " expression expected, got '" + expType.description() + "'");
  326. var index = this._indexSequence(this.__currentType, this.__info);
  327. var pValue = e.constValue();
  328. if (pValue){
  329. var value = pValue.value;
  330. Code.checkIndex(value);
  331. var length = index.length;
  332. if ((this.__currentType instanceof Type.StaticArray || this.__currentType instanceof Type.String)
  333. && value >= length)
  334. throw new Errors.Error("index out of bounds: maximum possible index is "
  335. + (length - 1)
  336. + ", got " + value );
  337. }
  338. return index;
  339. },
  340. _advance: function(type, info, code){
  341. this.__currentType = type;
  342. this.__info = info;
  343. this.__code += code;
  344. },
  345. _indexSequence: function(type, info){
  346. var isArray = type instanceof Type.Array;
  347. if (!isArray && !(type instanceof Type.String))
  348. throw new Errors.Error("ARRAY or string expected, got '" + type.description() + "'");
  349. var length = isArray ? type instanceof Type.StaticArray ? type.length()
  350. : undefined
  351. : Type.stringLen(type);
  352. if (!isArray && !length)
  353. throw new Errors.Error("cannot index empty string" );
  354. var indexType = isArray ? Type.arrayElementsType(type) : basicTypes.ch;
  355. return { length: length,
  356. type: indexType,
  357. info: Type.makeVariable(indexType, info instanceof Type.Const || info.isReadOnly())
  358. };
  359. },
  360. handleLiteral: function(s){
  361. if (s == "]" || s == ","){
  362. var index = this.__handleIndexExpression();
  363. var indexCode = Code.derefExpression(this.__indexExpression).code();
  364. this.__propCode = indexCode;
  365. var code = this.__derefCode + "[" + indexCode + "]";
  366. if (index.type == basicTypes.ch){
  367. this.__lval = code;
  368. code = this.__derefCode + ".charCodeAt(" + indexCode + ")";
  369. }
  370. this._advance(index.type, index.info, this.__code + code);
  371. }
  372. if (s == "[" || s == ","){
  373. this.__derefCode = this.__code;
  374. this.__code = "";
  375. }
  376. else if (s == "^"){
  377. this.__handleDeref();
  378. this.__info = this._makeDerefVar(this.__info);
  379. }
  380. },
  381. __handleDeref: function(){
  382. if (!(this.__currentType instanceof Type.Pointer))
  383. throw new Errors.Error("POINTER TO type expected, got '"
  384. + this.__currentType.description() + "'");
  385. this.__currentType = Type.pointerBase(this.__currentType);
  386. if (this.__currentType instanceof Type.NonExportedRecord)
  387. throw new Errors.Error("POINTER TO non-exported RECORD type cannot be dereferenced");
  388. },
  389. handleTypeCast: function(type){
  390. checkTypeCast(this.__info, this.__currentType, type, "type cast");
  391. var code = this.language().rtl.typeGuard(this.__code, castCode(type, this));
  392. this.__code = code;
  393. this.__currentType = type;
  394. },
  395. endParse: function(){
  396. var code = this.__code;
  397. var self = this;
  398. var refCode = function(code){return self.__makeRefCode(code);};
  399. this.parent().setDesignator(
  400. new Code.Designator(code, this.__lval ? this.__lval : code, refCode, this.__currentType, this.__info, this.__scope));
  401. },
  402. __makeRefCode: function(code){
  403. if ( this.__currentType instanceof Type.Array
  404. || this.__currentType instanceof Type.Record
  405. || this.__info.isReference())
  406. return code;
  407. if (this.__derefCode)
  408. return this.language().rtl.makeRef(this.__derefCode, this.__propCode);
  409. return "{set: function($v){" + code + " = $v;}, get: function(){return " + code + ";}}";
  410. }
  411. });
  412. exports.Type = ChainedContext.extend({
  413. init: function Context$Type(context){
  414. ChainedContext.prototype.init.call(this, context);
  415. },
  416. handleQIdent: function(q){
  417. this.parent().handleQIdent(q);
  418. }
  419. });
  420. var HandleSymbolAsType = ChainedContext.extend({
  421. init: function Context$HandleSymbolAsType(context){
  422. ChainedContext.prototype.init.call(this, context);
  423. },
  424. handleQIdent: function(q){
  425. var s = getQIdSymbolAndScope(this, q);
  426. this.setType(unwrapType(s.symbol().info()));
  427. }
  428. });
  429. exports.FormalType = HandleSymbolAsType.extend({
  430. init: function FormalType(context){
  431. HandleSymbolAsType.prototype.init.call(this, context);
  432. this.__arrayDimension = 0;
  433. },
  434. setType: function(type){
  435. for(var i = 0; i < this.__arrayDimension; ++i)
  436. type = new (this.language().types.OpenArray)(type);
  437. this.parent().setType(type);
  438. },
  439. handleLiteral: function(s){
  440. if (s == "ARRAY")
  441. ++this.__arrayDimension;
  442. }
  443. });
  444. var ProcArg = Class.extend({
  445. init: function(type, isVar){
  446. this.type = type;
  447. this.isVar = isVar;
  448. },
  449. description: function(){
  450. return (this.isVar ? "VAR " : "") + this.type.description();
  451. }
  452. });
  453. function AddArgumentMsg(name, arg){
  454. this.name = name;
  455. this.arg = arg;
  456. }
  457. exports.FormalParameters = ChainedContext.extend({
  458. init: function FormalParametersContext(context){
  459. ChainedContext.prototype.init.call(this, context);
  460. this.__arguments = [];
  461. this.__result = undefined;
  462. var parent = this.parent();
  463. var name = parent.typeName();
  464. if (name === undefined)
  465. name = "";
  466. this.__type = new Procedure.Type(name);
  467. parent.setType(this.__type);
  468. },
  469. handleMessage: function(msg){
  470. if (msg instanceof AddArgumentMsg){
  471. this.__arguments.push(msg.arg);
  472. return undefined;
  473. }
  474. return ChainedContext.prototype.handleMessage.call(this, msg);
  475. },
  476. handleQIdent: function(q){
  477. var s = getQIdSymbolAndScope(this, q);
  478. var resultType = unwrapType(s.symbol().info());
  479. this._checkResultType(resultType);
  480. this.__result = resultType;
  481. },
  482. endParse: function(){
  483. this.__type.define(this.__arguments, this.__result);
  484. },
  485. _checkResultType: function(type){
  486. if (type instanceof Type.Array)
  487. throw new Errors.Error("the result type of a procedure cannot be an ARRAY");
  488. if (type instanceof Type.Record)
  489. throw new Errors.Error("the result type of a procedure cannot be a RECORD");
  490. }
  491. });
  492. function endParametersMsg(){}
  493. exports.FormalParametersProcDecl = exports.FormalParameters.extend({
  494. init: function FormalParametersProcDeclContext(context){
  495. exports.FormalParameters.prototype.init.call(this, context);
  496. },
  497. handleMessage: function(msg){
  498. var result = exports.FormalParameters.prototype.handleMessage.call(this, msg);
  499. if (msg instanceof AddArgumentMsg)
  500. this.parent().handleMessage(msg);
  501. return result;
  502. },
  503. endParse: function(){
  504. exports.FormalParameters.prototype.endParse.call(this);
  505. this.handleMessage(endParametersMsg);
  506. }
  507. });
  508. exports.ProcDecl = ChainedContext.extend({
  509. init: function ProcDeclContext(context){
  510. ChainedContext.prototype.init.call(this, context);
  511. this.__id = undefined;
  512. this.__firstArgument = true;
  513. this.__type = undefined;
  514. this.__returnParsed = false;
  515. this.__outerScope = this.parent().currentScope();
  516. this.__stdSymbols = this.language().stdSymbols;
  517. },
  518. handleIdentdef: function(id){
  519. this.__id = id;
  520. this.codeGenerator().write(this._prolog());
  521. this.parent().pushScope(Scope.makeProcedure(this.__stdSymbols));
  522. },
  523. handleIdent: function(id){
  524. if (this.__id.id() != id)
  525. throw new Errors.Error("mismatched procedure names: '" + this.__id.id()
  526. + "' at the begining and '" + id + "' at the end");
  527. },
  528. _prolog: function(){
  529. return "\nfunction " + this.__id.id() + "(";
  530. },
  531. _beginBody: function(){
  532. this.codeGenerator().openScope();
  533. },
  534. typeName: function(){return undefined;},
  535. setType: function(type){
  536. var procSymbol = new Symbol.Symbol(
  537. this.__id.id(),
  538. new Type.ProcedureId(type));
  539. this.__outerScope.addSymbol(procSymbol, this.__id.exported());
  540. this.__type = type;
  541. },
  542. __addArgument: function(name, arg){
  543. if (name == this.__id.id())
  544. throw new Errors.Error("argument '" + name + "' has the same name as procedure");
  545. var v = this._makeArgumentVariable(arg);
  546. var s = new Symbol.Symbol(name, v);
  547. this.currentScope().addSymbol(s);
  548. var code = this.codeGenerator();
  549. if (!this.__firstArgument)
  550. code.write(", ");
  551. else
  552. this.__firstArgument = false;
  553. code.write(name + "/*" + arg.description() + "*/");
  554. },
  555. _makeArgumentVariable: function(arg){
  556. var readOnly = !arg.isVar
  557. && (arg.type instanceof Type.Array || arg.type instanceof Type.Record);
  558. return arg.isVar ? Type.makeVariableRef(arg.type)
  559. : Type.makeVariable(arg.type, readOnly);
  560. },
  561. handleMessage: function(msg){
  562. if (msg == endParametersMsg){
  563. this.codeGenerator().write(")");
  564. this._beginBody();
  565. return;
  566. }
  567. if (msg instanceof AddArgumentMsg)
  568. return this.__addArgument(msg.name, msg.arg);
  569. return ChainedContext.prototype.handleMessage.call(this, msg);
  570. },
  571. handleReturn: function(type){
  572. var result = this.__type.result();
  573. if (!result)
  574. throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
  575. var op;
  576. if (this.language().types.implicitCast(type, result, false, castOperations, {set: function(v){op = v;}, get:function(){return op;}}))
  577. throw new Errors.Error(
  578. "RETURN '" + result.description() + "' expected, got '"
  579. + type.description() + "'");
  580. this.__returnParsed = true;
  581. },
  582. endParse: function(){
  583. this.codeGenerator().closeScope("");
  584. this.parent().popScope();
  585. var result = this.__type.result();
  586. if (result && !this.__returnParsed)
  587. throw new Errors.Error("RETURN expected at the end of PROCEDURE declared with '"
  588. + Type.typeName(result) + "' result type");
  589. }
  590. });
  591. exports.Return = ChainedContext.extend({
  592. init: function Context$Return(context){
  593. ChainedContext.prototype.init.call(this, context);
  594. this.__expr = undefined;
  595. },
  596. codeGenerator: function(){return nullCodeGenerator;},
  597. handleExpression: function(e){this.__expr = e;},
  598. endParse: function(){
  599. var parent = this.parent();
  600. parent.codeGenerator().write("return " + Code.derefExpression(this.__expr).code() + ";\n");
  601. parent.handleReturn(this.__expr.type());
  602. }
  603. });
  604. exports.ProcParams = HandleSymbolAsType.extend({
  605. init: function Context$ProcParams(context){
  606. HandleSymbolAsType.prototype.init.call(this, context);
  607. this.__isVar = false;
  608. this.__argNamesForType = [];
  609. },
  610. handleLiteral: function(s){
  611. if (s == "VAR")
  612. this.__isVar = true;
  613. },
  614. handleIdent: function(id){ this.__argNamesForType.push(id);},
  615. setType: function(type){
  616. var names = this.__argNamesForType;
  617. for(var i = 0; i < names.length; ++i){
  618. var name = names[i];
  619. this.handleMessage(
  620. new AddArgumentMsg(name, new Type.ProcedureArgument(type, this.__isVar)));
  621. }
  622. this.__isVar = false;
  623. this.__argNamesForType = [];
  624. }
  625. });
  626. function ForwardTypeMsg(id){
  627. this.id = id;
  628. }
  629. exports.PointerDecl = ChainedContext.extend({
  630. init: function Context$PointerDecl(context){
  631. ChainedContext.prototype.init.call(this, context);
  632. },
  633. handleQIdent: function(q){
  634. var id = q.id;
  635. var s = q.module
  636. ? getQIdSymbolAndScope(this, q)
  637. : this.findSymbol(id);
  638. var info = s ? s.symbol().info()
  639. : this.parent().handleMessage(new ForwardTypeMsg(id));
  640. var typeId = unwrapTypeId(info);
  641. this.__setTypeId(typeId);
  642. },
  643. __setTypeId: function(typeId){
  644. if (!(typeId instanceof Type.ForwardTypeId)){
  645. var type = typeId.type();
  646. if (!(type instanceof Type.Record))
  647. throw new Errors.Error(
  648. "RECORD is expected as a POINTER base type, got '" + type.description() + "'");
  649. }
  650. var parent = this.parent();
  651. var name = parent.isAnonymousDeclaration()
  652. ? ""
  653. : parent.genTypeName();
  654. var pointerType = new Type.Pointer(name, typeId);
  655. parent.setType(pointerType);
  656. },
  657. setType: function(type){
  658. var typeId = new Type.TypeId(type);
  659. this.currentScope().addFinalizer(function(){typeId.strip();});
  660. this.__setTypeId(typeId);
  661. },
  662. isAnonymousDeclaration: function(){return true;},
  663. exportField: function(field){
  664. throw new Errors.Error( "cannot export anonymous RECORD field: '" + field + "'");
  665. }
  666. });
  667. exports.ArrayDecl = HandleSymbolAsType.extend({
  668. init: function Context$ArrayDecl(context){
  669. HandleSymbolAsType.prototype.init.call(this, context);
  670. this.__dimensions = undefined;
  671. },
  672. handleDimensions: function(dimensions){this.__dimensions = dimensions;},
  673. setType: function(elementsType){
  674. var type = elementsType;
  675. var dimensions = "";
  676. for(var i = this.__dimensions.length; i-- ;){
  677. var length = this.__dimensions[i];
  678. dimensions = length + (dimensions.length ? ", " + dimensions : "");
  679. var arrayInit = i ? undefined
  680. : this._makeInit(elementsType, dimensions, length);
  681. type = this._makeType(type, arrayInit, length);
  682. }
  683. this.__type = type;
  684. },
  685. isAnonymousDeclaration: function(){return true;},
  686. endParse: function(){this.parent().setType(this.__type);},
  687. _makeInit: function(type, dimensions, length){
  688. var rtl = this.language().rtl;
  689. if (type == basicTypes.ch)
  690. return rtl.makeCharArray(dimensions);
  691. var initializer = type instanceof Type.Array || type instanceof Type.Record
  692. ? "function(){return " + type.initializer(this) + ";}"
  693. : type.initializer(this);
  694. return rtl.makeArray(dimensions + ", " + initializer);
  695. },
  696. _makeType: function(elementsType, init, length){
  697. return new (this.language().types.StaticArray)(init, elementsType, length);
  698. }
  699. });
  700. exports.ArrayDimensions = ChainedContext.extend({
  701. init: function ArrayDimensionsContext(context){
  702. ChainedContext.prototype.init.call(this, context);
  703. this.__dimensions = [];
  704. },
  705. codeGenerator: function(){return nullCodeGenerator;},
  706. handleExpression: function(e){
  707. var type = e.type();
  708. if (type !== basicTypes.integer)
  709. throw new Errors.Error("'INTEGER' constant expression expected, got '" + type.description() + "'");
  710. var value = e.constValue();
  711. if (!value)
  712. throw new Errors.Error("constant expression expected as ARRAY size");
  713. if (value.value <= 0)
  714. throw new Errors.Error("array size must be greater than 0, got " + value.value);
  715. this._addDimension(value.value);
  716. },
  717. endParse: function(){
  718. this.parent().handleDimensions(this.__dimensions);
  719. },
  720. _addDimension: function(size){
  721. this.__dimensions.push(size);
  722. }
  723. });
  724. var numericOpTypeCheck = {
  725. expect: "numeric type",
  726. check: function(t){return Type.numeric().indexOf(t) != -1;}
  727. };
  728. var numericOrSetOpTypeCheck = {
  729. expect: numericOpTypeCheck.expect + " or SET",
  730. check: function(t){return numericOpTypeCheck.check(t) || t == basicTypes.set;}
  731. };
  732. var intOpTypeCheck = {
  733. expect: Type.intsDescription(),
  734. check: Type.isInt
  735. };
  736. function throwOperatorTypeMismatch(op, expect, type){
  737. throw new Errors.Error(
  738. "operator '" + op +
  739. "' type mismatch: " + expect + " expected, got '" +
  740. type.description() + "'");
  741. }
  742. function assertOpType(type, check, literal){
  743. if (!check.check(type))
  744. throwOperatorTypeMismatch(literal, check.expect, type);
  745. }
  746. function assertNumericOp(type, literal, op, intOp){
  747. assertOpType(type, numericOpTypeCheck, literal);
  748. return (intOp && Type.isInt(type))
  749. ? intOp : op;
  750. }
  751. function assertNumericOrSetOp(type, literal, op, intOp, setOp){
  752. assertOpType(type, numericOrSetOpTypeCheck, literal);
  753. return Type.isInt(type) ? intOp : type == basicTypes.set ? setOp : op;
  754. }
  755. function assertIntOp(type, literal, op){
  756. assertOpType(type, intOpTypeCheck, literal);
  757. return op;
  758. }
  759. function useIntOrderOp(t){
  760. return Type.isInt(t) || t == basicTypes.ch;
  761. }
  762. function useIntEqOp(t){
  763. return Type.isInt(t)
  764. || t == basicTypes.bool
  765. || t == basicTypes.ch
  766. || t instanceof Type.Pointer
  767. || t instanceof Type.Procedure
  768. || t == nilType;
  769. }
  770. var RelationOps = Class.extend({
  771. init: function RelationOps(){
  772. },
  773. eq: function(type){
  774. return useIntEqOp(type) ? op.equalInt
  775. : Type.isString(type) ? op.equalStr
  776. : type == basicTypes.real ? op.equalReal
  777. : type == basicTypes.set ? op.equalSet
  778. : undefined;
  779. },
  780. notEq: function(type){
  781. return useIntEqOp(type) ? op.notEqualInt
  782. : Type.isString(type) ? op.notEqualStr
  783. : type == basicTypes.real ? op.notEqualReal
  784. : type == basicTypes.set ? op.notEqualSet
  785. : undefined;
  786. },
  787. less: function(type){
  788. return useIntOrderOp(type) ? op.lessInt
  789. : Type.isString(type) ? op.lessStr
  790. : type == basicTypes.real ? op.lessReal
  791. : undefined;
  792. },
  793. greater: function(type){
  794. return useIntOrderOp(type) ? op.greaterInt
  795. : Type.isString(type) ? op.greaterStr
  796. : type == basicTypes.real ? op.greaterReal
  797. : undefined;
  798. },
  799. lessEq: function(type){
  800. return useIntOrderOp(type) ? op.eqLessInt
  801. : Type.isString(type) ? op.eqLessStr
  802. : type == basicTypes.real ? op.eqLessReal
  803. : type == basicTypes.set ? op.setInclL
  804. : undefined;
  805. },
  806. greaterEq: function(type){
  807. return useIntOrderOp(type) ? op.eqGreaterInt
  808. : Type.isString(type) ? op.eqGreaterStr
  809. : type == basicTypes.real ? op.eqGreaterReal
  810. : type == basicTypes.set ? op.setInclR
  811. : undefined;
  812. },
  813. is: function(type, context){
  814. return function(left, right){
  815. var d = left.designator();
  816. checkTypeCast(d ? d.info() : undefined, left.type(), type, "type test");
  817. return op.is(left, Code.makeExpression(castCode(type, context)));
  818. };
  819. },
  820. eqExpect: function(){return "numeric type or SET or BOOLEAN or CHAR or character array or POINTER or PROCEDURE";},
  821. strongRelExpect: function(){return "numeric type or CHAR or character array";},
  822. relExpect: function(){return "numeric type or SET or CHAR or character array";},
  823. coalesceType: function(leftType, rightType){
  824. if (leftType instanceof Type.Pointer && rightType instanceof Type.Pointer){
  825. var type = Cast.findPointerBaseType(leftType, rightType);
  826. if (!type)
  827. type = Cast.findPointerBaseType(rightType, leftType);
  828. if (type)
  829. return type;
  830. }
  831. // special case for strings
  832. var isStrings = Type.isString(leftType) && Type.isString(rightType);
  833. if (!isStrings)
  834. checkTypeMatch(rightType, leftType);
  835. return leftType;
  836. }
  837. });
  838. var relationOps = new RelationOps();
  839. function checkSetHasBit(leftType, rightType, context){
  840. if (!Type.isInt(leftType))
  841. throw new Errors.Error(
  842. Type.intsDescription() + " expected as an element of SET, got '" + Type.typeName(leftType) + "'");
  843. checkImplicitCast(context.language().types, rightType, basicTypes.set);
  844. }
  845. function relationOp(leftType, rightType, literal, ops, context){
  846. var type =
  847. literal == "IS" ? unwrapType(rightType)
  848. : literal == "IN" ? checkSetHasBit(leftType, rightType, context)
  849. : ops.coalesceType(leftType, rightType);
  850. var o;
  851. var mismatch;
  852. switch (literal){
  853. case "=":
  854. o = ops.eq(type);
  855. if (!o)
  856. mismatch = ops.eqExpect();
  857. break;
  858. case "#":
  859. o = ops.notEq(type);
  860. if (!o)
  861. mismatch = ops.eqExpect();
  862. break;
  863. case "<":
  864. o = ops.less(type);
  865. if (!o)
  866. mismatch = ops.strongRelExpect();
  867. break;
  868. case ">":
  869. o = ops.greater(type);
  870. if (!o)
  871. mismatch = ops.strongRelExpect();
  872. break;
  873. case "<=":
  874. o = ops.lessEq(type);
  875. if (!o)
  876. mismatch = ops.relExpect();
  877. break;
  878. case ">=":
  879. o = ops.greaterEq(type);
  880. if (!o)
  881. mismatch = ops.relExpect();
  882. break;
  883. case "IS":
  884. o = ops.is(type, context);
  885. break;
  886. case "IN":
  887. o = op.setHasBit;
  888. break;
  889. }
  890. if (mismatch)
  891. throwOperatorTypeMismatch(literal, mismatch, type);
  892. return o;
  893. }
  894. exports.AddOperator = ChainedContext.extend({
  895. init: function AddOperatorContext(context){
  896. ChainedContext.prototype.init.call(this, context);
  897. },
  898. handleLiteral: function(s){
  899. var parent = this.parent();
  900. var type = parent.type();
  901. var o = this.__matchOperator(s, type);
  902. if (o)
  903. parent.handleBinaryOperator(o);
  904. },
  905. __matchOperator: function(s, type){
  906. var result;
  907. switch (s){
  908. case "+":
  909. result = this._matchPlusOperator(type);
  910. if (!result)
  911. throwOperatorTypeMismatch(s, this._expectPlusOperator(), type);
  912. break;
  913. case "-":
  914. return assertNumericOrSetOp(type, s, op.subReal, op.subInt, op.setDiff);
  915. case "OR":
  916. if (type != basicTypes.bool)
  917. throw new Errors.Error("BOOLEAN expected as operand of 'OR', got '"
  918. + type.description() + "'");
  919. return op.or;
  920. }
  921. return result;
  922. },
  923. _matchPlusOperator: function(type){
  924. if (type == basicTypes.set)
  925. return op.setUnion;
  926. if (Type.isInt(type))
  927. return op.addInt;
  928. if (type == basicTypes.real)
  929. return op.addReal;
  930. return undefined;
  931. },
  932. _expectPlusOperator: function(){return "numeric type or SET";}
  933. });
  934. exports.MulOperator = ChainedContext.extend({
  935. init: function MulOperatorContext(context){
  936. ChainedContext.prototype.init.call(this, context);
  937. },
  938. handleLiteral: function(s){
  939. var parent = this.parent();
  940. var type = parent.type();
  941. var o;
  942. if (s == "*")
  943. o = assertNumericOrSetOp(type, s, op.mulReal, op.mulInt, op.setIntersection);
  944. else if (s == "/"){
  945. if (Type.isInt(type))
  946. throw new Errors.Error("operator DIV expected for integer division");
  947. o = assertNumericOrSetOp(type, s, op.divReal, undefined, op.setSymmetricDiff);
  948. }
  949. else if (s == "DIV")
  950. o = assertIntOp(type, s, op.divInt);
  951. else if (s == "MOD")
  952. o = assertIntOp(type, s, op.mod);
  953. else if (s == "&"){
  954. if (type != basicTypes.bool)
  955. throw new Errors.Error("BOOLEAN expected as operand of '&', got '"
  956. + type.description() + "'");
  957. o = op.and;
  958. }
  959. if (o)
  960. parent.handleOperator(o);
  961. }
  962. });
  963. exports.Term = ChainedContext.extend({
  964. init: function TermContext(context){
  965. ChainedContext.prototype.init.call(this, context);
  966. this.__logicalNot = false;
  967. this.__operator = undefined;
  968. this.__expression = undefined;
  969. },
  970. type: function(){return this.__expression.type();},
  971. setDesignator: function(d){
  972. var info = d.info();
  973. if (info instanceof Type.ProcedureId){
  974. var proc = Type.procedureType(info);
  975. if (proc instanceof Procedure.Std)
  976. throw new Errors.Error(proc.description() + " cannot be referenced");
  977. var scope = d.scope();
  978. if (scope instanceof Scope.Procedure)
  979. throw new Errors.Error("local procedure '" + d.code() + "' cannot be referenced");
  980. }
  981. var value;
  982. if (info instanceof Type.Const)
  983. value = Type.constValue(info);
  984. this.handleExpression(
  985. Code.makeExpression(d.code(), d.type(), d, value));
  986. },
  987. handleLogicalNot: function(){
  988. this.__logicalNot = !this.__logicalNot;
  989. this.setType(basicTypes.bool);
  990. },
  991. handleOperator: function(o){this.__operator = o;},
  992. handleConst: function(type, value, code){
  993. this.handleExpression(Code.makeExpression(
  994. code, type, undefined, value));
  995. },
  996. handleFactor: function(e){
  997. this.handleExpression(e);
  998. },
  999. endParse: function(){this.parent().handleTerm(this.__expression);},
  1000. handleExpression: function(e){
  1001. promoteExpressionType(this, this.__expression, e);
  1002. if (this.__logicalNot){
  1003. e = op.not(e);
  1004. this.__logicalNot = false;
  1005. }
  1006. if (this.__operator)
  1007. e = this.__expression ? this.__operator(this.__expression, e)
  1008. : this.__operator(e);
  1009. this.__expression = e;
  1010. }
  1011. });
  1012. exports.Factor = ChainedContext.extend({
  1013. init: function FactorContext(context){
  1014. ChainedContext.prototype.init.call(this, context);
  1015. },
  1016. type: function(){return this.parent().type();},
  1017. handleLiteral: function(s){
  1018. var parent = this.parent();
  1019. if (s == "NIL")
  1020. parent.handleConst(nilType, undefined, "null");
  1021. else if (s == "TRUE")
  1022. parent.handleConst(basicTypes.bool, Code.makeIntConst(1), "true");
  1023. else if (s == "FALSE")
  1024. parent.handleConst(basicTypes.bool, Code.makeIntConst(0), "false");
  1025. else if (s == "~")
  1026. parent.handleLogicalNot();
  1027. },
  1028. handleFactor: function(e){this.parent().handleFactor(e);},
  1029. handleLogicalNot: function(){this.parent().handleLogicalNot();}
  1030. });
  1031. exports.Set = ChainedContext.extend({
  1032. init: function SetContext(context){
  1033. ChainedContext.prototype.init.call(this, context);
  1034. this.__value = 0;
  1035. this.__expr = "";
  1036. },
  1037. handleElement: function(from, fromValue, to, toValue){
  1038. if (fromValue && (!to || toValue)){
  1039. if (to)
  1040. for(var i = fromValue.value; i <= toValue.value; ++i)
  1041. this.__value |= 1 << i;
  1042. else
  1043. this.__value |= 1 << fromValue.value;
  1044. }
  1045. else{
  1046. if (this.__expr.length)
  1047. this.__expr += ", ";
  1048. if (to)
  1049. this.__expr += "[" + from + ", " + to + "]";
  1050. else
  1051. this.__expr += from;
  1052. }
  1053. },
  1054. endParse: function(){
  1055. var parent = this.parent();
  1056. if (!this.__expr.length)
  1057. parent.handleConst(basicTypes.set, Code.makeSetConst(this.__value), this.__value.toString());
  1058. else{
  1059. var code = this.language().rtl.makeSet(this.__expr);
  1060. if (this.__value)
  1061. code += " | " + this.__value;
  1062. var e = Code.makeExpression(code, basicTypes.set);
  1063. parent.handleFactor(e);
  1064. }
  1065. }
  1066. });
  1067. exports.SetElement = ChainedContext.extend({
  1068. init: function SetElementContext(context){
  1069. ChainedContext.prototype.init.call(this, context);
  1070. this.__from = undefined;
  1071. this.__fromValue = undefined;
  1072. this.__to = undefined;
  1073. this.__toValue = undefined;
  1074. this.__expr = CodeGenerator.makeSimpleGenerator();
  1075. },
  1076. codeGenerator: function(){return this.__expr;},
  1077. handleExpression: function(e){
  1078. var value = e.constValue();
  1079. if (!this.__from)
  1080. {
  1081. this.__from = this.__expr.result();
  1082. this.__fromValue = value;
  1083. this.__expr = CodeGenerator.makeSimpleGenerator();
  1084. }
  1085. else{
  1086. this.__to = this.__expr.result();
  1087. this.__toValue = value;
  1088. }
  1089. },
  1090. endParse: function(){
  1091. this.parent().handleElement(this.__from, this.__fromValue, this.__to, this.__toValue);
  1092. }
  1093. });
  1094. function constValueCode(value){
  1095. if (typeof value == "string")
  1096. return escapeString(value);
  1097. return value.toString();
  1098. }
  1099. exports.SimpleExpression = ChainedContext.extend({
  1100. init: function SimpleExpressionContext(context){
  1101. ChainedContext.prototype.init.call(this, context);
  1102. this.__unaryOperator = undefined;
  1103. this.__binaryOperator = undefined;
  1104. this.__type = undefined;
  1105. this.__exp = undefined;
  1106. },
  1107. handleTerm: function(e){
  1108. var type = e.type();
  1109. this.setType(type);
  1110. var o;
  1111. switch(this.__unaryOperator){
  1112. case "-":
  1113. o = assertNumericOrSetOp(type, this.__unaryOperator, op.negateReal, op.negateInt, op.setComplement);
  1114. break;
  1115. case "+":
  1116. o = assertNumericOp(type, this.__unaryOperator, op.unaryPlus);
  1117. break;
  1118. }
  1119. if (o){
  1120. this.__exp = o(e);
  1121. this.__unaryOperator = undefined;
  1122. }
  1123. else
  1124. this.__exp = this.__exp ? this.__binaryOperator(this.__exp, e) : e;
  1125. },
  1126. handleLiteral: function(s){this.__unaryOperator = s;},
  1127. type: function(){return this.__type;},
  1128. setType: function(type){
  1129. if (type === undefined || this.__type === undefined)
  1130. this.__type = type;
  1131. else
  1132. checkImplicitCast(this.language().types, type, this.__type);
  1133. },
  1134. handleBinaryOperator: function(o){this.__binaryOperator = o;},
  1135. endParse: function(){
  1136. this.parent().handleSimpleExpression(this.__exp);
  1137. }
  1138. });
  1139. exports.Expression = ChainedContext.extend({
  1140. init: function ExpressionContext(context, relOps){
  1141. ChainedContext.prototype.init.call(this, context);
  1142. this.__relOps = relOps || relationOps;
  1143. this.__relation = undefined;
  1144. this.__expression = undefined;
  1145. },
  1146. handleSimpleExpression: function(e){
  1147. if (!this.__expression){
  1148. this.__expression = e;
  1149. return;
  1150. }
  1151. var leftExpression = this.__expression;
  1152. var rightExpression = e;
  1153. leftExpression = promoteTypeInExpression(leftExpression, rightExpression.type());
  1154. rightExpression = promoteTypeInExpression(rightExpression, leftExpression.type());
  1155. var o = relationOp(leftExpression.type(), rightExpression.type(), this.__relation, this.__relOps, this);
  1156. this.__expression = o(leftExpression, rightExpression, this.language().rtl);
  1157. },
  1158. handleLiteral: function(relation){
  1159. this.__relation = relation;
  1160. },
  1161. codeGenerator: function(){return nullCodeGenerator;},
  1162. endParse: function(){
  1163. var type = this.__expression.type();
  1164. if (!type)
  1165. throw new Errors.Error("procedure returning no result cannot be used in an expression");
  1166. var parent = this.parent();
  1167. parent.codeGenerator().write(this.__expression.code());
  1168. parent.handleExpression(this.__expression);
  1169. }
  1170. });
  1171. function handleIfExpression(e){
  1172. var type = e.type();
  1173. if (type !== basicTypes.bool)
  1174. throw new Errors.Error("'BOOLEAN' expression expected, got '" + type.description() + "'");
  1175. }
  1176. /*
  1177. var IfContextBase = ChainedContext.extend({
  1178. init: function(context){
  1179. ChainedContext.prototype.init.call(this, context);
  1180. },
  1181. endParse: function(){
  1182. var gen = this.codeGenerator();
  1183. gen.write(")");
  1184. gen.openScope();
  1185. },
  1186. handleExpression: handleIfExpression
  1187. });
  1188. */
  1189. exports.If = ChainedContext.extend({
  1190. init: function IfContext(context){
  1191. ChainedContext.prototype.init.call(this, context);
  1192. this.codeGenerator().write("if (");
  1193. },
  1194. handleExpression: function(e){
  1195. handleIfExpression(e);
  1196. var gen = this.codeGenerator();
  1197. gen.write(")");
  1198. gen.openScope();
  1199. },
  1200. handleLiteral: function(s){
  1201. var gen = this.codeGenerator();
  1202. if (s == "ELSIF"){
  1203. gen.closeScope("");
  1204. gen.write("else if (");
  1205. }
  1206. else if (s == "ELSE"){
  1207. gen.closeScope("");
  1208. gen.write("else ");
  1209. gen.openScope();
  1210. }
  1211. },
  1212. endParse: function(){
  1213. this.codeGenerator().closeScope("");
  1214. }
  1215. });
  1216. exports.emitEndStatement = function(context){
  1217. context.codeGenerator().write(";\n");
  1218. };
  1219. exports.Case = ChainedContext.extend({
  1220. init: function CaseContext(context){
  1221. ChainedContext.prototype.init.call(this, context);
  1222. this.__type = undefined;
  1223. this.__firstCase = true;
  1224. this.genVarName("$c");
  1225. this.codeGenerator().write("$c = ");
  1226. },
  1227. handleExpression: function(e){
  1228. var type = e.type();
  1229. var gen = this.codeGenerator();
  1230. if (type instanceof Type.String){
  1231. var v;
  1232. if (Type.stringAsChar(type, {set: function(value){v = value;}})){
  1233. gen.write(v);
  1234. type = basicTypes.ch;
  1235. }
  1236. }
  1237. if (!Type.isInt(type) && type != basicTypes.ch)
  1238. throw new Errors.Error(
  1239. Type.intsDescription() + " or 'CHAR' expected as CASE expression");
  1240. this.__type = type;
  1241. gen.write(";\n");
  1242. },
  1243. beginCase: function(){
  1244. if (this.__firstCase)
  1245. this.__firstCase = false;
  1246. else
  1247. this.codeGenerator().write("else ");
  1248. },
  1249. handleLabelType: function(type){
  1250. if (!Cast.areTypesMatch(type, this.__type))
  1251. throw new Errors.Error(
  1252. "label must be '" + Type.typeName(this.__type) + "' (the same as case expression), got '"
  1253. + Type.typeName(type) + "'");
  1254. }
  1255. });
  1256. exports.CaseLabelList = ChainedContext.extend({
  1257. init: function CaseLabelListContext(context){
  1258. ChainedContext.prototype.init.call(this, context);
  1259. this.__glue = "";
  1260. },
  1261. handleLabelType: function(type){this.parent().handleLabelType(type);},
  1262. handleRange: function(from, to){
  1263. if (!this.__glue)
  1264. this.parent().caseLabelBegin();
  1265. var cond = to === undefined
  1266. ? "$c === " + from.value
  1267. : "($c >= " + from.value + " && $c <= " + to.value + ")";
  1268. this.codeGenerator().write(this.__glue + cond);
  1269. this.__glue = " || ";
  1270. },
  1271. endParse: function(){this.parent().caseLabelEnd();}
  1272. });
  1273. exports.CaseLabel = ChainedContext.extend({
  1274. init: function CaseLabelContext(context){
  1275. ChainedContext.prototype.init.call(this, context);
  1276. },
  1277. caseLabelBegin: function(){
  1278. this.parent().beginCase();
  1279. this.codeGenerator().write("if (");
  1280. },
  1281. caseLabelEnd: function(){
  1282. var gen = this.codeGenerator();
  1283. gen.write(")");
  1284. gen.openScope();
  1285. },
  1286. handleLabelType: function(type){this.parent().handleLabelType(type);},
  1287. handleRange: function(from, to){this.parent().handleRange(from, to);},
  1288. endParse: function(){this.codeGenerator().closeScope("");}
  1289. });
  1290. exports.CaseRange = ChainedContext.extend({
  1291. init: function CaseRangeContext(context){
  1292. ChainedContext.prototype.init.call(this, context);
  1293. this.__from = undefined;
  1294. this.__to = undefined;
  1295. },
  1296. codeGenerator: function(){return nullCodeGenerator;}, // suppress any output
  1297. handleLabel: function(type, v){
  1298. this.parent().handleLabelType(type);
  1299. if (this.__from === undefined )
  1300. this.__from = v;
  1301. else
  1302. this.__to = v;
  1303. },
  1304. handleConst: function(type, value){
  1305. if (type instanceof Type.String){
  1306. if (!Type.stringAsChar(type, {set: function(v){value = v;}}))
  1307. throw new Errors.Error("single-character string expected");
  1308. type = basicTypes.ch;
  1309. value = Code.makeIntConst(value);
  1310. }
  1311. this.handleLabel(type, value);
  1312. },
  1313. handleIdent: function(id){
  1314. var s = getSymbol(this.parent(), id);
  1315. if (!s.isConst())
  1316. throw new Errors.Error("'" + id + "' is not a constant");
  1317. var type = Type.constType(s.info());
  1318. if (type instanceof Type.String)
  1319. this.handleConst(type, undefined);
  1320. else
  1321. this.handleLabel(type, Type.constValue(s.info()));
  1322. },
  1323. endParse: function(){this.parent().handleRange(this.__from, this.__to);}
  1324. });
  1325. exports.While = ChainedContext.extend({
  1326. init: function WhileContext(context){
  1327. ChainedContext.prototype.init.call(this, context);
  1328. var gen = this.codeGenerator();
  1329. gen.write("while (true)");
  1330. gen.openScope();
  1331. gen.write("if (");
  1332. },
  1333. handleExpression: function WhileContext$handleExpression(e){
  1334. handleIfExpression(e);
  1335. var gen = this.codeGenerator();
  1336. gen.write(")");
  1337. gen.openScope();
  1338. },
  1339. handleLiteral: function(s){
  1340. if (s == "ELSIF"){
  1341. var gen = this.codeGenerator();
  1342. gen.closeScope("");
  1343. gen.write("else if (");
  1344. }
  1345. },
  1346. endParse: function(){
  1347. var gen = this.codeGenerator();
  1348. gen.closeScope(" else break;\n");
  1349. gen.closeScope("");
  1350. }
  1351. });
  1352. exports.Repeat = ChainedContext.extend({
  1353. init: function RepeatContext(context){
  1354. ChainedContext.prototype.init.call(this, context);
  1355. var gen = context.codeGenerator();
  1356. gen.write("do ");
  1357. gen.openScope();
  1358. }
  1359. });
  1360. exports.Until = ChainedContext.extend({
  1361. init: function UntilContext(context){
  1362. ChainedContext.prototype.init.call(this, context);
  1363. context.codeGenerator().closeScope(" while (");
  1364. },
  1365. codeGenerator: function(){ return nullCodeGenerator; },
  1366. handleExpression: function(e){
  1367. handleIfExpression(e);
  1368. this.parent().codeGenerator().write( op.not(e).code() );
  1369. },
  1370. endParse: function(){
  1371. this.parent().codeGenerator().write(");\n");
  1372. }
  1373. });
  1374. exports.For = ChainedContext.extend({
  1375. init: function ForContext(context){
  1376. ChainedContext.prototype.init.call(this, context);
  1377. this.__var = undefined;
  1378. this.__initExprParsed = false;
  1379. this.__toExpr = CodeGenerator.makeSimpleGenerator();
  1380. this.__toParsed = false;
  1381. this.__by_parsed = false;
  1382. this.__by = undefined;
  1383. },
  1384. handleIdent: function(id){
  1385. var s = getSymbol(this.parent(), id);
  1386. if (!s.isVariable())
  1387. throw new Errors.Error("'" + s.id() + "' is not a variable");
  1388. var type = s.info().type();
  1389. if (type !== basicTypes.integer)
  1390. throw new Errors.Error(
  1391. "'" + s.id() + "' is a '"
  1392. + type.description() + "' variable, 'FOR' control variable must be 'INTEGER'");
  1393. this._handleInitCode(id, "for (" + id + " = ");
  1394. },
  1395. _handleInitCode: function(id, code){
  1396. this.__var = id;
  1397. this.codeGenerator().write(code);
  1398. },
  1399. _handleInitExpression: function(type){
  1400. if (type != basicTypes.integer)
  1401. throw new Errors.Error(
  1402. "'INTEGER' expression expected to assign '" + this.__var
  1403. + "', got '" + type.description() + "'");
  1404. this.__initExprParsed = true;
  1405. },
  1406. handleExpression: function(e){
  1407. var type = e.type();
  1408. if (!this.__initExprParsed)
  1409. this._handleInitExpression(type);
  1410. else if (!this.__toParsed) {
  1411. if (type != basicTypes.integer)
  1412. throw new Errors.Error(
  1413. "'INTEGER' expression expected as 'TO' parameter, got '" + type.description() + "'");
  1414. this.__toParsed = true;
  1415. }
  1416. else {
  1417. if (type != basicTypes.integer)
  1418. throw new Errors.Error("'INTEGER' expression expected as 'BY' parameter, got '" + type.description() + "'");
  1419. var value = e.constValue();
  1420. if ( value === undefined )
  1421. throw new Errors.Error("constant expression expected as 'BY' parameter");
  1422. this.__by = value.value;
  1423. }
  1424. },
  1425. codeGenerator: function(){
  1426. if (this.__initExprParsed && !this.__toParsed)
  1427. return this.__toExpr;
  1428. if (this.__toParsed && !this.__by_parsed)
  1429. return nullCodeGenerator; // suppress output for BY expression
  1430. return this.parent().codeGenerator();
  1431. },
  1432. handleBegin: function(){
  1433. this.__by_parsed = true;
  1434. var relation = this.__by < 0 ? " >= " : " <= ";
  1435. var step = this.__by === undefined
  1436. ? "++" + this.__var
  1437. : this.__var + (this.__by < 0
  1438. ? " -= " + -this.__by
  1439. : " += " + this.__by);
  1440. var s = "; " + this.__var + relation + this.__toExpr.result() + "; " + step + ")";
  1441. var gen = this.codeGenerator();
  1442. gen.write(s);
  1443. gen.openScope();
  1444. },
  1445. endParse: function(){this.codeGenerator().closeScope("");}
  1446. });
  1447. exports.emitForBegin = function(context){context.handleBegin();};
  1448. exports.CheckAssignment = ChainedContext.extend({
  1449. init: function Context$CheckAssignment(context){
  1450. ChainedContext.prototype.init.call(this, context);
  1451. },
  1452. handleLiteral: function(s){
  1453. if (s == "=")
  1454. throw new Errors.Error("did you mean ':=' (statement expected, got expression)?");
  1455. }
  1456. });
  1457. exports.ConstDecl = ChainedContext.extend({
  1458. init: function ConstDeclContext(context){
  1459. ChainedContext.prototype.init.call(this, context);
  1460. this.__id = undefined;
  1461. this.__type = undefined;
  1462. this.__value = undefined;
  1463. },
  1464. handleIdentdef: function(id){
  1465. this.__id = id;
  1466. this.codeGenerator().write("var " + id.id() + " = ");
  1467. },
  1468. handleExpression: function(e){
  1469. var value = e.constValue();
  1470. if (!value)
  1471. throw new Errors.Error("constant expression expected");
  1472. this.__type = e.type();
  1473. this.__value = value;
  1474. },
  1475. endParse: function(){
  1476. var c = new Type.Const(this.__type, this.__value);
  1477. this.currentScope().addSymbol(new Symbol.Symbol(this.__id.id(), c), this.__id.exported());
  1478. this.codeGenerator().write(";\n");
  1479. }
  1480. });
  1481. function checkIfFieldCanBeExported(name, idents, hint){
  1482. for(var i = 0; i < idents.length; ++i){
  1483. var id = idents[i];
  1484. if (!id.exported())
  1485. throw new Errors.Error(
  1486. "field '" + name + "' can be exported only if " + hint + " '" +
  1487. id.id() + "' itself is exported too");
  1488. }
  1489. }
  1490. exports.VariableDeclaration = HandleSymbolAsType.extend({
  1491. init: function Context$VariableDeclaration(context){
  1492. HandleSymbolAsType.prototype.init.call(this, context);
  1493. this.__idents = [];
  1494. this.__type = undefined;
  1495. },
  1496. handleIdentdef: function(id){this.__idents.push(id);},
  1497. exportField: function(name){
  1498. checkIfFieldCanBeExported(name, this.__idents, "variable");
  1499. },
  1500. setType: function(type){this.__type = type;},
  1501. type: function(){return this.__type;},
  1502. typeName: function(){return undefined;},
  1503. isAnonymousDeclaration: function(){return true;},
  1504. checkExport: function(){},
  1505. handleMessage: function(msg){
  1506. if (msg instanceof ForwardTypeMsg)
  1507. throw new Errors.Error("type '" + msg.id + "' was not declared");
  1508. return HandleSymbolAsType.prototype.handleMessage.call(this, msg);
  1509. },
  1510. _initCode: function(){
  1511. return this.__type.initializer(this);
  1512. },
  1513. endParse: function(){
  1514. var v = Type.makeVariable(this.__type, false);
  1515. var idents = this.__idents;
  1516. var gen = this.codeGenerator();
  1517. for(var i = 0; i < idents.length; ++i){
  1518. var id = idents[i];
  1519. var varName = id.id();
  1520. if (id.exported())
  1521. this.checkExport(varName);
  1522. this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
  1523. gen.write("var " + varName + " = " + this._initCode() + ";");
  1524. }
  1525. gen.write("\n");
  1526. }
  1527. });
  1528. exports.FieldListDeclaration = HandleSymbolAsType.extend({
  1529. init: function Context$FieldListDeclaration(context){
  1530. HandleSymbolAsType.prototype.init.call(this, context);
  1531. this.__idents = [];
  1532. this.__type = undefined;
  1533. },
  1534. typeName: function(){return undefined;},
  1535. handleIdentdef: function(id) {this.__idents.push(id);},
  1536. exportField: function(name){
  1537. checkIfFieldCanBeExported(name, this.__idents, "field");
  1538. },
  1539. setType: function(type) {this.__type = type;},
  1540. isAnonymousDeclaration: function(){return true;},
  1541. endParse: function(){
  1542. var idents = this.__idents;
  1543. var parent = this.parent();
  1544. for(var i = 0; i < idents.length; ++i)
  1545. parent.addField(idents[i], this.__type);
  1546. }
  1547. });
  1548. function assertProcType(type, info){
  1549. var unexpected;
  1550. if ( !type )
  1551. unexpected = info.idType();
  1552. else if (!(type instanceof Type.Procedure) && !(type instanceof Module.AnyType))
  1553. unexpected = type.description();
  1554. if (unexpected)
  1555. throw new Errors.Error("PROCEDURE expected, got '" + unexpected + "'");
  1556. return type;
  1557. }
  1558. function assertProcStatementResult(type){
  1559. if (type && !(type instanceof Module.AnyType))
  1560. throw new Errors.Error("procedure returning a result cannot be used as a statement");
  1561. }
  1562. function beginCallMsg(){}
  1563. function endCallMsg(){}
  1564. exports.ActualParameters = ChainedContext.extend({
  1565. init: function ActualParametersContext(context){
  1566. ChainedContext.prototype.init.call(this, context);
  1567. this.handleMessage(beginCallMsg);
  1568. },
  1569. handleLiteral: function(){}, // do not propagate ","
  1570. endParse: function(){
  1571. this.handleMessage(endCallMsg);
  1572. }
  1573. });
  1574. function isTypeRecursive(type, base){
  1575. if (type == base)
  1576. return true;
  1577. if (type instanceof Type.Record){
  1578. if (isTypeRecursive(Type.recordBase(type), base))
  1579. return true;
  1580. var fields = Type.recordOwnFields(type);
  1581. for(var fieldName in fields){
  1582. if (isTypeRecursive(fields[fieldName].type(), base))
  1583. return true;
  1584. }
  1585. }
  1586. else if (type instanceof Type.Array)
  1587. return isTypeRecursive(Type.arrayElementsType(type), base);
  1588. return false;
  1589. }
  1590. exports.RecordDecl = ChainedContext.extend({
  1591. init: function RecordDeclContext(context, RecordCons){
  1592. ChainedContext.prototype.init.call(this, context);
  1593. var parent = this.parent();
  1594. this.__cons = parent.genTypeName();
  1595. var name = parent.isAnonymousDeclaration() ? "" : this.__cons;
  1596. this.__type = new RecordCons(name, this.__cons, context.currentScope());
  1597. parent.setType(this.__type);
  1598. },
  1599. type: function(){return this.__type;},
  1600. addField: function(field, type){
  1601. if (isTypeRecursive(type, this.__type))
  1602. throw new Errors.Error("recursive field definition: '"
  1603. + field.id() + "'");
  1604. this.__type.addField(this._makeField(field, type));
  1605. if (field.exported())
  1606. this.parent().exportField(field.id());
  1607. },
  1608. setBaseType: function(type){
  1609. if (!(type instanceof Type.Record))
  1610. throw new Errors.Error(
  1611. "RECORD type is expected as a base type, got '"
  1612. + type.description()
  1613. + "'");
  1614. if (isTypeRecursive(type, this.__type))
  1615. throw new Errors.Error("recursive inheritance: '"
  1616. + Type.typeName(this.__type) + "'");
  1617. this.__type.setBase(type);
  1618. },
  1619. endParse: function(){
  1620. var gen = this.codeGenerator();
  1621. this.codeGenerator().write(
  1622. this._generateConstructor()
  1623. + this._generateInheritance()
  1624. );
  1625. },
  1626. _generateConstructor: function(){
  1627. var gen = CodeGenerator.makeGenerator();
  1628. gen.write("function " + this.__cons + "()");
  1629. gen.openScope();
  1630. gen.write(this._generateBaseConstructorCallCode()
  1631. + this.__generateFieldsInitializationCode());
  1632. gen.closeScope("");
  1633. return gen.result();
  1634. },
  1635. _qualifiedBaseConstructor: function(){
  1636. var baseType = Type.recordBase(this.__type);
  1637. if (!baseType)
  1638. return "";
  1639. return this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType);
  1640. },
  1641. _generateBaseConstructorCallCode: function(){
  1642. var baseType = Type.recordBase(this.__type);
  1643. var qualifiedBase = baseType ? this.qualifyScope(Type.recordScope(baseType)) + Type.typeName(baseType) : undefined;
  1644. var result = this._qualifiedBaseConstructor();
  1645. return result ? result + ".call(this);\n" : "";
  1646. },
  1647. __generateFieldsInitializationCode: function(){
  1648. var result = "";
  1649. var ownFields = Type.recordOwnFields(this.__type);
  1650. for(var f in ownFields){
  1651. var fieldType = ownFields[f].type();
  1652. result += "this." + Type.mangleField(f, fieldType) + " = " + fieldType.initializer(this) + ";\n";
  1653. }
  1654. return result;
  1655. },
  1656. _generateInheritance: function(){
  1657. var base = Type.recordBase(this.__type);
  1658. if (!base)
  1659. return "";
  1660. var qualifiedBase = this.qualifyScope(Type.recordScope(base)) + Type.typeName(base);
  1661. return this.language().rtl.extend(this.__cons, qualifiedBase) + ";\n";
  1662. },
  1663. _makeField: function(field, type){
  1664. return new Type.RecordField(field, type);
  1665. }
  1666. });
  1667. exports.TypeDeclaration = ChainedContext.extend({
  1668. init: function TypeDeclarationContext(context){
  1669. ChainedContext.prototype.init.call(this, context);
  1670. this.__id = undefined;
  1671. this.__symbol = undefined;
  1672. },
  1673. handleIdentdef: function(id){
  1674. var typeId = new Type.LazyTypeId();
  1675. var symbol = new Symbol.Symbol(id.id(), typeId);
  1676. this.currentScope().addSymbol(symbol, id.exported());
  1677. if (!id.exported())
  1678. this.currentScope().addFinalizer(function(){typeId.strip();});
  1679. this.__id = id;
  1680. this.__symbol = symbol;
  1681. },
  1682. setType: function(type){
  1683. Type.defineTypeId(this.__symbol.info(), type);
  1684. Scope.resolve(this.currentScope(), this.__symbol);
  1685. },
  1686. typeName: function(){return this.__id.id();},
  1687. id: function(){return this.__id;},
  1688. genTypeName: function(){return this.__id.id();},
  1689. isAnonymousDeclaration: function(){return false;},
  1690. type: function(){return this.parent().type();},
  1691. exportField: function(name){
  1692. checkIfFieldCanBeExported(name, [this.__id], "record");
  1693. }
  1694. });
  1695. exports.TypeSection = ChainedContext.extend({
  1696. init: function TypeSection(context){
  1697. ChainedContext.prototype.init.call(this, context);
  1698. },
  1699. handleMessage: function(msg){
  1700. if (msg instanceof ForwardTypeMsg){
  1701. var scope = this.currentScope();
  1702. Scope.addUnresolved(scope, msg.id);
  1703. var resolve = function(){return getSymbol(this, msg.id).info().type();}.bind(this);
  1704. return new Type.ForwardTypeId(resolve);
  1705. }
  1706. return ChainedContext.prototype.handleMessage.call(this, msg);
  1707. },
  1708. endParse: function(){
  1709. var unresolved = Scope.unresolved(this.currentScope());
  1710. if (unresolved.length)
  1711. throw new Errors.Error("no declaration found for '" + unresolved.join("', '") + "'");
  1712. }
  1713. });
  1714. exports.TypeCast = ChainedContext.extend({
  1715. init: function TypeCastContext(context){
  1716. ChainedContext.prototype.init.call(this, context);
  1717. this.__type = undefined;
  1718. },
  1719. handleQIdent: function(q){
  1720. var s = getQIdSymbolAndScope(this, q);
  1721. s = s.symbol();
  1722. if (!s.isType())
  1723. return; // this is not a type cast, may be procedure call
  1724. this.__type = s.info().type();
  1725. },
  1726. endParse: function(){
  1727. if (this.__type === undefined)
  1728. return false;
  1729. this.parent().handleTypeCast(this.__type);
  1730. return true;
  1731. }
  1732. });
  1733. exports.ModuleDeclaration = ChainedContext.extend({
  1734. init: function ModuleDeclarationContext(context){
  1735. ChainedContext.prototype.init.call(this, context);
  1736. this.__name = undefined;
  1737. this.__imports = {};
  1738. this.__moduleScope = undefined;
  1739. this.__moduleGen = undefined;
  1740. this.__stdSymbols = this.language().stdSymbols;
  1741. },
  1742. handleIdent: function(id){
  1743. var parent = this.parent();
  1744. if (this.__name === undefined ) {
  1745. this.__name = id;
  1746. this.__moduleScope = new Scope.Module(id, this.__stdSymbols);
  1747. parent.pushScope(this.__moduleScope);
  1748. }
  1749. else if (id === this.__name){
  1750. var scope = parent.currentScope();
  1751. scope.close();
  1752. var exports = Scope.moduleExports(scope);
  1753. Scope.defineExports(Scope.moduleSymbol(scope).info(), exports);
  1754. this.codeGenerator().write(this.__moduleGen.epilog(exports));
  1755. }
  1756. else
  1757. throw new Errors.Error("original module name '" + this.__name + "' expected, got '" + id + "'" );
  1758. },
  1759. findModule: function(name){
  1760. if (name == this.__name)
  1761. throw new Errors.Error("module '" + this.__name + "' cannot import itself");
  1762. return this.parent().findModule(name);
  1763. },
  1764. handleImport: function(modules){
  1765. var scope = this.currentScope();
  1766. var moduleAliases = {};
  1767. for(var i = 0; i < modules.length; ++i){
  1768. var s = modules[i];
  1769. var name = Type.moduleName(s.info());
  1770. this.__imports[name] = s;
  1771. scope.addSymbol(s);
  1772. moduleAliases[name] = s.id();
  1773. }
  1774. this.__moduleGen = this.parent().makeModuleGenerator(
  1775. this.__name,
  1776. moduleAliases);
  1777. this.codeGenerator().write(this.__moduleGen.prolog());
  1778. },
  1779. qualifyScope: function(scope){
  1780. if (scope != this.__moduleScope && scope instanceof Scope.Module){
  1781. var id = Scope.moduleSymbol(scope).id();
  1782. // implicitly imported module, e.g.: record.pointerToRecordFromAnotherModule.field
  1783. // should not be used in code generation,
  1784. // just return non-empty value to indicate this is not current module
  1785. if (!(id in this.__imports))
  1786. return "module '" + id + "' is not imported";
  1787. return this.__imports[id].id() + ".";
  1788. }
  1789. return "";
  1790. }
  1791. });
  1792. var ModuleImport = ChainedContext.extend({
  1793. init: function ModuleImport(context){
  1794. ChainedContext.prototype.init.call(this, context);
  1795. this.__import = {};
  1796. this.__currentModule = undefined;
  1797. this.__currentAlias = undefined;
  1798. },
  1799. handleIdent: function(id){
  1800. this.__currentModule = id;
  1801. },
  1802. handleLiteral: function(s){
  1803. if (s == ":=")
  1804. this.__currentAlias = this.__currentModule;
  1805. else if (s == ",")
  1806. this.__handleImport();
  1807. },
  1808. endParse: function(){
  1809. if (this.__currentModule)
  1810. this.__handleImport();
  1811. var modules = [];
  1812. var unresolved = [];
  1813. for(var alias in this.__import){
  1814. var moduleName = this.__import[alias];
  1815. var module = this.parent().findModule(moduleName);
  1816. if (!module)
  1817. unresolved.push(moduleName);
  1818. else
  1819. modules.push(new Symbol.Symbol(alias, module));
  1820. }
  1821. if (unresolved.length)
  1822. throw new Errors.Error("module(s) not found: " + unresolved.join(", "));
  1823. this.parent().handleImport(modules);
  1824. },
  1825. __handleImport: function(){
  1826. var alias = this.__currentAlias;
  1827. if (!alias)
  1828. alias = this.__currentModule;
  1829. else
  1830. this.__currentAlias = undefined;
  1831. for(var a in this.__import){
  1832. if (a == alias)
  1833. throw new Errors.Error("duplicated alias: '" + alias +"'");
  1834. if (this.__import[a] == this.__currentModule)
  1835. throw new Errors.Error("module already imported: '" + this.__currentModule +"'");
  1836. }
  1837. this.__import[alias] = this.__currentModule;
  1838. }
  1839. });
  1840. exports.ModuleImport = ModuleImport;
  1841. exports.Context = Class.extend({
  1842. init: function Context(language){
  1843. this.__language = language;
  1844. this.__scopes = [];
  1845. this.__gen = 0;
  1846. this.__vars = [];
  1847. },
  1848. language: function(){return this.__language;},
  1849. genTypeName: function(){
  1850. ++this.__gen;
  1851. return "anonymous$" + this.__gen;
  1852. },
  1853. genVarName: function(id){
  1854. if (this.__vars.indexOf(id) === -1) {
  1855. this.codeGenerator().write("var " + id + ";\n");
  1856. this.__vars.push(id);
  1857. }
  1858. },
  1859. findSymbol: function(ident){
  1860. for(var i = this.__scopes.length; i--;){
  1861. var scope = this.__scopes[i];
  1862. var s = scope.findSymbol(ident);
  1863. if (s)
  1864. return s;
  1865. }
  1866. return undefined;
  1867. },
  1868. currentScope: function(){return this.__scopes[this.__scopes.length - 1];},
  1869. pushScope: function(scope){this.__scopes.push(scope);},
  1870. popScope: function(){
  1871. var scope = this.__scopes.pop();
  1872. scope.close();
  1873. },
  1874. handleExpression: function(){},
  1875. handleLiteral: function(){},
  1876. codeGenerator: function(){return this.__language.codeGenerator;},
  1877. makeModuleGenerator: function(name, imports){
  1878. return this.__language.moduleGenerator(name, imports);
  1879. },
  1880. findModule: function(name){
  1881. if (name == "JS"){
  1882. return Module.makeJS();
  1883. }
  1884. return this.__language.moduleResolver ? this.__language.moduleResolver(name) : undefined;
  1885. }
  1886. });
  1887. function makeProcCall(context, type, info){
  1888. assertProcType(type, info);
  1889. var l = context.language();
  1890. return type.callGenerator(
  1891. { types: l.types,
  1892. rtl: l.rtl,
  1893. qualifyScope: context.qualifyScope.bind(context)
  1894. });
  1895. }
  1896. exports.AddArgumentMsg = AddArgumentMsg;
  1897. exports.assertProcStatementResult = assertProcStatementResult;
  1898. exports.beginCallMsg = beginCallMsg;
  1899. exports.endCallMsg = endCallMsg;
  1900. exports.Chained = ChainedContext;
  1901. exports.endParametersMsg = endParametersMsg;
  1902. exports.getSymbolAndScope = getSymbolAndScope;
  1903. exports.getQIdSymbolAndScope = getQIdSymbolAndScope;
  1904. exports.makeProcCall = makeProcCall;
  1905. exports.unwrapType = unwrapType;
  1906. exports.RelationOps = RelationOps;
  1907. exports.HandleSymbolAsType = HandleSymbolAsType;