context.js 63 KB

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