test_unit_eberon.js 79 KB

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