context.js 70 KB

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