context.js 69 KB

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