context.js 64 KB

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