context.js 69 KB

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