test_unit_eberon.js 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608
  1. "use strict";
  2. var Class = require("rtl.js").Class;
  3. //var EberonCodeGenerator = require("js/EberonCodeGenerator.js");
  4. var language = require("eberon/eberon_grammar.js").language;
  5. var TestUnitCommon = require("test_unit_common.js");
  6. var TypePromotion = require("js/EberonTypePromotion.js");
  7. var assert = TestUnitCommon.assert;
  8. var pass = TestUnitCommon.pass;
  9. var fail = TestUnitCommon.fail;
  10. var context = TestUnitCommon.context;
  11. var grammar = language.grammar;
  12. function testWithContext(context, pass, fail){
  13. return TestUnitCommon.testWithContext(context, grammar.declarationSequence, language, pass, fail);
  14. }
  15. function testWithModule(src, pass, fail){
  16. return TestUnitCommon.testWithModule(src, language, pass, fail);
  17. }
  18. function testWithGrammar(parser, pass, fail){
  19. return TestUnitCommon.testWithGrammar(parser, language, pass, fail);
  20. }
  21. var temporaryValues = {
  22. context: context(
  23. grammar.declarationSequence,
  24. "TYPE Base = RECORD END;"
  25. + "Derived = RECORD (Base) flag: BOOLEAN END;"
  26. + "Derived2 = RECORD (Derived) flag2: BOOLEAN END;"
  27. + "PBase = POINTER TO Base;"
  28. + "PDerived = POINTER TO Derived;"
  29. + "PDerived2 = POINTER TO Derived2;"
  30. + "VAR pBase: POINTER TO Base; bVar: BOOLEAN;"
  31. + "PROCEDURE proc(b: BOOLEAN): BOOLEAN; RETURN b END proc;"
  32. + "PROCEDURE passPDerived(p: PDerived): BOOLEAN; RETURN TRUE END;"
  33. ),
  34. __expression: function(e){
  35. return "PROCEDURE p(); BEGIN b <- pBase; b2 <- pBase; ASSERT(" + e + "); END p;";
  36. },
  37. __statement: function(e){
  38. return "PROCEDURE p(); BEGIN b <- pBase; b2 <- pBase; " + e + " END p;";
  39. },
  40. passExpressions: function(){
  41. return this.__pass(this.__expression.bind(this), arguments);
  42. },
  43. passStatements: function(){
  44. return this.__pass(this.__statement.bind(this), arguments);
  45. },
  46. failExpressions: function(){
  47. return this.__fail(this.__expression.bind(this), arguments);
  48. },
  49. failStatements: function(){
  50. return this.__fail(this.__statement.bind(this), arguments);
  51. },
  52. __pass: function(make, cases){
  53. var result = [];
  54. for(var i = 0; i < cases.length; ++i)
  55. result.push(make(cases[i]));
  56. return pass.apply(this, result);
  57. },
  58. __fail: function(make, cases){
  59. var result = [];
  60. for(var i = 0; i < cases.length; ++i)
  61. result.push([make(cases[i]), "type 'Base' has no 'flag' field"]);
  62. return fail.apply(this, result);
  63. }
  64. };
  65. var TestVar = Class.extend({
  66. init: function(){
  67. this.__type = "type";
  68. },
  69. type: function(){return this.__type;},
  70. setType: function(type){this.__type = type;}
  71. });
  72. exports.suite = {
  73. //"code": makeCodeSuite(),
  74. "arithmetic operators": testWithContext(
  75. context(grammar.statement, "VAR b1: BOOLEAN;"),
  76. pass(),
  77. fail(["b1 := b1 + b1", "operator '+' type mismatch: numeric type or SET or STRING expected, got 'BOOLEAN'"])
  78. ),
  79. "key words": testWithGrammar(
  80. grammar.variableDeclaration,
  81. pass(),
  82. fail(["SELF: INTEGER", "not parsed"],
  83. ["SUPER: INTEGER", "not parsed"],
  84. ["STRING: INTEGER", "'STRING' already declared"]
  85. )
  86. ),
  87. "abstract method declaration": testWithContext(
  88. context(grammar.declarationSequence,
  89. "TYPE T = RECORD PROCEDURE p() END;"
  90. + "D = RECORD(T) END;"
  91. + "T2 = RECORD PROCEDURE p1(); PROCEDURE p2(i: INTEGER): BOOLEAN END;"
  92. ),
  93. pass(),
  94. fail(["VAR r: T;",
  95. "cannot instantiate 'T' because it has abstract method(s): p"],
  96. ["VAR r: T2;",
  97. "cannot instantiate 'T2' because it has abstract method(s): p1, p2"],
  98. ["PROCEDURE p(); VAR p: POINTER TO T; BEGIN NEW(p); END p;",
  99. "cannot instantiate 'T' because it has abstract method(s): p"],
  100. ["PROCEDURE p(); TYPE LocalT = RECORD(T) END; VAR r: LocalT; END p;",
  101. "cannot instantiate 'LocalT' because it has abstract method(s): p"],
  102. ["PROCEDURE p(); TYPE LocalT = RECORD(T) END; VAR p: POINTER TO LocalT; BEGIN NEW(p) END p;",
  103. "cannot instantiate 'LocalT' because it has abstract method(s): p"],
  104. ["VAR r: D;",
  105. "cannot instantiate 'D' because it has abstract method(s): p"],
  106. ["PROCEDURE p(); VAR p: POINTER TO D; BEGIN NEW(p); END p;",
  107. "cannot instantiate 'D' because it has abstract method(s): p"],
  108. ["PROCEDURE p(); TYPE HasAbstractField = RECORD f: T; END; END;",
  109. "cannot instantiate 'T' because it has abstract method(s): p"]
  110. )
  111. ),
  112. "new method declaration": testWithContext(
  113. context(grammar.declarationSequence,
  114. "TYPE T = RECORD PROCEDURE p(); intField: INTEGER END; A = ARRAY 1 OF INTEGER;"),
  115. pass("PROCEDURE T.p(); END T.p;",
  116. "PROCEDURE T.p(); END;"
  117. ),
  118. fail(["PROCEDURE TUnk.p(); END TUnk.p;", "undeclared identifier: 'TUnk'"],
  119. ["PROCEDURE A.p(); END A.p;",
  120. "RECORD type expected in method declaration, got 'ARRAY 1 OF INTEGER'"],
  121. ["PROCEDURE T.p(); END p;",
  122. "mismatched method names: expected 'T.p' at the end (or nothing), got 'p'"],
  123. ["PROCEDURE T.p(); END T2.p;",
  124. "mismatched method names: expected 'T.p' at the end (or nothing), got 'T2.p'"],
  125. ["PROCEDURE T.p(); END T.p2;",
  126. "mismatched method names: expected 'T.p' at the end (or nothing), got 'T.p2'"],
  127. ["PROCEDURE T.intField(); END T.intField;",
  128. "'T' has no declaration for method 'intField'"],
  129. ["PROCEDURE T.p(); END T.p; PROCEDURE T.p(); END T.p;",
  130. "method 'T.p' already defined"],
  131. ["PROCEDURE p(); TYPE T = RECORD PROCEDURE m(); PROCEDURE m() END; END p;",
  132. "cannot declare a new method 'm': method already was declared"],
  133. ["PROCEDURE p(); TYPE T = RECORD m: INTEGER; PROCEDURE m() END; END p;",
  134. "cannot declare method, record already has field 'm'"],
  135. ["PROCEDURE p(); TYPE T = RECORD PROCEDURE m(); m: INTEGER END; END p;",
  136. "cannot declare field, record already has method 'm'"]
  137. )
  138. ),
  139. "method is not exported in base record": testWithModule(
  140. "MODULE test;"
  141. + "TYPE Base* = RECORD PROCEDURE method(); END;"
  142. + "END test.",
  143. pass(),
  144. fail(["MODULE m; IMPORT test; TYPE D = RECORD(test.Base) PROCEDURE method(); END; END m.",
  145. "cannot declare a new method 'method': method already was declared in the base record (but was not exported)"],
  146. ["MODULE m; IMPORT test; TYPE D = RECORD(test.Base) method: INTEGER; END; END m.",
  147. "cannot declare field, record already has method 'method' in the base record (was not exported)"],
  148. ["MODULE m; IMPORT test; TYPE D = RECORD(test.Base) END; PROCEDURE D.method(); END; END m.",
  149. "'D' has no declaration for method 'method'"])
  150. ),
  151. "overridden method declaration": testWithContext(
  152. context(grammar.declarationSequence,
  153. "TYPE Base = RECORD PROCEDURE p() END; T = RECORD (Base) END;"
  154. + "PROCEDURE Base.p(); END Base.p;"),
  155. pass("PROCEDURE T.p(); END T.p;"),
  156. fail(["PROCEDURE T.pUnk(); END T.pUnk;",
  157. "'T' has no declaration for method 'pUnk'"],
  158. ["PROCEDURE proc(); TYPE T = RECORD (Base) PROCEDURE p() END; END proc;",
  159. "cannot declare a new method 'p': method already was declared"],
  160. ["PROCEDURE T.p(); END T.p; PROCEDURE T.p(); END T.p;",
  161. "method 'T.p' already defined"],
  162. ["PROCEDURE T.p(a: INTEGER); END T.p;",
  163. "overridden method 'p' signature mismatch: should be 'PROCEDURE', got 'PROCEDURE(INTEGER)'"],
  164. ["PROCEDURE p(); PROCEDURE T.p(); END T.p; END p;",
  165. "method should be defined in the same scope as its bound type 'T'"]
  166. )
  167. ),
  168. "SELF": testWithContext(
  169. context(grammar.declarationSequence,
  170. "TYPE T = RECORD PROCEDURE p(); i: INTEGER END;"
  171. + "PROCEDURE proc(i: INTEGER); END proc;"),
  172. pass("PROCEDURE T.p(); BEGIN SELF.i := 0; END T.p;",
  173. "PROCEDURE T.p(); BEGIN proc(SELF.i); END T.p;"
  174. ),
  175. fail(["PROCEDURE p(); BEGIN SELF.i := 0; END p;",
  176. "SELF can be used only in methods"])
  177. ),
  178. "SELF as VAR parameter": testWithContext(
  179. context(grammar.declarationSequence,
  180. "TYPE T = RECORD PROCEDURE method() END;"
  181. + "PROCEDURE refProc(VAR r: T); END;"
  182. ),
  183. pass("PROCEDURE T.method(); BEGIN refProc(SELF); END;")
  184. ),
  185. "SELF as pointer": testWithContext(
  186. context(grammar.declarationSequence,
  187. "TYPE T = RECORD PROCEDURE method() END;"
  188. + "PT = POINTER TO T;"
  189. + "VAR pVar: PT;"
  190. + "PROCEDURE refProc(VAR r: T); END;"
  191. + "PROCEDURE refPointerProc(VAR p: PT); END;"
  192. ),
  193. pass("PROCEDURE T.method(); BEGIN pVar := SELF(POINTER) END T.method;",
  194. "PROCEDURE p();"
  195. + "TYPE Derived = RECORD(T) END; VAR pd: POINTER TO Derived;"
  196. + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN NEW(pd); pVar := SELF(POINTER); END Derived.method;"
  197. + "END p;",
  198. "PROCEDURE T.method(); BEGIN refProc(SELF(POINTER)^) END;"
  199. ),
  200. fail(["PROCEDURE T.method(); BEGIN refPointerProc(SELF(POINTER)) END T.method;",
  201. "SELF(POINTER) cannot be passed as VAR actual parameter"],
  202. ["PROCEDURE T.method(); BEGIN SELF(POINTER) := pVar; END T.method;",
  203. "cannot assign to SELF(POINTER)"],
  204. ["PROCEDURE p();"
  205. + "TYPE Derived = RECORD(T) END; VAR d: Derived;"
  206. + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN pVar := SELF(POINTER); END Derived.method;"
  207. + "END p;",
  208. "cannot declare a variable of type 'Derived' (and derived types) because SELF(POINTER) was used in its method(s)"],
  209. ["PROCEDURE p();"
  210. + "TYPE Derived = RECORD(T) END; Derived2 = RECORD(Derived) END;"
  211. + "VAR d: Derived2;"
  212. + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN pVar := SELF(POINTER); END Derived.method;"
  213. + "END p;",
  214. "cannot declare a variable of type 'Derived' (and derived types) because SELF(POINTER) was used in its method(s)"]
  215. )
  216. ),
  217. "method call": testWithContext(
  218. context(grammar.expression,
  219. "TYPE T = RECORD PROCEDURE p(); PROCEDURE f(): INTEGER END;"
  220. + "VAR o: T;"
  221. + "PROCEDURE T.p(); END T.p;"
  222. + "PROCEDURE T.f(): INTEGER; RETURN 0 END T.f;"
  223. ),
  224. pass("o.f()"),
  225. fail(["o.p()", "procedure returning no result cannot be used in an expression"])
  226. ),
  227. "method call as statement": testWithContext(
  228. context(grammar.statement,
  229. "TYPE T = RECORD PROCEDURE p(); PROCEDURE f(): INTEGER END;"
  230. + "VAR o: T;"
  231. + "PROCEDURE T.p(); END T.p;"
  232. + "PROCEDURE T.f(): INTEGER; RETURN 0 END T.f;"
  233. ),
  234. pass("o.p"),
  235. fail(["o.f", "procedure returning a result cannot be used as a statement"])
  236. ),
  237. "cannot assign to method": testWithContext(
  238. context(grammar.statement,
  239. "TYPE T = RECORD PROCEDURE p() END;"
  240. + "VAR o: T;"
  241. + "PROCEDURE T.p(); END T.p;"
  242. ),
  243. pass(),
  244. fail(["o.p := o.p", "method 'p' cannot be referenced"],
  245. ["o.p := NIL", "cannot assign to method 'p'"])
  246. ),
  247. "method cannot be referenced": testWithContext(
  248. context(grammar.statement,
  249. "TYPE T = RECORD PROCEDURE p() END;"
  250. + "Proc = PROCEDURE();"
  251. + "VAR o: T;"
  252. + "PROCEDURE T.p(); END T.p;"
  253. + "PROCEDURE proc(p: Proc); END proc;"
  254. ),
  255. pass(),
  256. fail(["proc(o.p)", "method 'p' cannot be referenced"],
  257. ["v <- o.p", "method 'p' cannot be referenced"])
  258. ),
  259. "method super call": testWithContext(
  260. context(grammar.declarationSequence,
  261. "TYPE T = RECORD PROCEDURE p(); PROCEDURE pAbstract(); PROCEDURE pAbstract2() END;"
  262. + "D = RECORD(T) PROCEDURE pNoSuper() END;"
  263. + "PROCEDURE T.p(); END T.p;"
  264. ),
  265. pass("PROCEDURE D.p(); BEGIN SUPER() END D.p;"),
  266. fail(["PROCEDURE D.pNoSuper(); BEGIN SUPER() END D.pNoSuper;",
  267. "there is no method 'pNoSuper' in base type(s)"],
  268. ["PROCEDURE p(); BEGIN SUPER() END p;",
  269. "SUPER can be used only in methods"],
  270. ["PROCEDURE T.pNoBase(); BEGIN SUPER() END T.pNoBase;",
  271. "'T' has no base type - SUPER cannot be used"],
  272. ["PROCEDURE D.pAbstract(); BEGIN SUPER() END D.pAbstract;",
  273. "cannot use abstract method(s) in SUPER calls: pAbstract"],
  274. ["PROCEDURE D.pAbstract(); BEGIN SUPER() END D.pAbstract; PROCEDURE D.pAbstract2(); BEGIN SUPER() END D.pAbstract2;",
  275. "cannot use abstract method(s) in SUPER calls: pAbstract, pAbstract2"]
  276. )
  277. ),
  278. "export method": testWithContext(
  279. context(grammar.declarationSequence,
  280. "TYPE T = RECORD PROCEDURE p() END;"
  281. ),
  282. pass(),
  283. fail(["PROCEDURE T.p*(); END T.p;",
  284. "method implementation cannot be exported: p"],
  285. ["TYPE R = RECORD PROCEDURE m*(); END;",
  286. "method 'm' cannot be exported because record itslef is not exported"] )
  287. ),
  288. "import method": testWithModule(
  289. "MODULE test;"
  290. + "TYPE T* = RECORD PROCEDURE m*(); PROCEDURE mNotExported() END;"
  291. + "PROCEDURE T.m(); END T.m; PROCEDURE T.mNotExported(); END T.mNotExported;"
  292. + "END test.",
  293. pass("MODULE m; IMPORT test; VAR r: test.T; BEGIN r.m(); END m.",
  294. "MODULE m; IMPORT test; TYPE T = RECORD(test.T) END; PROCEDURE T.m(); END T.m; END m."
  295. ),
  296. fail(["MODULE m; IMPORT test; VAR r: test.T; BEGIN r.mNotExported(); END m.",
  297. "type 'T' has no 'mNotExported' field"],
  298. ["MODULE m; IMPORT test; TYPE T = RECORD(test.T) END; PROCEDURE T.mNotExported(); END T.mNotExported; END m.",
  299. "'T' has no declaration for method 'mNotExported'"])
  300. ),
  301. "import abstract record": testWithModule(
  302. "MODULE test;"
  303. + "TYPE T* = RECORD PROCEDURE m*(); END;"
  304. + "Derived* = RECORD(T) END;"
  305. + "END test.",
  306. pass("MODULE m; IMPORT test; TYPE T = RECORD f: POINTER TO test.T; END; END m."
  307. ),
  308. fail(["MODULE m; IMPORT test; TYPE T = RECORD f: test.T; END; END m.",
  309. "cannot instantiate 'T' because it has abstract method(s): m"],
  310. ["MODULE m; IMPORT test; TYPE T = RECORD(test.T) END; VAR r: T; END m.",
  311. "cannot instantiate 'T' because it has abstract method(s): m"],
  312. ["MODULE m; IMPORT test; TYPE T = RECORD(test.Derived) END; VAR r: T; END m.",
  313. "cannot instantiate 'T' because it has abstract method(s): m"]
  314. )
  315. ),
  316. "non-scalar variables can be exported": testWithContext(
  317. context(grammar.declarationSequence,
  318. "TYPE T = RECORD END; A = ARRAY 3 OF INTEGER;"
  319. ),
  320. pass("VAR r*: T;",
  321. "VAR a*: A;"),
  322. fail()
  323. ),
  324. "export as read-only": testWithContext(
  325. context(grammar.declarationSequence, ""),
  326. pass("TYPE T* = RECORD i-: INTEGER END;"),
  327. fail(["TYPE T- = RECORD END;",
  328. "type cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  329. ["PROCEDURE p-(); END p;",
  330. "procedure cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  331. ["CONST c- = 123;",
  332. "constant cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  333. ["VAR i-: INTEGER;",
  334. "variable cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  335. ["TYPE T* = RECORD PROCEDURE p-() END;",
  336. "method cannot be exported as read-only using '-' mark (did you mean '*'?)"]
  337. )
  338. ),
  339. "field exported as read-only is writable in current module": testWithContext(
  340. context(grammar.statement,
  341. "TYPE T* = RECORD i-: INTEGER END;"
  342. + "VAR r: T;"
  343. ),
  344. pass("r.i := 123"),
  345. fail()
  346. ),
  347. "import as read-only": testWithModule(
  348. "MODULE test; TYPE T* = RECORD f-: INTEGER END; END test.",
  349. pass(),
  350. fail(["MODULE m; IMPORT test; VAR r: test.T; BEGIN r.f := 123; END m.",
  351. "cannot assign to read-only record's field"],
  352. ["MODULE m; IMPORT test; TYPE D = RECORD(test.T) END; VAR r: D; BEGIN r.f := 123; END m.",
  353. "cannot assign to read-only record's field"]
  354. )),
  355. "STRING variable": testWithGrammar(
  356. grammar.variableDeclaration,
  357. pass("s: STRING")
  358. ),
  359. "STRING expression": testWithContext(
  360. context(grammar.expression,
  361. "VAR s1, s2: STRING; a: ARRAY 10 OF CHAR;"),
  362. pass("s1 + s2",
  363. "s1 + \"abc\"",
  364. "\"abc\" + s1",
  365. "s1 = s2",
  366. "s1 = \"abc\"",
  367. "s1 = 22X",
  368. "\"abc\" = s1",
  369. "22X = s1",
  370. "s1 # s2",
  371. "s1 # \"abc\"",
  372. "s1 # 22X",
  373. "\"abc\" # s1",
  374. "22X # s1",
  375. "s1 < s2",
  376. "s1 < \"abc\"",
  377. "s1 < 22X",
  378. "\"abc\" < s1",
  379. "22X < s1",
  380. "s1 > s2",
  381. "s1 > \"abc\"",
  382. "s1 > 22X",
  383. "\"abc\" > s1",
  384. "22X > s1",
  385. "s1 <= s2",
  386. "s1 <= \"abc\"",
  387. "\"abc\" <=s1",
  388. "22X <= s1",
  389. "s1 >= \"abc\"",
  390. "s1 >= 22X",
  391. "s1 >= s2",
  392. "\"abc\" >= s1",
  393. "22X >= s1"
  394. ),
  395. fail(["s1 = NIL", "type mismatch: expected 'STRING', got 'NIL'"],
  396. ["s1 = a", "type mismatch: expected 'STRING', got 'ARRAY 10 OF CHAR'"],
  397. ["a = s1", "type mismatch: expected 'ARRAY 10 OF CHAR', got 'STRING'"]
  398. )
  399. ),
  400. "STRING literal expression": testWithContext(
  401. context(grammar.expression,
  402. "CONST cs = \"abc\";"
  403. + "PROCEDURE pString(s: STRING): STRING; RETURN s END pString;"
  404. + "PROCEDURE pStringByRef(VAR s: STRING): STRING; RETURN s END pStringByRef;"
  405. ),
  406. pass("\"abc\" + \"cde\"",
  407. "cs + cs",
  408. "cs + \"abc\"",
  409. "cs = \"abc\"",
  410. "cs # \"abc\"",
  411. "cs < \"abc\"",
  412. "cs > \"abc\"",
  413. "cs <= \"abc\"",
  414. "cs >= \"abc\"",
  415. "pString(cs)",
  416. "pString(\"abc\")"
  417. ),
  418. fail(["pStringByRef(cs)", "type mismatch for argument 1: cannot pass 'multi-character string' as VAR parameter of type 'STRING'"],
  419. ["pStringByRef(\"abc\")", "type mismatch for argument 1: cannot pass 'multi-character string' as VAR parameter of type 'STRING'"]
  420. )
  421. ),
  422. "STRING assignment": testWithContext(
  423. context(grammar.statement,
  424. "VAR s1, s2: STRING; a: ARRAY 10 OF CHAR;"),
  425. pass("s1 := s2",
  426. "s1 := \"abc\"",
  427. "s1 := 22X"
  428. ),
  429. fail(["a := s1", "type mismatch: 'ARRAY 10 OF CHAR' cannot be assigned to 'STRING' expression"],
  430. ["s1 := a", "type mismatch: 'STRING' cannot be assigned to 'ARRAY 10 OF CHAR' expression"]
  431. )
  432. ),
  433. "STRING and ARRAY OF CHAR": testWithContext(
  434. context(grammar.expression,
  435. "VAR s: STRING; a: ARRAY 10 OF CHAR;"
  436. + "PROCEDURE pArray(a: ARRAY OF CHAR): BOOLEAN; RETURN FALSE END pArray;"
  437. + "PROCEDURE pString(s: STRING): BOOLEAN; RETURN FALSE END pString;"
  438. + "PROCEDURE pVar(VAR a: ARRAY OF CHAR): BOOLEAN; RETURN FALSE END pVar;"
  439. + "PROCEDURE pIntArray(a: ARRAY OF INTEGER): BOOLEAN; RETURN FALSE END pIntArray;"
  440. ),
  441. pass("pArray(s)"),
  442. fail(["pVar(s)", "type mismatch for argument 1: cannot pass 'STRING' as VAR parameter of type 'ARRAY OF CHAR'"],
  443. ["pString(a)", "type mismatch for argument 1: 'ARRAY 10 OF CHAR' cannot be converted to 'STRING'"],
  444. ["pIntArray(s)", "type mismatch for argument 1: 'STRING' cannot be converted to 'ARRAY OF INTEGER'"]
  445. )
  446. ),
  447. "STRING LEN": testWithContext(
  448. context(grammar.expression,
  449. "VAR s: STRING;"),
  450. pass("LEN(s)"),
  451. fail()
  452. ),
  453. "STRING indexing": testWithContext(
  454. context(grammar.expression,
  455. "VAR s: STRING;"
  456. + "PROCEDURE pCharByVar(VAR c: CHAR): CHAR; RETURN c END pCharByVar;"),
  457. pass("s[0]"),
  458. fail(["s[-1]", "index is negative: -1"],
  459. ["pCharByVar(s[0])", "string element cannot be passed as VAR actual parameter"]
  460. )
  461. ),
  462. "designate call result in expression": testWithContext(
  463. context(grammar.expression,
  464. "TYPE PT = POINTER TO RECORD field: INTEGER END;"
  465. + "VAR p: PT;"
  466. + "PROCEDURE proc(): PT; RETURN p END proc;"
  467. + "PROCEDURE int(): INTEGER; RETURN 0 END int;"
  468. + "PROCEDURE intVar(VAR i: INTEGER): INTEGER; RETURN i END intVar;"),
  469. pass("proc().field",
  470. "intVar(proc().field)"),
  471. fail(["intVar(int())", "expression cannot be used as VAR parameter"])
  472. ),
  473. "designate call result in statement": testWithContext(
  474. context(grammar.statement,
  475. "TYPE PT = POINTER TO RECORD field: INTEGER; proc: PROCEDURE END;"
  476. + "ProcType = PROCEDURE;"
  477. + "VAR p: PT;"
  478. + "PROCEDURE procVoid(); END procVoid;"
  479. + "PROCEDURE proc(): PT; RETURN p END proc;"
  480. + "PROCEDURE int(): INTEGER; RETURN 0 END int;"
  481. + "PROCEDURE intVar(VAR i: INTEGER); END intVar;"
  482. + "PROCEDURE returnProc(): ProcType; RETURN procVoid END returnProc;"
  483. ),
  484. pass("proc().field := 0",
  485. "proc().proc()",
  486. "proc().proc"
  487. ),
  488. fail(["int() := 0", "cannot assign to procedure call result"],
  489. ["intVar(int())", "expression cannot be used as VAR parameter"],
  490. ["procVoid()()", "PROCEDURE expected, got 'procedure call statement'"],
  491. ["int()()", "PROCEDURE expected, got 'INTEGER'"],
  492. ["returnProc()", "procedure returning a result cannot be used as a statement"] // call is not applied implicitly to result
  493. )
  494. ),
  495. "type promotion": {
  496. "or" : pass(
  497. function(){
  498. var or = new TypePromotion.Or();
  499. var a = new TestVar();
  500. var p = or.next();
  501. assert(a.type() == "type");
  502. p.invert();
  503. p.promote(a, "type1");
  504. assert(a.type() == "type");
  505. or.next();
  506. assert(a.type() == "type1");
  507. or.reset();
  508. assert(a.type() == "type");
  509. },
  510. function(){
  511. var or = new TypePromotion.Or();
  512. var a = new TestVar();
  513. var p = or.next(p);
  514. p.promote(a, "type1");
  515. or.next();
  516. assert(a.type() == "type");
  517. },
  518. function(){
  519. var or = new TypePromotion.Or();
  520. var a = new TestVar();
  521. var p1 = or.next();
  522. p1.promote(a, "type1");
  523. var p2 = or.next();
  524. p2.invert();
  525. p2.promote(a, "type2");
  526. assert(a.type() == "type");
  527. assert(a.type() == "type");
  528. or.next();
  529. assert(a.type() == "type2");
  530. or.reset();
  531. assert(a.type() == "type");
  532. }
  533. ),
  534. "and": pass(
  535. function(){
  536. var and = new TypePromotion.And();
  537. var a = new TestVar();
  538. var p = and.next();
  539. p.promote(a, "type1");
  540. and.next();
  541. assert(a.type() == "type1");
  542. and.reset();
  543. assert(a.type() == "type");
  544. },
  545. function(){ // (a IS type1) & (v OR (a IS type2)) & v
  546. var and = new TypePromotion.And();
  547. var a = new TestVar();
  548. var p = and.next();
  549. p.promote(a, "type1");
  550. var subOr = and.next().makeOr();
  551. subOr.next();
  552. subOr.next().promote(a, "type2");
  553. and.next();
  554. assert(a.type() == "type1");
  555. and.reset();
  556. assert(a.type() == "type");
  557. },
  558. function(){ // (a IS type1) & ~(v OR ~(a IS type2)) & v
  559. var and = new TypePromotion.And();
  560. var a = new TestVar();
  561. and.next().promote(a, "type1");
  562. var subOr = and.next();
  563. subOr.invert();
  564. subOr = subOr.makeOr();
  565. subOr.next();
  566. var p = subOr.next();
  567. p.invert();
  568. p.promote(a, "type2");
  569. and.next();
  570. assert(a.type() == "type2");
  571. and.reset();
  572. assert(a.type() == "type");
  573. },
  574. function(){ // (a IS type1) & (v & (a IS type2))
  575. var and = new TypePromotion.And();
  576. var a = new TestVar();
  577. and.next().promote(a, "type1");
  578. var sub = and.next().makeAnd();
  579. sub.next();
  580. assert(a.type() == "type1");
  581. sub.next().promote(a, "type2");
  582. assert(a.type() == "type1");
  583. and.and();
  584. assert(a.type() == "type2");
  585. and.or();
  586. assert(a.type() == "type");
  587. },
  588. function(){ // (~(~(a IS type1)) & v) OR v
  589. var a = new TestVar();
  590. var or = new TypePromotion.Or();
  591. var and = or.next().makeAnd();
  592. var p1 = and.next();
  593. p1.invert();
  594. var p2 = p1.makeOr().next().makeAnd().next();
  595. p2.invert();
  596. p2.promote(a, "type1");
  597. and.next();
  598. assert(a.type() == "type1");
  599. or.next();
  600. assert(a.type() == "type");
  601. },
  602. function(){ // (v OR (a IS type1)) & v)
  603. var a = new TestVar();
  604. var and = new TypePromotion.And();
  605. var or = and.next().makeOr();
  606. or.next();
  607. or.next().makeAnd().next().promote(a, "type1");
  608. and.next();
  609. assert(a.type() == "type");
  610. }
  611. )
  612. },
  613. "in place variables": {
  614. "initialization": testWithContext(
  615. context(grammar.statement,
  616. "VAR i: INTEGER; s: STRING;"
  617. + "PROCEDURE p(): BOOLEAN; RETURN FALSE END p;"
  618. + "PROCEDURE void(); END void;"
  619. ),
  620. pass("v <- 0",
  621. "v <- 1.23",
  622. "v <- TRUE",
  623. "v <- i",
  624. "v <- i + i",
  625. "v <- \"abc\" + s",
  626. "v <- s + \"abc\"",
  627. "v <- \"abc\"",
  628. "v <- \"abc\" + \"def\"",
  629. "v <- p()",
  630. "v <- void" // procedure type
  631. ),
  632. fail(["v <-", "initialization expression expected"],
  633. ["v <- void()", "procedure returning no result cannot be used in an expression"],
  634. ["v <- NIL", "cannot use NIL to initialize variable 'v'"]
  635. )
  636. ),
  637. "scope": testWithContext(
  638. temporaryValues.context,
  639. temporaryValues.passStatements(
  640. "v1 <- 0; v2 <-0;",
  641. "i <- 0; ASSERT(i = 0);",
  642. "WHILE FALSE DO v <- 0; ASSERT(v = 0); END; WHILE FALSE DO v <- 0; END;",
  643. "WHILE FALSE DO i1 <- 0; WHILE FALSE DO i2 <- 0; ASSERT(i1 = 0); ASSERT(i2 = 0); END; END;",
  644. "WHILE bVar DO v <- 0; ELSIF ~bVar DO v <- 0 END;",
  645. "IF FALSE THEN v <- 0; ASSERT(v = 0); END; IF FALSE THEN v <- 0; END;",
  646. "IF FALSE THEN v <- 0; END; IF FALSE THEN v <- 0; END;",
  647. "IF FALSE THEN v <- 0; ELSIF FALSE THEN v <- 0; ELSE v <- 0; END;",
  648. "i <- 0; CASE i OF 0: v <- 0 | 1: v <- 1; ; ASSERT(v = 1); END;",
  649. "REPEAT v <- 0; UNTIL FALSE; REPEAT v <- 0; UNTIL FALSE;",
  650. "REPEAT v <- 0; ASSERT(v = 0); UNTIL v # 0;",
  651. "i <- 0; FOR i := 0 TO 10 DO v <- 0; END; FOR i := 0 TO 10 DO v <- 0; END;"
  652. ),
  653. fail(["PROCEDURE p(); BEGIN v <- 0; v <-0; END p;", "'v' already declared"],
  654. ["PROCEDURE p(); VAR v: INTEGER; BEGIN v <- 0; END p;", "'v' already declared"],
  655. ["PROCEDURE p(); BEGIN v <- 0; WHILE FALSE DO v <- 0; END; END p;",
  656. "'v' already declared in procedure scope"],
  657. ["PROCEDURE p(); BEGIN i <- 0; IF FALSE THEN i <- 0; END; END p;",
  658. "'i' already declared in procedure scope"],
  659. ["PROCEDURE p(); BEGIN i <- 0; IF TRUE THEN IF TRUE THEN i <- 0; END; END; END p;",
  660. "'i' already declared in procedure scope"],
  661. ["PROCEDURE p(); BEGIN WHILE FALSE DO i <- 0; WHILE FALSE DO i <- 0; END; END; END p;",
  662. "'i' already declared in operator scope"]
  663. )
  664. ),
  665. "type promotion in expression": testWithContext(
  666. temporaryValues.context,
  667. temporaryValues.passExpressions(
  668. "(b IS PDerived) & b.flag",
  669. "(b IS PDerived) & bVar & b.flag",
  670. "(b IS PDerived) & (bVar OR b.flag)",
  671. "(b IS PDerived) & (b2 IS PDerived) & b.flag & b2.flag",
  672. "(b IS PDerived) & proc(TRUE) & b.flag",
  673. "(b IS PDerived) & ~proc(TRUE) & b.flag",
  674. "~(~(b IS PDerived)) & b.flag",
  675. "~~(b IS PDerived) & b.flag",
  676. "(b IS PDerived) & ((b IS PDerived2) OR bVar) & b.flag",
  677. "(b IS PDerived) & (bVar OR (b IS PDerived2)) & b.flag",
  678. "(b IS PDerived) & ~(bVar OR ~(b IS PDerived2)) & b.flag2",
  679. "~(bVar & (b IS PDerived)) OR b.flag"
  680. //TODO: "((b IS PDerived) = TRUE) & b.flag); END p;",
  681. ),
  682. temporaryValues.failExpressions(
  683. "(b IS PDerived) OR b.flag",
  684. "(bVar OR (b IS PDerived)) & b.flag",
  685. "(b IS PDerived) OR bVar & b.flag",
  686. "~(b IS PDerived) & b.flag",
  687. "((b IS PDerived) & (b2 IS PDerived) OR bVar) & b.flag",
  688. "proc(b IS PDerived) & proc(b.flag)",
  689. "ORD(b IS PDerived) * ORD(b.flag) = 0",
  690. "((b IS PDerived) = FALSE) & b.flag",
  691. "((b IS PDerived) & bVar) = b.flag",
  692. "b IS PDerived); ASSERT(b.flag",
  693. "((b IS PDerived) OR (b IS PDerived)) & b.flag",
  694. "(b IS PDerived) OR (b IS PDerived) OR b.flag",
  695. "(bVar OR (b IS PDerived)) & b.flag",
  696. "~(bVar & ~(b IS PDerived)) & b.flag"
  697. )
  698. ),
  699. "invert type promotion in expression": testWithContext(
  700. temporaryValues.context,
  701. temporaryValues.passExpressions(
  702. "~(b IS PDerived) OR b.flag",
  703. "~(b IS PDerived) OR b.flag OR bVar",
  704. "~(b IS PDerived) OR b.flag & bVar",
  705. "~(b IS PDerived) OR bVar & b.flag",
  706. "~(b IS PDerived) OR (bVar & b.flag)",
  707. "~(b IS PDerived) OR bVar OR b.flag",
  708. "~(b IS PDerived) OR (bVar = b.flag)",
  709. "~(~(b IS PDerived) OR bVar) & b.flag",
  710. "~(~(b IS PDerived) OR b.flag) & b.flag",
  711. "~(b IS PDerived) OR ~(b2 IS PDerived) OR b2.flag",
  712. "~(b IS PDerived) OR b.flag OR ~(b2 IS PDerived) OR b2.flag",
  713. "~((b IS PDerived) & b.flag) OR b.flag OR ~(b2 IS PDerived) OR b2.flag",
  714. "~((b IS PDerived) & b.flag) OR b.flag OR ~((b2 IS PDerived) & b.flag & b2.flag) OR b2.flag"
  715. ),
  716. temporaryValues.failExpressions(
  717. "(~(b IS PDerived) OR bVar) & b.flag",
  718. "(ORD(~(b IS PDerived)) + ORD(b.flag)",
  719. "~(~(b IS PDerived) OR bVar) OR b.flag",
  720. "~(~(b IS PDerived) & bVar) & b.flag",
  721. "~(b IS PDerived) OR b.flag = b.flag"
  722. )
  723. ),
  724. "type promotion in separate statements": testWithContext(
  725. temporaryValues.context,
  726. pass(),
  727. temporaryValues.failStatements(
  728. "bVar := b IS PDerived; ASSERT(b.flag)",
  729. "bVar := (b IS PDerived) & bVar; ASSERT(b.flag)"
  730. )
  731. ),
  732. "type promotion in ternary operator": testWithContext(
  733. temporaryValues.context,
  734. temporaryValues.passExpressions(
  735. "b IS PDerived ? b.flag : FALSE",
  736. "~(b IS PDerived) ? FALSE : b.flag",
  737. "(b IS PDerived) & bVar ? b.flag : FALSE",
  738. "~~(b IS PDerived) ? b.flag : FALSE"
  739. ),
  740. temporaryValues.failExpressions(
  741. "b IS PDerived ? FALSE : b.flag",
  742. "(b IS PDerived ? FALSE : TRUE) & b.flag"
  743. )
  744. ),
  745. "type promotion in IF": testWithContext(
  746. temporaryValues.context,
  747. temporaryValues.passStatements(
  748. "IF b IS PDerived THEN b.flag := FALSE; END;",
  749. "IF (b IS PDerived) & bVar THEN b.flag := FALSE; END;",
  750. "IF bVar & (b IS PDerived) THEN b.flag := FALSE; END;",
  751. "IF FALSE THEN ELSIF b IS PDerived THEN b.flag := FALSE; END;",
  752. "IF b IS PDerived THEN bVar := (b IS PDerived2) & b.flag2; b.flag := FALSE; END;",
  753. "IF bVar THEN ELSIF b IS PDerived2 THEN ELSIF b IS PDerived THEN END;",
  754. "IF bVar THEN ELSIF b IS PDerived THEN ELSIF b IS PDerived THEN ELSIF b IS PDerived THEN END;",
  755. "IF b IS PDerived THEN IF bVar OR (b IS PDerived2) THEN b.flag := FALSE; END; END"
  756. ),
  757. temporaryValues.failStatements(
  758. "IF (b IS PDerived) OR bVar THEN b.flag := FALSE; END",
  759. "IF bVar OR (b IS PDerived) THEN b.flag := FALSE; END",
  760. "IF (b2 IS PDerived) OR (b IS PDerived) THEN b.flag := FALSE; END",
  761. "IF (b IS PDerived) OR (b IS PDerived) THEN b.flag := FALSE; END",
  762. "IF (b IS PDerived) OR (b IS PDerived) OR b.flag THEN END",
  763. "IF (b IS PDerived) OR (b IS PDerived) OR (b IS PDerived) THEN b.flag := FALSE; END",
  764. "IF ((b IS PDerived) OR (b IS PDerived)) THEN b.flag := FALSE; END",
  765. "IF (b IS PDerived) OR (b IS PDerived2) THEN b.flag := FALSE; END",
  766. "IF (b IS PDerived2) OR (b IS PDerived) THEN b.flag := FALSE; END",
  767. "IF b IS PDerived THEN END; b.flag := FALSE",
  768. "IF ~(b IS PDerived) THEN END; b.flag := FALSE",
  769. "IF ~(b IS PDerived) THEN ELSIF bVar THEN END; b.flag := FALSE",
  770. "IF ~(b IS PDerived) THEN ELSIF bVar THEN ELSE END; b.flag := FALSE",
  771. "IF bVar THEN ELSIF b IS PDerived THEN ELSE END; b.flag := FALSE",
  772. "IF b IS PDerived THEN ELSE b.flag := FALSE; END",
  773. "IF bVar OR (b IS PDerived) THEN b.flag := FALSE; END;",
  774. "IF bVar OR (b IS PDerived) THEN ELSE b.flag := FALSE; END;",
  775. "IF bVar OR ~(b IS PDerived) THEN b.flag := FALSE; END;",
  776. "IF b IS PDerived THEN ELSIF TRUE THEN b.flag := FALSE; END",
  777. "IF bVar THEN bVar := (b IS PDerived) & bVar; ASSERT(b.flag); END",
  778. "IF b IS PDerived ? FALSE : TRUE THEN ASSERT(b.flag); END"
  779. )
  780. ),
  781. "invert type promotion in IF": testWithContext(
  782. temporaryValues.context,
  783. temporaryValues.passStatements(
  784. "IF ~(b IS PDerived) THEN ELSE b.flag := FALSE; END;",
  785. "IF ~(b IS PDerived) THEN ELSIF bVar THEN b.flag := FALSE; ELSE b.flag := FALSE; END;",
  786. "IF ~(b IS PDerived) THEN ELSIF ~(b2 IS PDerived) THEN b.flag := FALSE; ELSE b.flag := FALSE; b2.flag := FALSE; END;",
  787. "IF ~(b IS PDerived) OR bVar THEN ELSE b.flag := FALSE; END;",
  788. "IF ~(b IS PDerived) OR b.flag THEN ELSE b.flag := FALSE; END;",
  789. "IF ~(b IS PDerived) OR (b2 IS PDerived) THEN ELSE b.flag := FALSE; END;",
  790. "IF ~(b IS PDerived) OR ~(b2 IS PDerived) THEN ELSE b2.flag := FALSE; END;",
  791. "IF ~(b IS PDerived) THEN bVar := b IS PDerived; ELSE b.flag := FALSE; END;",
  792. "IF ~(b IS PDerived) THEN ASSERT((b IS PDerived) & b.flag); ELSE b.flag := FALSE; END;",
  793. "IF bVar OR ~(b IS PDerived) THEN ELSE b.flag := FALSE; END;"
  794. ),
  795. temporaryValues.failStatements(
  796. "IF ~(b IS PDerived) & bVar THEN ELSE b.flag := FALSE; END; END p;",
  797. "IF ~(b IS PDerived) THEN ELSIF ~(b2 IS PDerived) THEN b2.flag := FALSE; END;",
  798. "IF bVar OR (b IS PDerived) THEN ELSE b.flag := FALSE; END;"
  799. )
  800. ),
  801. "type promotion in WHILE": testWithContext(
  802. temporaryValues.context,
  803. temporaryValues.passStatements(
  804. "WHILE (b IS PDerived) & b.flag DO END;",
  805. "WHILE ~(b IS PDerived) OR b.flag DO END;",
  806. "WHILE b IS PDerived DO b.flag := FALSE; END;",
  807. "WHILE ~(b IS PDerived) DO ELSIF b.flag DO END;",
  808. "WHILE ~(b IS PDerived) DO ELSIF bVar DO b.flag := FALSE; END;"
  809. ),
  810. temporaryValues.failStatements(
  811. "WHILE b IS PDerived DO END; b.flag := FALSE;"
  812. )
  813. ),
  814. "type promotion cannot be reset by assignment": testWithContext(
  815. temporaryValues.context,
  816. pass(),
  817. fail(["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN b := pBase; b.flag := FALSE; END; END p;",
  818. "type mismatch: 'PDerived' cannot be assigned to 'POINTER TO Base' expression"]
  819. )
  820. ),
  821. "type promotion cannot be reset by passing as VAR argument": testWithContext(
  822. temporaryValues.context,
  823. pass(),
  824. fail(["PROCEDURE p(); PROCEDURE procBaseAsVar(VAR p: PBase); END procBaseAsVar; BEGIN b <- pBase; IF b IS PDerived THEN procBaseAsVar(b); b.flag := FALSE; END; END p;",
  825. "type mismatch for argument 1: cannot pass 'PDerived' as VAR parameter of type 'PBase'"]
  826. )
  827. ),
  828. "type promotion after dereferencing": testWithContext(
  829. temporaryValues.context,
  830. temporaryValues.passExpressions(
  831. "(b^ IS Derived) & b.flag",
  832. "(b^ IS Derived) & passPDerived(b)"
  833. )
  834. ),
  835. "IS expression after type promotion": testWithContext(
  836. temporaryValues.context,
  837. pass(),
  838. fail(["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN bVar := b IS PDerived; b.flag := FALSE; END; END p;",
  839. "invalid type test: 'Derived' is not an extension of 'Derived'"]
  840. )
  841. ),
  842. "record types as values": testWithContext(
  843. context(grammar.declarationSequence,
  844. "TYPE Base = RECORD pBase: POINTER TO Base END;"
  845. + "Derived = RECORD (Base) END;"
  846. + "VAR base: Base;"
  847. + "PROCEDURE procBaseVar(VAR b: Base); END procBaseVar;"
  848. ),
  849. pass("PROCEDURE p(b: Base); BEGIN base <- b; procBaseVar(base); base := b; END p;"),
  850. fail(["PROCEDURE p(); BEGIN baseVar <- base.pBase^; ASSERT(base IS Derived); END p;",
  851. "invalid type test: a value variable cannot be used"],
  852. ["PROCEDURE p(VAR b: Base); BEGIN base <- b; ASSERT(base IS Derived); END p;",
  853. "invalid type test: a value variable cannot be used"],
  854. ["PROCEDURE p(b: Base); BEGIN base <- b; ASSERT(base IS Derived); END p;",
  855. "invalid type test: a value variable cannot be used"],
  856. ["PROCEDURE p(); TYPE Abstract = RECORD PROCEDURE method() END; PROCEDURE test(a: Abstract); BEGIN v <- a; END test; END p;",
  857. "cannot instantiate 'Abstract' because it has abstract method(s): method"],
  858. ["PROCEDURE p(); TYPE T = RECORD PROCEDURE method() END; PROCEDURE T.method(); BEGIN ASSERT(SELF(POINTER) # NIL); END T.method; PROCEDURE test(r: T); BEGIN v <- r; END test; END p;",
  859. "cannot declare a variable of type 'T' (and derived types) because SELF(POINTER) was used in its method(s)"]
  860. )
  861. ),
  862. "arrays as values": testWithContext(
  863. context(grammar.declarationSequence,
  864. "TYPE A = ARRAY 3 OF INTEGER; T = RECORD a: A END;"
  865. + "VAR r: T;"
  866. + "PROCEDURE procArrayVar(VAR a: A); END procArrayVar;"
  867. ),
  868. pass("PROCEDURE p(r: T); BEGIN a <- r.a; a[0] := 123; procArrayVar(a); END p;",
  869. "PROCEDURE p(a: A); BEGIN tmp <- a; END p;",
  870. "PROCEDURE p(); VAR a: A; BEGIN tmp <- a; END p;",
  871. "PROCEDURE p(); VAR a: ARRAY 3 OF BOOLEAN; BEGIN tmp <- a; END p;"
  872. ),
  873. fail(["PROCEDURE p(a: ARRAY OF INTEGER); BEGIN v <- a; END p;",
  874. "cannot initialize variable 'v' with open array"]
  875. )
  876. ),
  877. "FOR variable": testWithContext(
  878. context(grammar.statement, ""),
  879. pass("FOR i <- 0 TO 10 DO END",
  880. "FOR i <- 0 TO 10 DO FOR j <- 0 TO 10 BY 1 DO END END",
  881. "IF TRUE THEN FOR i <- 0 TO 10 DO END; FOR i <- 0 TO 10 BY 1 DO END; END"
  882. ),
  883. fail(["FOR i <- 0.0 TO 10 DO END", "'INTEGER' expression expected to assign 'i', got 'REAL'"],
  884. ["IF TRUE THEN FOR i <- 0 TO 10 DO END; i := 1; END", "undeclared identifier: 'i'"]
  885. )
  886. )
  887. },
  888. "type promotion for VAR arguments": testWithContext(
  889. context(grammar.declarationSequence,
  890. "TYPE Base = RECORD END; PBase = POINTER TO Base;"
  891. + "Derived = RECORD (Base) flag: BOOLEAN END; PDerived = POINTER TO Derived;"),
  892. pass("PROCEDURE p(VAR b: Base); BEGIN ASSERT((b IS Derived) & b.flag); END p;"),
  893. fail(["PROCEDURE p(VAR b: PBase); BEGIN ASSERT((b IS PDerived) & b.flag); END p;",
  894. "type 'Base' has no 'flag' field"])
  895. ),
  896. "type promotion for non-VAR arguments": testWithContext(
  897. context(grammar.declarationSequence,
  898. "TYPE Base = RECORD END; PBase = POINTER TO Base;"
  899. + "Derived = RECORD (Base) flag: BOOLEAN END; PDerived = POINTER TO Derived;"),
  900. pass("PROCEDURE p(b: PBase); BEGIN ASSERT((b IS PDerived) & b.flag); END p;")
  901. ),
  902. "Non-VAR arguments cannot be modified": testWithContext(
  903. context(grammar.declarationSequence,
  904. "TYPE PBase = POINTER TO RECORD END; T = RECORD i: INTEGER END;"
  905. + "PROCEDURE pArrayRef(VAR a: ARRAY OF INTEGER); END pArrayRef;"
  906. + "PROCEDURE recordVar(VAR r: T); END recordVar;"),
  907. pass("PROCEDURE p(VAR i: INTEGER); BEGIN i := 0; END p;",
  908. "PROCEDURE p(VAR b: PBase); BEGIN b := NIL; END p;"),
  909. fail(["PROCEDURE p(i: INTEGER); BEGIN i := 0; END p;",
  910. "cannot assign to non-VAR formal parameter"],
  911. ["PROCEDURE p(b: PBase); BEGIN b := NIL; END p;",
  912. "cannot assign to non-VAR formal parameter"],
  913. ["PROCEDURE p(a: ARRAY OF INTEGER); BEGIN pArrayRef(a) END;",
  914. "non-VAR formal parameter cannot be passed as VAR actual parameter"],
  915. ["PROCEDURE p(r: T); BEGIN recordVar(r); END p",
  916. "non-VAR formal parameter cannot be passed as VAR actual parameter"],
  917. ["PROCEDURE p(s1, s2: ARRAY OF CHAR); BEGIN s1 := s2 END p",
  918. "cannot assign to non-VAR formal parameter"],
  919. ["PROCEDURE p(s: ARRAY OF CHAR); BEGIN s := \"abc\" END p",
  920. "cannot assign to non-VAR formal parameter"]
  921. )
  922. ),
  923. "array": {
  924. "static array indexOf": testWithContext(
  925. context(grammar.expression,
  926. "TYPE "
  927. + "T = RECORD END;"
  928. + "VAR "
  929. + "r: T;"
  930. + "intArray: ARRAY 3 OF INTEGER;"
  931. + "boolDynArray: ARRAY * OF BOOLEAN;"
  932. + "recordArray: ARRAY 3 OF T;"
  933. + "arrayOfArray: ARRAY 3, 4 OF INTEGER;"
  934. ),
  935. pass("intArray.indexOf(0)",
  936. "boolDynArray.indexOf(FALSE) = -1"
  937. ),
  938. fail(["intArray.indexOf(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
  939. ["recordArray.indexOf(r)", "'indexOf' is not defined for array of 'T'"],
  940. ["arrayOfArray.indexOf(intArray)", "'indexOf' is not defined for array of 'ARRAY 4 OF INTEGER'"],
  941. ["intArray.indexOf", "array's method 'indexOf' cannot be referenced"]
  942. )
  943. ),
  944. "open array indexOf": testWithGrammar(
  945. grammar.declarationSequence,
  946. pass("PROCEDURE p(a: ARRAY OF INTEGER): INTEGER; RETURN a.indexOf(123) END p;"
  947. )
  948. ),
  949. "dynamic": {
  950. "declaration": testWithContext(
  951. context(grammar.declarationSequence,
  952. "TYPE DA = ARRAY * OF INTEGER;"),
  953. pass("TYPE A = ARRAY * OF INTEGER;",
  954. "TYPE A = ARRAY * OF ARRAY * OF INTEGER;",
  955. "TYPE A = ARRAY *, * OF INTEGER;",
  956. "TYPE A = ARRAY 3, * OF INTEGER;",
  957. "TYPE A = ARRAY *, 3 OF INTEGER;",
  958. "TYPE P = PROCEDURE(): DA;",
  959. "TYPE P = PROCEDURE(VAR a: DA): DA;",
  960. "TYPE P = PROCEDURE(VAR a: ARRAY * OF INTEGER): DA;",
  961. "TYPE T = RECORD a: ARRAY * OF T END;",
  962. "VAR a: ARRAY * OF INTEGER;",
  963. "PROCEDURE p(VAR a: ARRAY * OF INTEGER);END p;",
  964. "PROCEDURE p(VAR a: ARRAY * OF ARRAY * OF INTEGER);END p;",
  965. "PROCEDURE p(VAR a: ARRAY OF ARRAY * OF INTEGER);END p;"
  966. ),
  967. fail(["TYPE A = ARRAY OF INTEGER;", "not parsed"],
  968. ["TYPE P = PROCEDURE(): ARRAY OF INTEGER;", "';' expected"],
  969. ["TYPE P = PROCEDURE(a: DA);", "dynamic array has no use as non-VAR argument 'a'"],
  970. ["TYPE P = PROCEDURE(a: ARRAY * OF INTEGER);", "dynamic array has no use as non-VAR argument 'a'"],
  971. ["PROCEDURE p(a: DA);END p;", "dynamic array has no use as non-VAR argument 'a'"],
  972. ["PROCEDURE p(a: ARRAY * OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"],
  973. ["PROCEDURE p(a: ARRAY OF ARRAY * OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"],
  974. ["PROCEDURE p(a: ARRAY * OF ARRAY OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"]
  975. )
  976. ),
  977. "return": testWithContext(
  978. context(grammar.declarationSequence,
  979. "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
  980. + "VAR a: A; b: B;"),
  981. pass("PROCEDURE p(): A; RETURN a END p;",
  982. "PROCEDURE p(): A; VAR static: ARRAY 3 OF INTEGER; RETURN static END p;"),
  983. fail(["PROCEDURE p(): ARRAY OF INTEGER; RETURN a; END p;", "not parsed"],
  984. ["PROCEDURE p(): A; RETURN b; END p;", "RETURN 'ARRAY * OF INTEGER' expected, got 'ARRAY * OF BOOLEAN'"])
  985. ),
  986. "pass as non-VAR argument": testWithContext(
  987. context(grammar.statement,
  988. "TYPE Int3 = ARRAY 3 OF INTEGER;"
  989. + "VAR dInt: ARRAY * OF INTEGER;"
  990. + "dIntInt: ARRAY *,* OF INTEGER;"
  991. + "PROCEDURE pOpenInt(a: ARRAY OF INTEGER); END pOpenInt;"
  992. + "PROCEDURE pOpenIntOfInt(a: ARRAY OF ARRAY OF INTEGER); END pOpenIntOfInt;"
  993. + "PROCEDURE pInt3(a: Int3); END pInt3;"),
  994. pass("pOpenInt(dInt)",
  995. "pOpenIntOfInt(dIntInt)"),
  996. fail(["pInt3(dInt)", "type mismatch for argument 1: 'ARRAY * OF INTEGER' cannot be converted to 'ARRAY 3 OF INTEGER'"])
  997. ),
  998. "pass as VAR argument": testWithContext(
  999. context(grammar.statement,
  1000. "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
  1001. + "VAR a: A; b: B; aStatic: ARRAY 3 OF INTEGER;"
  1002. + "aIntInt: ARRAY * OF ARRAY * OF INTEGER;"
  1003. + "aInt3Int: ARRAY * OF ARRAY 3 OF INTEGER;"
  1004. + "PROCEDURE paVar(VAR a: A); END paVar;"
  1005. + "PROCEDURE paVarOpen(VAR a: ARRAY OF INTEGER); END paVarOpen;"
  1006. + "PROCEDURE pDynamicIntOfInt(VAR a: ARRAY * OF ARRAY * OF INTEGER); END pDynamicIntOfInt;"
  1007. + "PROCEDURE pDynamicIntOfOpenInt(VAR a: ARRAY * OF ARRAY OF INTEGER); END pDynamicIntOfOpenInt;"
  1008. ),
  1009. pass("paVar(a)",
  1010. "paVarOpen(a)",
  1011. "pDynamicIntOfInt(aIntInt)",
  1012. "pDynamicIntOfOpenInt(aIntInt)",
  1013. "pDynamicIntOfOpenInt(aInt3Int)"
  1014. ),
  1015. fail(["paVar(aStatic)", "type mismatch for argument 1: cannot pass 'ARRAY 3 OF INTEGER' as VAR parameter of type 'ARRAY * OF INTEGER'"],
  1016. ["pDynamicIntOfInt(aInt3Int)", "type mismatch for argument 1: 'ARRAY *, 3 OF INTEGER' cannot be converted to 'ARRAY *, * OF INTEGER'"]
  1017. )
  1018. ),
  1019. "assign": testWithContext(
  1020. context(grammar.statement,
  1021. "VAR stat: ARRAY 3 OF INTEGER; dynamic: ARRAY * OF INTEGER;"),
  1022. pass("dynamic := stat"),
  1023. fail(["stat := dynamic", "type mismatch: 'ARRAY 3 OF INTEGER' cannot be assigned to 'ARRAY * OF INTEGER' expression"],
  1024. ["dynamic := NIL", "type mismatch: 'ARRAY * OF INTEGER' cannot be assigned to 'NIL' expression"])
  1025. ),
  1026. "indexing": testWithContext(
  1027. context(grammar.expression,
  1028. "VAR a: ARRAY * OF INTEGER;"),
  1029. pass("a[0]", "a[1]"),
  1030. fail(["a[-1]", "index is negative: -1"],
  1031. ["a[-2]", "index is negative: -2"])
  1032. ),
  1033. "indexOf": testWithContext(
  1034. context(grammar.expression,
  1035. "VAR intArray: ARRAY * OF INTEGER;"
  1036. ),
  1037. pass("intArray.indexOf(0)"),
  1038. fail()
  1039. ),
  1040. "add": testWithContext(
  1041. context(grammar.statement,
  1042. "VAR a: ARRAY * OF INTEGER;"
  1043. + "a2: ARRAY * OF ARRAY * OF INTEGER;"
  1044. + "aStatic: ARRAY 3 OF INTEGER;"
  1045. + "byte: BYTE;"),
  1046. pass("a.add(123)",
  1047. "a.add(byte)",
  1048. "a2.add(a)",
  1049. "a2.add(aStatic)"
  1050. ),
  1051. fail(["a.add := NIL", "cannot assign to dynamic array's method 'add'"],
  1052. ["v <- a.add", "dynamic array's method 'add' cannot be referenced"],
  1053. ["a.add()", "method 'add' expects one argument, got nothing"],
  1054. ["a.add(1, 2)", "method 'add' expects one argument, got many"],
  1055. ["a.add(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"]
  1056. )
  1057. ),
  1058. "add open array to dynamic array of static arrays": testWithContext(
  1059. context(grammar.declarationSequence,
  1060. "VAR a: ARRAY * OF ARRAY 3 OF INTEGER;"),
  1061. pass(),
  1062. fail(["PROCEDURE p(paramA: ARRAY OF INTEGER); BEGIN a.add(paramA); END p",
  1063. "type mismatch for argument 1: 'ARRAY OF INTEGER' cannot be converted to 'ARRAY 3 OF INTEGER'"]
  1064. )
  1065. ),
  1066. "remove": testWithContext(
  1067. context(grammar.statement,
  1068. "VAR a: ARRAY * OF INTEGER;"),
  1069. pass("a.remove(0)"),
  1070. fail(["a.remove(-1)", "index is negative: -1"],
  1071. ["a.remove()", "1 argument(s) expected, got 0"],
  1072. ["a.remove(0, 1)", "1 argument(s) expected, got 2"],
  1073. ["a.remove(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
  1074. ["a.Remove(0)", "selector '.Remove' cannot be applied to 'ARRAY * OF INTEGER'"]
  1075. )
  1076. ),
  1077. "clear": testWithContext(
  1078. context(grammar.statement,
  1079. "VAR a: ARRAY * OF INTEGER;"),
  1080. pass("a.clear()"),
  1081. fail(["a.clear(0)", "0 argument(s) expected, got 1"])
  1082. ),
  1083. "add, remove and clear cannot be called for read-only array": testWithContext(
  1084. context(grammar.declarationSequence,
  1085. "TYPE T = RECORD a: ARRAY * OF INTEGER; END;"),
  1086. pass("PROCEDURE p(VAR r: T); BEGIN r.a.add(1); END;",
  1087. "PROCEDURE p(VAR r: T); BEGIN r.a.remove(1); END;",
  1088. "PROCEDURE p(VAR r: T); BEGIN r.a.clear(); END;"
  1089. ),
  1090. fail(["PROCEDURE p(r: T); BEGIN r.a.add(1); END;", "method 'add' cannot be applied to non-VAR dynamic array"],
  1091. ["PROCEDURE p(r: T); BEGIN r.a.remove(1); END;", "method 'remove' cannot be applied to non-VAR dynamic array"],
  1092. ["PROCEDURE p(r: T); BEGIN r.a.clear(); END;", "method 'clear' cannot be applied to non-VAR dynamic array"]
  1093. )
  1094. )
  1095. }
  1096. },
  1097. "syntax relaxation": testWithGrammar(
  1098. grammar.declarationSequence,
  1099. pass("PROCEDURE p; END;",
  1100. "TYPE T = RECORD field: INTEGER; END;",
  1101. "TYPE T = RECORD PROCEDURE method(); END;",
  1102. "TYPE T = RECORD PROCEDURE method(); END; PROCEDURE T.method(); END;",
  1103. "PROCEDURE p(): INTEGER; RETURN 0; END;"
  1104. )
  1105. ),
  1106. "constructor": {
  1107. "declaration": testWithGrammar(
  1108. grammar.declarationSequence,
  1109. pass("TYPE T = RECORD PROCEDURE T(); END; PROCEDURE T.T(); END;",
  1110. "TYPE T = RECORD PROCEDURE T(); i: INTEGER; END; PROCEDURE T.T(); BEGIN SELF.i := 0; END;",
  1111. "TYPE T = RECORD PROCEDURE T(); END; PROCEDURE T.T(); END T.T;",
  1112. "TYPE T = RECORD PROCEDURE T(a: INTEGER); END; PROCEDURE T.T(a: INTEGER); END;"
  1113. ),
  1114. fail(["TYPE T = RECORD END; PROCEDURE T(); END;", "'T' already declared"],
  1115. ["TYPE T = RECORD END; PROCEDURE T.T(); END;", "constructor was not declared for 'T'"],
  1116. ["TYPE T = RECORD PROCEDURE T(); END; PROCEDURE T.T(a: INTEGER); END;", "constructor 'T' signature mismatch: declared as 'PROCEDURE' but defined as 'PROCEDURE(INTEGER)'"],
  1117. ["TYPE T = RECORD PROCEDURE T(); PROCEDURE T(); END;", "constructor 'T' already declared"],
  1118. ["TYPE T = RECORD PROCEDURE T(); END; PROCEDURE T.T(); END T;", "mismatched method names: expected 'T.T' at the end (or nothing), got 'T'"],
  1119. ["TYPE T = RECORD PROCEDURE T(); END; PROCEDURE p(); PROCEDURE T.T(); END; END;", "method should be defined in the same scope as its bound type 'T'"],
  1120. ["PROCEDURE p(); TYPE T = RECORD PROCEDURE T(); END; END;", "constructor was declared for 'T' but was not defined"],
  1121. ["TYPE T = RECORD PROCEDURE T(); END; PROCEDURE T.T(); END; PROCEDURE T.T(); END;", "constructor already defined for 'T'"],
  1122. ["TYPE T = RECORD PROCEDURE T(): INTEGER; END;", "constructor 'T' cannot have result type specified"],
  1123. ["TYPE T = ARRAY 3 OF INTEGER; PROCEDURE T(); END;", "'T' already declared"]
  1124. )
  1125. ),
  1126. "as expression": testWithContext(
  1127. context(grammar.expression,
  1128. "TYPE T = RECORD i: INTEGER; END; PT = POINTER TO T; ProcType = PROCEDURE(): INTEGER;"
  1129. + "ConsWithArguments = RECORD PROCEDURE ConsWithArguments(a: INTEGER); END;"
  1130. + "PROCEDURE ConsWithArguments.ConsWithArguments(a: INTEGER); END;"
  1131. + "PROCEDURE byVar(VAR a: T): INTEGER; RETURN 0; END;"
  1132. + "PROCEDURE byNonVar(a: T): INTEGER; RETURN 0; END;"
  1133. ),
  1134. pass("T()",
  1135. "byNonVar(T())",
  1136. "T().i",
  1137. "ConsWithArguments(123)"
  1138. ),
  1139. fail(["ProcType()", "PROCEDURE expected, got 'ProcType'"],
  1140. ["PT()", "PROCEDURE expected, got 'PT'"],
  1141. ["byVar(T())", "expression cannot be used as VAR parameter"],
  1142. ["T(0)", "0 argument(s) expected, got 1"],
  1143. ["ConsWithArguments()", "1 argument(s) expected, got 0"],
  1144. ["ConsWithArguments(FALSE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"]
  1145. )
  1146. ),
  1147. "initialize in place variable": testWithContext(
  1148. context(grammar.statement,
  1149. "TYPE T = RECORD END;"),
  1150. pass("r <- T()"),
  1151. fail()
  1152. ),
  1153. "call base - correct": testWithContext(
  1154. context(grammar.declarationSequence,
  1155. "TYPE T = RECORD PROCEDURE T(a: INTEGER); END;"
  1156. + "Derived = RECORD(T) PROCEDURE Derived(); END;"
  1157. + "PROCEDURE T.T(a: INTEGER); END;"
  1158. ),
  1159. pass("PROCEDURE Derived.Derived() | SUPER(0); END;")
  1160. ),
  1161. "call base - incorrect": testWithContext(
  1162. context(grammar.declarationSequence,
  1163. "TYPE T = RECORD PROCEDURE T(a: INTEGER); END;"
  1164. + "RecordWthoutBase = RECORD END;"
  1165. + "Derived = RECORD(T) PROCEDURE Derived(); END;"
  1166. + "DerivedWthoutConstructor = RECORD(RecordWthoutBase) PROCEDURE DerivedWthoutConstructor(); END;"
  1167. + "RecordWthConstructorNoParameters = RECORD PROCEDURE RecordWthConstructorNoParameters(); END;"
  1168. + "DerivedWthConstructorNoParameters = RECORD(RecordWthConstructorNoParameters) PROCEDURE DerivedWthConstructorNoParameters(); END;"
  1169. + "PROCEDURE T.T(a: INTEGER); END;"
  1170. + "PROCEDURE RecordWthConstructorNoParameters.RecordWthConstructorNoParameters(); END;"
  1171. ),
  1172. pass(),
  1173. fail(["PROCEDURE Derived.Derived(); END;", "base record constructor has parameters but was not called (use '| SUPER' to pass parameters to base constructor)"],
  1174. ["PROCEDURE Derived.Derived() | SUPER(1, 2); END;", "1 argument(s) expected, got 2"],
  1175. ["PROCEDURE Derived.Derived() | SUPER(FALSE); END;", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
  1176. ["PROCEDURE Derived.Derived() | SUPER(); END;", "1 argument(s) expected, got 0"],
  1177. ["PROCEDURE Derived.Derived(); BEGIN SUPER(0); END;", "cannot call base constructor from procedure body (use '| SUPER' to pass parameters to base constructor)"],
  1178. ["PROCEDURE RecordWthoutBase.RecordWthConstructorNoParametersthoutBase() | SUPER(0); END;", "'RecordWthoutBase' has no base type - SUPER cannot be used"],
  1179. ["PROCEDURE DerivedWthoutConstructor.DerivedWthoutConstructor() | SUPER(); END;", "base record constructor has no parameters and will be called automatically (do not use '| SUPER' to call base constructor)"],
  1180. ["PROCEDURE DerivedWthConstructorNoParameters.DerivedWthConstructorNoParameters() | SUPER(); END;", "base record constructor has no parameters and will be called automatically (do not use '| SUPER' to call base constructor)"]
  1181. )
  1182. ),
  1183. "initialize fields (of non record type)": testWithContext(
  1184. context(grammar.declarationSequence,
  1185. "TYPE T = RECORD PROCEDURE T(); i: INTEGER; END;"),
  1186. pass("PROCEDURE T.T() | i(123); END;"),
  1187. fail(["PROCEDURE T.T() | i(); END;", "single argument expected to initialize field 'i'"],
  1188. ["PROCEDURE T.T() | i(123, 456); END;", "single argument expected to initialize field 'i'"],
  1189. ["PROCEDURE T.T() | i(TRUE); END;",
  1190. "type mismatch: field 'i' is 'INTEGER' and cannot be initialized using 'BOOLEAN' expression"]
  1191. )
  1192. ),
  1193. "initialize array fields": testWithContext(
  1194. context(grammar.declarationSequence,
  1195. "TYPE RecordWithArray = RECORD PROCEDURE RecordWithArray(a: ARRAY OF INTEGER); aStatic: ARRAY 3 OF INTEGER; aDynamic: ARRAY * OF INTEGER; END;"
  1196. ),
  1197. pass("PROCEDURE RecordWithArray.RecordWithArray(a: ARRAY OF INTEGER) | aDynamic(a); END;"),
  1198. fail(["PROCEDURE RecordWithArray.RecordWithArray(a: ARRAY OF INTEGER) | aStatic(a); END;",
  1199. "type mismatch: field 'aStatic' is 'ARRAY 3 OF INTEGER' and cannot be initialized using 'ARRAY OF INTEGER' expression"]
  1200. )
  1201. ),
  1202. "initialize fields (of record type)": testWithContext(
  1203. context(grammar.declarationSequence,
  1204. "TYPE Field = RECORD PROCEDURE Field(a: INTEGER); END;"
  1205. + "PROCEDURE Field.Field(a: INTEGER); END;"),
  1206. pass("TYPE T = RECORD PROCEDURE T(); f: Field; END; PROCEDURE T.T() | f(123); END;"),
  1207. fail(["TYPE T = RECORD PROCEDURE T(); f: Field; END; PROCEDURE T.T(); END;",
  1208. "constructor 'T' must initialize fields: f"],
  1209. ["TYPE T = RECORD PROCEDURE T(); END; PROCEDURE T.T() | unknownField(123); END;",
  1210. "'unknownField' is not record 'T' own field"],
  1211. ["TYPE T = RECORD f: Field; END; Derived = RECORD(T) PROCEDURE Derived(); END; PROCEDURE Derived.Derived() | f(123); END;",
  1212. "'f' is not record 'Derived' own field"],
  1213. ["TYPE T = RECORD PROCEDURE T(); f: Field; END; PROCEDURE T.T() | f(123), f(123); END;",
  1214. "field 'f' is already initialized"]
  1215. )
  1216. ),
  1217. "initialize fields using SELF": testWithContext(
  1218. context(grammar.declarationSequence,
  1219. "TYPE T = RECORD PROCEDURE T(); i1, i2: INTEGER; END;"
  1220. ),
  1221. pass("PROCEDURE T.T() | i2(SELF.i1); END;"),
  1222. fail()
  1223. ),
  1224. "call base and initialize fields": testWithContext(
  1225. context(grammar.declarationSequence,
  1226. "TYPE Field = RECORD PROCEDURE Field(a: INTEGER); END;"
  1227. + "T = RECORD PROCEDURE T(a: INTEGER); END;"
  1228. + "Derived = RECORD(T) PROCEDURE Derived(); f: Field; END;"
  1229. + "PROCEDURE Field.Field(a: INTEGER); END;"
  1230. + "PROCEDURE T.T(a: INTEGER); END;"
  1231. ),
  1232. pass("PROCEDURE Derived.Derived() | SUPER(123), f(456); END;"),
  1233. fail(["PROCEDURE Derived.Derived() | f(456), SUPER(123); END;", "not parsed"])
  1234. ),
  1235. "fields initialization order": testWithContext(
  1236. context(grammar.declarationSequence,
  1237. "TYPE Field = RECORD PROCEDURE Field(a: INTEGER); END;"
  1238. + "T = RECORD PROCEDURE T(); f1: Field; f2, f3: Field; END;"
  1239. + "PROCEDURE Field.Field(a: INTEGER); END;"
  1240. ),
  1241. pass("PROCEDURE T.T() | f1(1), f2(2), f3(3); END;"),
  1242. fail(["PROCEDURE T.T() | f2(2), f1(1), f3(3); END;", "field 'f1' must be initialized before 'f2'"],
  1243. ["PROCEDURE T.T() | f1(1), f3(3), f2(2); END;", "field 'f2' must be initialized before 'f3'"]
  1244. )
  1245. ),
  1246. "fields with constructor but record without constructor": testWithContext(
  1247. context(grammar.declarationSequence,
  1248. "TYPE Field = RECORD PROCEDURE Field(a: INTEGER); END;"
  1249. + "PROCEDURE Field.Field(a: INTEGER); END;"
  1250. ),
  1251. pass(),
  1252. fail(["TYPE T = RECORD f: Field; END;", "constructor 'T' must initialize fields: f"])
  1253. ),
  1254. "inherit constructor parameters": testWithContext(
  1255. context(grammar.expression,
  1256. "TYPE Base = RECORD PROCEDURE Base(i: INTEGER); END;"
  1257. + "Derived = RECORD(Base) END;"
  1258. + "PROCEDURE Base.Base(a: INTEGER); END;"
  1259. ),
  1260. pass("Derived(123)"),
  1261. fail(["Derived()", "1 argument(s) expected, got 0"])
  1262. ),
  1263. "ARRAY OF record with constructor": testWithContext(
  1264. context(grammar.declarationSequence,
  1265. "TYPE NoParams = RECORD PROCEDURE NoParams(); END;"
  1266. + "WithParams = RECORD PROCEDURE WithParams(i: INTEGER); END;"
  1267. + "PROCEDURE NoParams.NoParams(); END;"
  1268. + "PROCEDURE WithParams.WithParams(i: INTEGER); END;"
  1269. ),
  1270. pass("TYPE T = ARRAY * OF NoParams;",
  1271. "TYPE T = ARRAY 3 OF NoParams;",
  1272. "TYPE T = ARRAY * OF WithParams;",
  1273. "VAR a: ARRAY 3 OF NoParams;",
  1274. "VAR a: ARRAY * OF WithParams;",
  1275. "PROCEDURE p(); VAR a: ARRAY * OF WithParams; BEGIN a.add(WithParams(123)); END;"
  1276. ),
  1277. fail(["TYPE T = ARRAY 3 OF WithParams;", "cannot use 'WithParams' as an element of static array because it has constructor with parameters"],
  1278. ["VAR a: ARRAY 3 OF WithParams;", "cannot use 'WithParams' as an element of static array because it has constructor with parameters"]
  1279. )
  1280. ),
  1281. "NEW": testWithContext(
  1282. context(grammar.statement,
  1283. "TYPE WithParams = RECORD PROCEDURE WithParams(i: INTEGER); END;"
  1284. + "DerivedWithParams = RECORD(WithParams) END;"
  1285. + "VAR p: POINTER TO WithParams; pd: POINTER TO DerivedWithParams;"
  1286. + "PROCEDURE WithParams.WithParams(i: INTEGER); END;"
  1287. ),
  1288. pass(),
  1289. fail(["NEW(p)", "cannot use procedure NEW for 'WithParams' because it has constructor with parameters, use operator NEW instead"],
  1290. ["NEW(pd)", "cannot use procedure NEW for 'DerivedWithParams' because it has constructor with parameters, use operator NEW instead"]
  1291. )
  1292. ),
  1293. "export": testWithModule(
  1294. "MODULE test;"
  1295. + "TYPE Exported* = RECORD PROCEDURE Exported*(); END;"
  1296. + "NotExported* = RECORD PROCEDURE NotExported(); END;"
  1297. + "DerivedNotExportedWithoutConstructor* = RECORD (NotExported) END;"
  1298. + "NoConstructor* = RECORD END;"
  1299. + "PROCEDURE Exported.Exported(); END;"
  1300. + "PROCEDURE NotExported.NotExported(); END;"
  1301. + "END test.",
  1302. pass("MODULE m; IMPORT test; VAR r: test.Exported; p: POINTER TO test.Exported; BEGIN p := NEW test.Exported(); NEW(p); END m.",
  1303. "MODULE m; IMPORT test; TYPE T = RECORD(test.Exported) END; END m.",
  1304. "MODULE m; IMPORT test; TYPE T = RECORD(test.NoConstructor) END; END m.",
  1305. "MODULE m; IMPORT test; TYPE T = RECORD(test.DerivedNotExportedWithoutConstructor) END; END m.",
  1306. "MODULE m; IMPORT test; PROCEDURE p(r: test.NotExported); BEGIN copy <- r; END; END m."
  1307. ),
  1308. fail(["MODULE m; TYPE T = RECORD PROCEDURE T*(); END; END m.",
  1309. "constructor 'T' cannot be exported because record itslef is not exported"],
  1310. ["MODULE m; IMPORT test; TYPE T = RECORD(test.NotExported) END; END m.",
  1311. "cannot extend 'NotExported' - its constructor was not exported"],
  1312. ["MODULE m; IMPORT test; VAR r: test.NotExported; END m.",
  1313. "cannot instantiate 'NotExported' - its constructor was not exported"],
  1314. ["MODULE m; IMPORT test; VAR p: POINTER TO test.NotExported; BEGIN NEW(p); END m.",
  1315. "cannot instantiate 'NotExported' - its constructor was not exported"],
  1316. ["MODULE m; IMPORT test; VAR p: POINTER TO test.NotExported; BEGIN p := NEW test.NotExported(); END m.",
  1317. "cannot instantiate 'NotExported' - its constructor was not exported"],
  1318. ["MODULE m; IMPORT test; VAR a: ARRAY 3 OF test.NotExported; END m.",
  1319. "cannot instantiate 'NotExported' - its constructor was not exported"]
  1320. )
  1321. )
  1322. },
  1323. "operator NEW": testWithContext(
  1324. context(grammar.expression,
  1325. "TYPE T = RECORD field: INTEGER; END; Proc = PROCEDURE();"
  1326. + "ParamCons = RECORD PROCEDURE ParamCons(i: INTEGER); END;"
  1327. + "Abstract = RECORD PROCEDURE abstract(); END;"
  1328. + "PROCEDURE ParamCons.ParamCons(i: INTEGER); END;"
  1329. + "PROCEDURE proc(); END;"
  1330. ),
  1331. pass("NEW T()",
  1332. "NEW ParamCons(123)",
  1333. "NEW T().field",
  1334. "NEW T()^"
  1335. ),
  1336. fail(["NEW INTEGER()", "record type is expected in operator NEW, got 'INTEGER'"],
  1337. ["NEW proc()", "record type is expected in operator NEW, got 'procedure 'proc''"],
  1338. ["NEW Proc()", "record type is expected in operator NEW, got 'Proc'"],
  1339. ["NEW T().unknownField", "type 'T' has no 'unknownField' field"],
  1340. ["NEW T(123)", "0 argument(s) expected, got 1"],
  1341. ["NEW Abstract()", "cannot instantiate 'Abstract' because it has abstract method(s): abstract"],
  1342. ["NEW undeclared()", "undeclared identifier: 'undeclared'"]
  1343. )
  1344. ),
  1345. "FOR IN": {
  1346. "array": testWithContext(
  1347. context(grammar.statement,
  1348. "VAR a: ARRAY 3 OF BOOLEAN;"),
  1349. pass("FOR i, v IN a DO END",
  1350. "FOR i, v IN a DO ASSERT(a[i] = v); END",
  1351. "FOR v IN a DO END",
  1352. "FOR v IN a DO ASSERT(~v) END"),
  1353. fail()
  1354. ),
  1355. "string": testWithContext(
  1356. context(grammar.statement,
  1357. "CONST cc = 22X; cs = \"abc\";"
  1358. + "VAR s: STRING; as: ARRAY 3 OF CHAR;"),
  1359. pass("FOR c IN s DO END",
  1360. "FOR c IN cc DO END",
  1361. "FOR c IN cs DO END",
  1362. "FOR c IN as DO END",
  1363. "FOR c IN \"abc\" DO END",
  1364. "FOR c IN 22X DO END"
  1365. ),
  1366. fail(["FOR c IN as DO c := 22X; END", "cannot assign to FOR variable"])
  1367. ),
  1368. "map": testWithContext(
  1369. context(grammar.statement,
  1370. "TYPE T = RECORD END;"
  1371. + "VAR m: MAP OF INTEGER; r: T;"),
  1372. pass("FOR k, v IN m DO END",
  1373. "FOR k, v IN m DO ASSERT(k # \"abc\"); END",
  1374. "FOR k, v IN m DO ASSERT(v # 123); END"
  1375. ),
  1376. fail(["FOR k, k IN m DO END", "'k' already declared"],
  1377. ["FOR m, v IN m DO END", "'m' already declared in module scope"],
  1378. ["FOR k, m IN m DO END", "'m' already declared in module scope"],
  1379. ["FOR k, v IN m DO k := \"\"; END", "cannot assign to FOR variable"],
  1380. ["FOR k, v IN m DO v := 0; END", "cannot assign to FOR variable"],
  1381. ["FOR k, v IN r DO END", "expression of type ARRAY, STRING or MAP is expected in FOR, got 'T'"],
  1382. ["FOR k, v IN T DO END", "type name 'T' cannot be used as an expression"]
  1383. )
  1384. ),
  1385. "scope": testWithContext(
  1386. context(grammar.declarationSequence,
  1387. "VAR m: MAP OF INTEGER;"),
  1388. pass(),
  1389. fail(["PROCEDURE p(); BEGIN FOR k, v IN m DO END; ASSERT(k # \"abc\"); END;", "undeclared identifier: 'k'"],
  1390. ["PROCEDURE p(); BEGIN FOR k, v IN m DO END; ASSERT(v # 123); END;", "undeclared identifier: 'v'"]
  1391. )
  1392. )
  1393. },
  1394. "map": {
  1395. "declaration": testWithGrammar(
  1396. grammar.declarationSequence,
  1397. pass("TYPE M = MAP OF INTEGER;",
  1398. "TYPE M = MAP OF PROCEDURE;",
  1399. "TYPE M = MAP OF PROCEDURE();",
  1400. "TYPE M = MAP OF PROCEDURE(): INTEGER;",
  1401. "TYPE M = MAP OF PROCEDURE(): M;",
  1402. "TYPE M = MAP OF RECORD END;",
  1403. "TYPE M = MAP OF POINTER TO RECORD END;",
  1404. "TYPE M = MAP OF MAP OF INTEGER;",
  1405. "TYPE M = MAP OF ARRAY * OF INTEGER;",
  1406. "TYPE M = MAP OF M;",
  1407. "TYPE T = RECORD field: MAP OF T; END;",
  1408. "VAR v: MAP OF SET;"
  1409. ),
  1410. fail(["TYPE P = POINTER TO MAP OF INTEGER;", "RECORD is expected as a POINTER base type, got 'MAP OF INTEGER'"],
  1411. ["TYPE M = MAP OF Undeclared;", "undeclared identifier: 'Undeclared'"],
  1412. ["VAR MAP: INTEGER;", "not parsed"]
  1413. )
  1414. ),
  1415. "assign": testWithContext(
  1416. context(grammar.statement,
  1417. "TYPE MapOfInteger = MAP OF INTEGER;"
  1418. + "VAR mapOfInteger1: MapOfInteger; mapOfInteger2: MAP OF INTEGER;"
  1419. + "mapOfString: MAP OF STRING;"),
  1420. pass("mapOfInteger1 := mapOfInteger2"),
  1421. fail(["mapOfInteger1 := mapOfString", "type mismatch: 'MAP OF INTEGER' cannot be assigned to 'MAP OF STRING' expression"])
  1422. ),
  1423. "put": testWithContext(
  1424. context(grammar.statement,
  1425. "VAR m: MAP OF INTEGER;"
  1426. + "sIndex: STRING; aIndex: ARRAY 3 OF CHAR;"),
  1427. pass("m[\"abc\"] := 123",
  1428. "m[sIndex] := 123",
  1429. "m[aIndex] := 123"
  1430. ),
  1431. fail(["m[123] := 123", "invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
  1432. ),
  1433. "get": testWithContext(
  1434. context(grammar.expression,
  1435. "VAR m: MAP OF INTEGER;"
  1436. + "sIndex: STRING; aIndex: ARRAY 3 OF CHAR;"),
  1437. pass("m[\"abc\"]",
  1438. "m[sIndex]",
  1439. "m[aIndex]"
  1440. ),
  1441. fail(["m[123]", "invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
  1442. ),
  1443. "get and pass as VAR": testWithContext(
  1444. context(grammar.statement,
  1445. "TYPE T = RECORD END;"
  1446. + "VAR mInt: MAP OF INTEGER;"
  1447. + " mS: MAP OF STRING;"
  1448. + " mR: MAP OF T;"
  1449. + "PROCEDURE intByRef(VAR i: INTEGER); END;"
  1450. + "PROCEDURE stringByRef(VAR s: STRING); END;"
  1451. + "PROCEDURE recordByRef(VAR r: T); END;"
  1452. ),
  1453. pass("recordByRef(mR[\"a\"])"),
  1454. fail(["intByRef(mInt[\"a\"])", "cannot reference MAP's element of type 'INTEGER'"],
  1455. ["stringByRef(mS[\"a\"])", "cannot reference MAP's element of type 'STRING'"]
  1456. )
  1457. ),
  1458. "IN": testWithContext(
  1459. context(grammar.expression,
  1460. "VAR m: MAP OF INTEGER;"
  1461. + "sIndex: STRING; aIndex: ARRAY 3 OF CHAR;"),
  1462. pass("\"abc\" IN m",
  1463. "(\"abc\" IN m) = FALSE",
  1464. "sIndex IN m",
  1465. "aIndex IN m"
  1466. ),
  1467. fail(["123 IN m", "invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
  1468. ),
  1469. "non-VAR parameter": testWithContext(
  1470. context(grammar.declarationSequence,
  1471. "TYPE M = MAP OF INTEGER;"),
  1472. pass(),
  1473. fail(["PROCEDURE p(m: M); BEGIN m[\"abc\"] := 123; END;", "cannot assign to read-only MAP's element of type 'INTEGER'"])
  1474. ),
  1475. "remove": testWithContext(
  1476. context(grammar.statement,
  1477. "VAR m: MAP OF INTEGER; a: ARRAY * OF CHAR;"),
  1478. pass("m.remove(\"abc\")",
  1479. "m.remove(a)"),
  1480. fail(["m.remove(123)", "type mismatch for argument 1: 'INTEGER' cannot be converted to 'ARRAY OF CHAR'"],
  1481. ["m.remove()", "1 argument(s) expected, got 0"],
  1482. ["m.remove(\"abc\", \"abc\")", "1 argument(s) expected, got 2"],
  1483. ["v <- m.remove", "MAP's method 'remove' cannot be referenced"]
  1484. )
  1485. ),
  1486. "clear": testWithContext(
  1487. context(grammar.statement,
  1488. "VAR m: MAP OF INTEGER;"),
  1489. pass("m.clear()", "m.clear"),
  1490. fail(["m.clear(123)", "0 argument(s) expected, got 1"]
  1491. )
  1492. ),
  1493. "clear and remove cannot be applied to read only map": testWithContext(
  1494. context(grammar.declarationSequence,
  1495. "TYPE M = MAP OF INTEGER;"),
  1496. pass("PROCEDURE p(VAR m: M); BEGIN; m.remove(\"abc\"); END;",
  1497. "PROCEDURE p(VAR m: M); BEGIN; m.clear(); END;"),
  1498. fail(["PROCEDURE p(m: M); BEGIN; m.remove(\"abc\"); END;", "method 'remove' cannot be applied to non-VAR MAP"],
  1499. ["PROCEDURE p(m: M); BEGIN; m.clear(); END;", "method 'clear' cannot be applied to non-VAR MAP"]
  1500. )
  1501. ),
  1502. "return": testWithContext(
  1503. context(grammar.declarationSequence,
  1504. "TYPE M = MAP OF INTEGER;"),
  1505. pass("PROCEDURE p(): M; VAR m: M; BEGIN; RETURN m; END;")
  1506. )
  1507. },
  1508. "ternary operator": testWithContext(
  1509. context(grammar.expression,
  1510. "TYPE Base = RECORD END; PBase = POINTER TO Base;"
  1511. + "Derived = RECORD(Base) END; PDerived = POINTER TO Derived;"
  1512. + "Derived2 = RECORD(Base) END; Derived3 = RECORD(Base) END;"
  1513. + "VAR b: BOOLEAN; i1, i2: INTEGER; s: STRING; byte: BYTE;"
  1514. + "rb: Base; rd: Derived; rd2: Derived2; rd3: Derived3;"
  1515. + "pb: PBase; pd: POINTER TO Derived; pd2: POINTER TO Derived2; pd3: POINTER TO Derived3;"
  1516. + "PROCEDURE passBase(b: Base): BOOLEAN; RETURN TRUE END;"
  1517. + "PROCEDURE passDerived(d: Derived): BOOLEAN; RETURN TRUE END;"
  1518. + "PROCEDURE passPBase(p: PBase): BOOLEAN; RETURN TRUE END;"
  1519. + "PROCEDURE passPDerived(p: PDerived): BOOLEAN; RETURN TRUE END;"
  1520. + "PROCEDURE passRef(VAR i: INTEGER): BOOLEAN; RETURN TRUE END;"
  1521. ),
  1522. pass("b ? i1 : i2",
  1523. "(b ? i1 : i2) # 0",
  1524. "FLT(b ? i1 : i2)",
  1525. "b ? i1 : byte",
  1526. "b ? byte : i1",
  1527. "b ? \"abc\" : \"de\"",
  1528. "b ? s : \"de\"",
  1529. "b ? \"abc\" : s",
  1530. "b ? pb : pd",
  1531. "b ? pd : pb",
  1532. "b ? pb : NIL",
  1533. "b ? NIL : pb",
  1534. "passBase(b ? pb^ : pd^)",
  1535. "passBase(b ? pd^ : pb^)",
  1536. "passBase(b ? pd2^ : pd3^)",
  1537. "passBase(b ? rb : rd)",
  1538. "passBase(b ? rd : rb)",
  1539. "passBase(b ? rd2 : rd3)",
  1540. "b ? i1 : b ? i1 : i2",
  1541. "passPBase(b ? pb : pd)",
  1542. "passPBase(b ? pd : pb)",
  1543. "passPBase(b ? pb : NIL)",
  1544. "passPBase(b ? NIL : pb)"
  1545. ),
  1546. fail(["b ?", "not parsed"],
  1547. ["b ? i1", "expected \":\" after \"?\" in ternary operator"],
  1548. ["b ? i1 :", "expression is expected after \":\" in ternary operator"],
  1549. ["b ? i1 : s", "incompatible types in ternary operator: 'INTEGER' and 'STRING'"],
  1550. ["passBase(b ? pb^ : pd)", "incompatible types in ternary operator: 'Base' and 'POINTER TO Derived'"],
  1551. ["passDerived(b ? pb : pd)", "type mismatch for argument 1: 'POINTER TO Base' cannot be converted to 'Derived'"],
  1552. ["passDerived(b ? pd : pb)", "type mismatch for argument 1: 'POINTER TO Base' cannot be converted to 'Derived'"],
  1553. ["b ? b ? i1 : i2 : i1", "expected \":\" after \"?\" in ternary operator"],
  1554. ["b ? rb : NIL", "incompatible types in ternary operator: 'Base' and 'NIL'"],
  1555. ["b ? NIL : NIL", "cannot use 'NIL' as a result of ternary operator"],
  1556. ["passPDerived(b ? NIL : pb)", "type mismatch for argument 1: 'PBase' cannot be converted to 'PDerived'"],
  1557. ["passPDerived(b ? pb : NIL)", "type mismatch for argument 1: 'PBase' cannot be converted to 'PDerived'"],
  1558. ["passRef(b ? i1 : i2)", "ternary operator result cannot be passed as VAR actual parameter"]
  1559. )
  1560. ),
  1561. "array expression": testWithGrammar(
  1562. grammar.expression,
  1563. pass("[1]",
  1564. "[1, 2]",
  1565. "[FALSE, TRUE]"
  1566. ),
  1567. fail(["[]", "not parsed"],
  1568. ["[1, TRUE]", "array's elements should have the same type: expected 'INTEGER', got 'BOOLEAN'"],
  1569. ["[NIL]", "cannot use NIL to initialize array's element"],
  1570. ["[1, NIL]", "cannot use NIL to initialize array's element"]
  1571. )
  1572. ),
  1573. "CONST array": testWithGrammar(
  1574. grammar.declarationSequence,
  1575. pass("CONST a = [1];",
  1576. "CONST a = [1, 2];",
  1577. "CONST a = [FALSE, TRUE];"
  1578. )
  1579. ),
  1580. "CONST array pass to procedure": testWithContext(
  1581. context(grammar.expression,
  1582. "CONST a = [1, 2, 3];"
  1583. + "PROCEDURE intArray(a: ARRAY OF INTEGER): BOOLEAN; RETURN FALSE; END;"
  1584. + "PROCEDURE intVarArray(VAR a: ARRAY OF INTEGER): BOOLEAN; RETURN FALSE; END;"
  1585. + "PROCEDURE charArray(a: ARRAY OF CHAR): BOOLEAN; RETURN FALSE; END;"
  1586. ),
  1587. pass("intArray(a)"
  1588. ),
  1589. fail(["intVarArray(a)", "constant cannot be passed as VAR actual parameter"],
  1590. ["charArray(a)", "type mismatch for argument 1: 'ARRAY 3 OF INTEGER' cannot be converted to 'ARRAY OF CHAR'"])
  1591. ),
  1592. "CONST array with string literals": testWithContext(
  1593. context(grammar.expression,
  1594. "CONST a = [\"a\", \"bc\", \"d\"];"
  1595. + "PROCEDURE stringArray(a: ARRAY OF STRING): BOOLEAN; RETURN FALSE; END;"
  1596. ),
  1597. pass("stringArray(a)")
  1598. )
  1599. };