test_unit_eberon.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. "use strict";
  2. var Class = require("rtl.js").Class;
  3. var language = require("eberon/eberon_grammar.js").language;
  4. var TestUnitCommon = require("test_unit_common.js");
  5. var TypePromotion = require("eberon/eberon_type_promotion.js");
  6. var assert = TestUnitCommon.assert;
  7. var pass = TestUnitCommon.pass;
  8. var fail = TestUnitCommon.fail;
  9. var context = TestUnitCommon.context;
  10. var grammar = language.grammar;
  11. function testWithContext(context, pass, fail){
  12. return TestUnitCommon.testWithContext(context, grammar.declarationSequence, language, pass, fail);
  13. }
  14. function testWithModule(src, pass, fail){
  15. return TestUnitCommon.testWithModule(src, language, pass, fail);
  16. }
  17. function testWithGrammar(parser, pass, faile){
  18. return TestUnitCommon.testWithGrammar(parser, language, pass, fail);
  19. }
  20. var temporaryValues = {
  21. context: context(
  22. grammar.declarationSequence,
  23. "TYPE Base = RECORD END;"
  24. + "Derived = RECORD (Base) flag: BOOLEAN END;"
  25. + "Derived2 = RECORD (Derived) flag2: BOOLEAN END;"
  26. + "PBase = POINTER TO Base;"
  27. + "PDerived = POINTER TO Derived;"
  28. + "PDerived2 = POINTER TO Derived2;"
  29. + "VAR pBase: POINTER TO Base; bVar: BOOLEAN;"
  30. + "PROCEDURE proc(b: BOOLEAN): BOOLEAN; RETURN b END proc;"),
  31. __expression: function(e){
  32. return "PROCEDURE p(); BEGIN b <- pBase; b2 <- pBase; ASSERT(" + e + "); END p;";
  33. },
  34. __statement: function(e){
  35. return "PROCEDURE p(); BEGIN b <- pBase; b2 <- pBase; " + e + " END p;";
  36. },
  37. passExpressions: function(){
  38. return this.__pass(this.__expression.bind(this), arguments);
  39. },
  40. passStatements: function(){
  41. return this.__pass(this.__statement.bind(this), arguments);
  42. },
  43. failExpressions: function(){
  44. return this.__fail(this.__expression.bind(this), arguments);
  45. },
  46. failStatements: function(){
  47. return this.__fail(this.__statement.bind(this), arguments);
  48. },
  49. __pass: function(make, cases){
  50. var result = [];
  51. for(var i = 0; i < cases.length; ++i)
  52. result.push(make(cases[i]));
  53. return pass.apply(this, result);
  54. },
  55. __fail: function(make, cases){
  56. var result = [];
  57. for(var i = 0; i < cases.length; ++i)
  58. result.push([make(cases[i]), "type 'Base' has no 'flag' field"]);
  59. return fail.apply(this, result);
  60. }
  61. };
  62. var TestVar = Class.extend({
  63. init: function(){
  64. this.__type = "type";
  65. },
  66. type: function(){return this.__type;},
  67. setType: function(type){this.__type = type;}
  68. });
  69. exports.suite = {
  70. "arithmetic operators": testWithContext(
  71. context(grammar.statement, "VAR b1: BOOLEAN;"),
  72. pass(),
  73. fail(["b1 := b1 + b1", "operator '+' type mismatch: numeric type or SET or STRING expected, got 'BOOLEAN'"])
  74. ),
  75. "key words": testWithGrammar(
  76. grammar.variableDeclaration,
  77. pass(),
  78. fail(["SELF: INTEGER", "not parsed"],
  79. ["SUPER: INTEGER", "not parsed"],
  80. ["STRING: INTEGER", "not parsed"]
  81. )
  82. ),
  83. "abstract method declaration": testWithContext(
  84. context(grammar.declarationSequence,
  85. "TYPE T = RECORD PROCEDURE p() END;"
  86. + "D = RECORD(T) END;"
  87. + "T2 = RECORD PROCEDURE p1(); PROCEDURE p2(i: INTEGER): BOOLEAN END;"
  88. ),
  89. pass(),
  90. fail(["VAR r: T;",
  91. "cannot instantiate 'T' because it has abstract method(s): p"],
  92. ["VAR r: T2;",
  93. "cannot instantiate 'T2' because it has abstract method(s): p1, p2"],
  94. ["PROCEDURE p(); VAR p: POINTER TO T; BEGIN NEW(p); END p;",
  95. "cannot instantiate 'T' because it has abstract method(s): p"],
  96. ["PROCEDURE p(); TYPE LocalT = RECORD(T) END; VAR r: LocalT; END p;",
  97. "cannot instantiate 'LocalT' because it has abstract method(s): p"],
  98. ["PROCEDURE p(); TYPE LocalT = RECORD(T) END; VAR p: POINTER TO LocalT; BEGIN NEW(p) END p;",
  99. "cannot instantiate 'LocalT' because it has abstract method(s): p"],
  100. ["VAR r: D;",
  101. "cannot instantiate 'D' because it has abstract method(s): p"],
  102. ["PROCEDURE p(); VAR p: POINTER TO D; BEGIN NEW(p); END p;",
  103. "cannot instantiate 'D' because it has abstract method(s): p"]
  104. )
  105. ),
  106. "new method declaration": testWithContext(
  107. context(grammar.declarationSequence,
  108. "TYPE T = RECORD PROCEDURE p(); intField: INTEGER END; A = ARRAY 1 OF INTEGER;"),
  109. pass("PROCEDURE T.p(); END T.p;"
  110. ),
  111. fail(["PROCEDURE TUnk.p(), NEW; END TUnk.p;", "undeclared identifier: 'TUnk'"],
  112. ["PROCEDURE A.p(), NEW; END A.p;",
  113. "RECORD type expected in method declaration, got 'ARRAY 1 OF INTEGER'"],
  114. ["PROCEDURE T.p(), NEW; END;", "not parsed"],
  115. ["PROCEDURE T.p(); END p;",
  116. "mismatched procedure names: 'T.p' at the begining and 'p.' at the end"],
  117. ["PROCEDURE T.p(); END T2.p;",
  118. "mismatched procedure names: 'T.p' at the begining and 'T2.p' at the end"],
  119. ["PROCEDURE T.p(); END T.p2;",
  120. "mismatched procedure names: 'T.p' at the begining and 'T.p2' at the end"],
  121. ["PROCEDURE T.intField(); END T.intField;",
  122. "'T' has no declaration for method 'intField'"],
  123. ["PROCEDURE T.p(); END T.p; PROCEDURE T.p(), NEW; END T.p;",
  124. "'T.p' already declared"],
  125. ["PROCEDURE p(); TYPE T = RECORD PROCEDURE m(); PROCEDURE m() END; END p;",
  126. "cannot declare a new method 'm': method already was declared"],
  127. ["PROCEDURE p(); TYPE T = RECORD m: INTEGER; PROCEDURE m() END; END p;",
  128. "cannot declare method, record already has field 'm'"],
  129. ["PROCEDURE p(); TYPE T = RECORD PROCEDURE m(); m: INTEGER END; END p;",
  130. "cannot declare field, record already has method 'm'"]
  131. )
  132. ),
  133. "overridden method declaration": testWithContext(
  134. context(grammar.declarationSequence,
  135. "TYPE Base = RECORD PROCEDURE p() END; T = RECORD (Base) END;"
  136. + "PROCEDURE Base.p(); END Base.p;"),
  137. pass("PROCEDURE T.p(); END T.p;"),
  138. fail(["PROCEDURE T.pUnk(); END T.pUnk;",
  139. "'T' has no declaration for method 'pUnk'"],
  140. ["PROCEDURE proc(); TYPE T = RECORD (Base) PROCEDURE p() END; END proc;",
  141. "cannot declare a new method 'p': method already was declared"],
  142. ["PROCEDURE T.p(); END T.p; PROCEDURE T.p(); END T.p;",
  143. "'T.p' already declared"],
  144. ["PROCEDURE T.p(a: INTEGER); END T.p;",
  145. "overridden method 'p' signature mismatch: should be 'PROCEDURE', got 'PROCEDURE(INTEGER)'"],
  146. ["PROCEDURE p(); PROCEDURE T.p(); END T.p; END p;",
  147. "method should be defined in the same scope as its bound type 'T'"]
  148. )
  149. ),
  150. "SELF": testWithContext(
  151. context(grammar.declarationSequence,
  152. "TYPE T = RECORD PROCEDURE p(); i: INTEGER END;"
  153. + "PROCEDURE proc(i: INTEGER); END proc;"),
  154. pass("PROCEDURE T.p(); BEGIN SELF.i := 0; END T.p;",
  155. "PROCEDURE T.p(); BEGIN proc(SELF.i); END T.p;"
  156. ),
  157. fail(["PROCEDURE p(); BEGIN SELF.i := 0; END p;",
  158. "SELF can be used only in methods"])
  159. ),
  160. "SELF as pointer": testWithContext(
  161. context(grammar.declarationSequence,
  162. "TYPE T = RECORD PROCEDURE method() END;"
  163. + "PT = POINTER TO T;"
  164. + "VAR pVar: PT;"
  165. + "PROCEDURE refProc(VAR p: PT); END refProc;"
  166. ),
  167. pass("PROCEDURE T.method(); BEGIN pVar := SELF(POINTER) END T.method;",
  168. "PROCEDURE p();"
  169. + "TYPE Derived = RECORD(T) END; VAR pd: POINTER TO Derived;"
  170. + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN NEW(pd); pVar := SELF(POINTER); END Derived.method;"
  171. + "END p;"),
  172. fail(["PROCEDURE T.method(); BEGIN refProc(SELF(POINTER)) END T.method;",
  173. "read-only variable cannot be used as VAR parameter"],
  174. ["PROCEDURE T.method(); BEGIN SELF(POINTER) := pVar; END T.method;",
  175. "cannot assign to read-only variable"],
  176. ["PROCEDURE p();"
  177. + "TYPE Derived = RECORD(T) END; VAR d: Derived;"
  178. + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN pVar := SELF(POINTER); END Derived.method;"
  179. + "END p;",
  180. "cannot declare a variable of type 'Derived' (and derived types) because SELF(POINTER) was used in its method(s)"],
  181. ["PROCEDURE p();"
  182. + "TYPE Derived = RECORD(T) END; Derived2 = RECORD(Derived) END;"
  183. + "VAR d: Derived2;"
  184. + "PROCEDURE Derived.method(); VAR pVar: PT; BEGIN pVar := SELF(POINTER); END Derived.method;"
  185. + "END p;",
  186. "cannot declare a variable of type 'Derived' (and derived types) because SELF(POINTER) was used in its method(s)"]
  187. )
  188. ),
  189. "method call": testWithContext(
  190. context(grammar.expression,
  191. "TYPE T = RECORD PROCEDURE p(); PROCEDURE f(): INTEGER END;"
  192. + "VAR o: T;"
  193. + "PROCEDURE T.p(); END T.p;"
  194. + "PROCEDURE T.f(): INTEGER; RETURN 0 END T.f;"
  195. ),
  196. pass("o.f()"),
  197. fail(["o.p()", "procedure returning no result cannot be used in an expression"])
  198. ),
  199. "method call as statement": testWithContext(
  200. context(grammar.statement,
  201. "TYPE T = RECORD PROCEDURE p(); PROCEDURE f(): INTEGER END;"
  202. + "VAR o: T;"
  203. + "PROCEDURE T.p(); END T.p;"
  204. + "PROCEDURE T.f(): INTEGER; RETURN 0 END T.f;"
  205. ),
  206. pass("o.p"),
  207. fail(["o.f", "procedure returning a result cannot be used as a statement"])
  208. ),
  209. "cannot assign to method": testWithContext(
  210. context(grammar.statement,
  211. "TYPE T = RECORD PROCEDURE p() END;"
  212. + "VAR o: T;"
  213. + "PROCEDURE T.p(); END T.p;"
  214. ),
  215. pass(),
  216. fail(["o.p := o.p", "method 'p' cannot be referenced"],
  217. ["o.p := NIL", "cannot assign to method"])
  218. ),
  219. "method cannot be referenced": testWithContext(
  220. context(grammar.statement,
  221. "TYPE T = RECORD PROCEDURE p() END;"
  222. + "Proc = PROCEDURE();"
  223. + "VAR o: T;"
  224. + "PROCEDURE T.p(); END T.p;"
  225. + "PROCEDURE proc(p: Proc); END proc;"
  226. ),
  227. pass(),
  228. fail(["proc(o.p)", "method 'p' cannot be referenced"],
  229. ["v <- o.p", "method 'p' cannot be referenced"])
  230. ),
  231. "method super call": testWithContext(
  232. context(grammar.declarationSequence,
  233. "TYPE T = RECORD PROCEDURE p(); PROCEDURE pAbstract(); PROCEDURE pAbstract2() END;"
  234. + "D = RECORD(T) PROCEDURE pNoSuper() END;"
  235. + "PROCEDURE T.p(); END T.p;"
  236. ),
  237. pass("PROCEDURE D.p(); BEGIN SUPER() END D.p;"),
  238. fail(["PROCEDURE D.pNoSuper(); BEGIN SUPER() END D.pNoSuper;",
  239. "there is no method 'pNoSuper' in base type(s)"],
  240. ["PROCEDURE p(); BEGIN SUPER() END p;",
  241. "SUPER can be used only in methods"],
  242. ["PROCEDURE T.pNoBase(); BEGIN SUPER() END T.pNoBase;",
  243. "'T' has no base type - SUPER cannot be used"],
  244. ["PROCEDURE D.pAbstract(); BEGIN SUPER() END D.pAbstract;",
  245. "cannot use abstract method(s) in SUPER calls: pAbstract"],
  246. ["PROCEDURE D.pAbstract(); BEGIN SUPER() END D.pAbstract; PROCEDURE D.pAbstract2(); BEGIN SUPER() END D.pAbstract2;",
  247. "cannot use abstract method(s) in SUPER calls: pAbstract, pAbstract2"]
  248. )
  249. ),
  250. "export method": testWithContext(
  251. context(grammar.declarationSequence,
  252. "TYPE T = RECORD PROCEDURE p() END;"
  253. ),
  254. pass(),
  255. fail(["PROCEDURE T.p*(); END T.p;",
  256. "method implementation cannot be exported: p"])
  257. ),
  258. "import method": testWithModule(
  259. "MODULE test;"
  260. + "TYPE T* = RECORD PROCEDURE m*(); PROCEDURE mNotExported() END;"
  261. + "PROCEDURE T.m(); END T.m; PROCEDURE T.mNotExported(); END T.mNotExported;"
  262. + "END test.",
  263. pass("MODULE m; IMPORT test; VAR r: test.T; BEGIN r.m(); END m.",
  264. "MODULE m; IMPORT test; TYPE T = RECORD(test.T) END; PROCEDURE T.m(); END T.m; END m."
  265. ),
  266. fail(["MODULE m; IMPORT test; VAR r: test.T; BEGIN r.mNotExported(); END m.",
  267. "type 'T' has no 'mNotExported' field"],
  268. ["MODULE m; IMPORT test; TYPE T = RECORD(test.T) END; PROCEDURE T.mNotExported(); END T.mNotExported; END m.",
  269. "'T' has no declaration for method 'mNotExported'"])
  270. ),
  271. "non-scalar variables can be exported": testWithContext(
  272. context(grammar.declarationSequence,
  273. "TYPE T = RECORD END; A = ARRAY 3 OF INTEGER;"
  274. ),
  275. pass("VAR r*: T;",
  276. "VAR a*: A;"),
  277. fail()
  278. ),
  279. "export as read-only": testWithContext(
  280. context(grammar.declarationSequence, ""),
  281. pass("TYPE T* = RECORD i-: INTEGER END;"),
  282. fail(["TYPE T- = RECORD END;",
  283. "type cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  284. ["PROCEDURE p-(); END p;",
  285. "procedure cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  286. ["CONST c- = 123;",
  287. "constant cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  288. ["VAR i-: INTEGER;",
  289. "variable cannot be exported as read-only using '-' mark (did you mean '*'?)"],
  290. ["TYPE T* = RECORD PROCEDURE p-() END;",
  291. "method cannot be exported as read-only using '-' mark (did you mean '*'?)"]
  292. )
  293. ),
  294. "field exported as read-only is writable in current module": testWithContext(
  295. context(grammar.statement,
  296. "TYPE T* = RECORD i-: INTEGER END;"
  297. + "VAR r: T;"
  298. ),
  299. pass("r.i := 123"),
  300. fail()
  301. ),
  302. "import as read-only": testWithModule(
  303. "MODULE test; TYPE T* = RECORD f-: INTEGER END; END test.",
  304. pass(),
  305. fail(["MODULE m; IMPORT test; VAR r: test.T; BEGIN r.f := 123; END m.",
  306. "cannot assign to read-only variable"],
  307. ["MODULE m; IMPORT test; TYPE D = RECORD(test.T) END; VAR r: D; BEGIN r.f := 123; END m.",
  308. "cannot assign to read-only variable"]
  309. )),
  310. "STRING variable": testWithGrammar(
  311. grammar.variableDeclaration,
  312. pass("s: STRING")
  313. ),
  314. "STRING expression": testWithContext(
  315. context(grammar.expression,
  316. "VAR s1, s2: STRING; a: ARRAY 10 OF CHAR;"),
  317. pass("s1 + s2",
  318. "s1 + \"abc\"",
  319. "\"abc\" + s1",
  320. "s1 = s2",
  321. "s1 = \"abc\"",
  322. "s1 = 22X",
  323. "\"abc\" = s1",
  324. "22X = s1",
  325. "s1 # s2",
  326. "s1 # \"abc\"",
  327. "s1 # 22X",
  328. "\"abc\" # s1",
  329. "22X # s1",
  330. "s1 < s2",
  331. "s1 < \"abc\"",
  332. "s1 < 22X",
  333. "\"abc\" < s1",
  334. "22X < s1",
  335. "s1 > s2",
  336. "s1 > \"abc\"",
  337. "s1 > 22X",
  338. "\"abc\" > s1",
  339. "22X > s1",
  340. "s1 <= s2",
  341. "s1 <= \"abc\"",
  342. "\"abc\" <=s1",
  343. "22X <= s1",
  344. "s1 >= \"abc\"",
  345. "s1 >= 22X",
  346. "s1 >= s2",
  347. "\"abc\" >= s1",
  348. "22X >= s1"
  349. ),
  350. fail(["s1 = NIL", "type mismatch: expected 'STRING', got 'NIL'"],
  351. ["s1 = a", "type mismatch: expected 'STRING', got 'ARRAY 10 OF CHAR'"],
  352. ["a = s1", "type mismatch: expected 'ARRAY 10 OF CHAR', got 'STRING'"]
  353. )
  354. ),
  355. "STRING literal expression": testWithContext(
  356. context(grammar.expression,
  357. "CONST cs = \"abc\";"
  358. + "PROCEDURE pString(s: STRING): STRING; RETURN s END pString;"
  359. + "PROCEDURE pStringByRef(VAR s: STRING): STRING; RETURN s END pStringByRef;"
  360. ),
  361. pass("\"abc\" + \"cde\"",
  362. "cs + cs",
  363. "cs + \"abc\"",
  364. "cs = \"abc\"",
  365. "cs # \"abc\"",
  366. "cs < \"abc\"",
  367. "cs > \"abc\"",
  368. "cs <= \"abc\"",
  369. "cs >= \"abc\"",
  370. "pString(cs)",
  371. "pString(\"abc\")"
  372. ),
  373. fail(["pStringByRef(cs)", "type mismatch for argument 1: cannot pass 'multi-character string' as VAR parameter of type 'STRING'"],
  374. ["pStringByRef(\"abc\")", "type mismatch for argument 1: cannot pass 'multi-character string' as VAR parameter of type 'STRING'"]
  375. )
  376. ),
  377. "STRING assignment": testWithContext(
  378. context(grammar.statement,
  379. "VAR s1, s2: STRING; a: ARRAY 10 OF CHAR;"),
  380. pass("s1 := s2",
  381. "s1 := \"abc\"",
  382. "s1 := 22X"
  383. ),
  384. fail(["a := s1", "type mismatch: 'a' is 'ARRAY 10 OF CHAR' and cannot be assigned to 'STRING' expression"],
  385. ["s1 := a", "type mismatch: 's1' is 'STRING' and cannot be assigned to 'ARRAY 10 OF CHAR' expression"]
  386. )
  387. ),
  388. "STRING and ARRAY OF CHAR": testWithContext(
  389. context(grammar.expression,
  390. "VAR s: STRING; a: ARRAY 10 OF CHAR;"
  391. + "PROCEDURE pArray(a: ARRAY OF CHAR): BOOLEAN; RETURN FALSE END pArray;"
  392. + "PROCEDURE pString(s: STRING): BOOLEAN; RETURN FALSE END pString;"
  393. + "PROCEDURE pVar(VAR a: ARRAY OF CHAR): BOOLEAN; RETURN FALSE END pVar;"
  394. + "PROCEDURE pIntArray(a: ARRAY OF INTEGER): BOOLEAN; RETURN FALSE END pIntArray;"
  395. ),
  396. pass("pArray(s)"),
  397. fail(["pVar(s)", "type mismatch for argument 1: cannot pass 'STRING' as VAR parameter of type 'ARRAY OF CHAR'"],
  398. ["pString(a)", "type mismatch for argument 1: 'ARRAY 10 OF CHAR' cannot be converted to 'STRING'"],
  399. ["pIntArray(s)", "type mismatch for argument 1: 'STRING' cannot be converted to 'ARRAY OF INTEGER'"]
  400. )
  401. ),
  402. "STRING LEN": testWithContext(
  403. context(grammar.expression,
  404. "VAR s: STRING;"),
  405. pass("LEN(s)"),
  406. fail()
  407. ),
  408. "STRING indexing": testWithContext(
  409. context(grammar.expression,
  410. "VAR s: STRING;"
  411. + "PROCEDURE pCharByVar(VAR c: CHAR): CHAR; RETURN c END pCharByVar;"),
  412. pass("s[0]"),
  413. fail(["s[-1]", "index is negative: -1"],
  414. ["pCharByVar(s[0])", "string element cannot be used as VAR parameter"]
  415. )
  416. ),
  417. "designate call result in expression": testWithContext(
  418. context(grammar.expression,
  419. "TYPE PT = POINTER TO RECORD field: INTEGER END;"
  420. + "VAR p: PT;"
  421. + "PROCEDURE proc(): PT; RETURN p END proc;"
  422. + "PROCEDURE int(): INTEGER; RETURN 0 END int;"
  423. + "PROCEDURE intVar(VAR i: INTEGER): INTEGER; RETURN i END intVar;"),
  424. pass("proc().field",
  425. "intVar(proc().field)"),
  426. fail(["intVar(int())", "expression cannot be used as VAR parameter"])
  427. ),
  428. "designate call result in statement": testWithContext(
  429. context(grammar.statement,
  430. "TYPE PT = POINTER TO RECORD field: INTEGER; proc: PROCEDURE END;"
  431. + "ProcType = PROCEDURE;"
  432. + "VAR p: PT;"
  433. + "PROCEDURE procVoid(); END procVoid;"
  434. + "PROCEDURE proc(): PT; RETURN p END proc;"
  435. + "PROCEDURE int(): INTEGER; RETURN 0 END int;"
  436. + "PROCEDURE intVar(VAR i: INTEGER); END intVar;"
  437. + "PROCEDURE returnProc(): ProcType; RETURN procVoid END returnProc;"
  438. ),
  439. pass("proc().field := 0",
  440. "proc().proc()",
  441. "proc().proc"
  442. ),
  443. fail(["int() := 0", "cannot assign to procedure call result"],
  444. ["intVar(int())", "expression cannot be used as VAR parameter"],
  445. ["procVoid()()", "PROCEDURE expected, got 'procedure call statement'"],
  446. ["int()()", "PROCEDURE expected, got 'INTEGER'"],
  447. ["returnProc()", "procedure returning a result cannot be used as a statement"] // call is not applied implicitly to result
  448. )
  449. ),
  450. "type promotion": {
  451. "or" : pass(
  452. function(){
  453. var or = new TypePromotion.OrPromotions();
  454. var a = new TestVar();
  455. var p = or.next();
  456. assert(a.type() == "type");
  457. p.invert();
  458. p.promote(a, "type1");
  459. assert(a.type() == "type");
  460. or.next();
  461. assert(a.type() == "type1");
  462. or.reset();
  463. assert(a.type() == "type");
  464. },
  465. function(){
  466. var or = new TypePromotion.OrPromotions();
  467. var a = new TestVar();
  468. var p = or.next(p);
  469. p.promote(a, "type1");
  470. or.next();
  471. assert(a.type() == "type");
  472. },
  473. function(){
  474. var or = new TypePromotion.OrPromotions();
  475. var a = new TestVar();
  476. var p1 = or.next();
  477. p1.promote(a, "type1");
  478. var p2 = or.next();
  479. p2.invert();
  480. p2.promote(a, "type2");
  481. assert(a.type() == "type");
  482. assert(a.type() == "type");
  483. or.next();
  484. assert(a.type() == "type2");
  485. or.reset();
  486. assert(a.type() == "type");
  487. }
  488. ),
  489. "and": pass(
  490. function(){
  491. var and = new TypePromotion.AndPromotions();
  492. var a = new TestVar();
  493. var p = and.next();
  494. p.promote(a, "type1");
  495. and.next();
  496. assert(a.type() == "type1");
  497. and.reset();
  498. assert(a.type() == "type");
  499. },
  500. function(){ // (a IS type1) & (v OR (a IS type2)) & v
  501. var and = new TypePromotion.AndPromotions();
  502. var a = new TestVar();
  503. var p = and.next();
  504. p.promote(a, "type1");
  505. var subOr = and.next().makeOr();
  506. subOr.next();
  507. subOr.next().promote(a, "type2");
  508. and.next();
  509. assert(a.type() == "type1");
  510. and.reset();
  511. assert(a.type() == "type");
  512. },
  513. function(){ // (a IS type1) & ~(v OR ~(a IS type2)) & v
  514. var and = new TypePromotion.AndPromotions();
  515. var a = new TestVar();
  516. and.next().promote(a, "type1");
  517. var subOr = and.next();
  518. subOr.invert();
  519. subOr = subOr.makeOr();
  520. subOr.next();
  521. var p = subOr.next();
  522. p.invert();
  523. p.promote(a, "type2");
  524. and.next();
  525. assert(a.type() == "type2");
  526. and.reset();
  527. assert(a.type() == "type");
  528. },
  529. function(){ // (a IS type1) & (v & (a IS type2))
  530. var and = new TypePromotion.AndPromotions();
  531. var a = new TestVar();
  532. and.next().promote(a, "type1");
  533. var sub = and.next().makeAnd();
  534. sub.next();
  535. assert(a.type() == "type1");
  536. sub.next().promote(a, "type2");
  537. assert(a.type() == "type1");
  538. and.and();
  539. assert(a.type() == "type2");
  540. and.or();
  541. assert(a.type() == "type");
  542. },
  543. function(){ // (~(~(a IS type1)) & v) OR v
  544. var a = new TestVar();
  545. var or = new TypePromotion.OrPromotions();
  546. var and = or.next().makeAnd();
  547. var p1 = and.next();
  548. p1.invert();
  549. var p2 = p1.makeOr().next().makeAnd().next();
  550. p2.invert();
  551. p2.promote(a, "type1");
  552. and.next();
  553. assert(a.type() == "type1");
  554. or.next();
  555. assert(a.type() == "type");
  556. },
  557. function(){ // (v OR (a IS type1)) & v)
  558. var a = new TestVar();
  559. var and = new TypePromotion.AndPromotions();
  560. var or = and.next().makeOr();
  561. or.next();
  562. or.next().makeAnd().next().promote(a, "type1");
  563. and.next();
  564. assert(a.type() == "type");
  565. }
  566. )
  567. },
  568. "in place variables": {
  569. "initialization": testWithContext(
  570. context(grammar.statement,
  571. "VAR i: INTEGER;"
  572. + "PROCEDURE p(): BOOLEAN; RETURN FALSE END p;"
  573. + "PROCEDURE void(); END void;"
  574. ),
  575. pass("v <- 0",
  576. "v <- 1.23",
  577. "v <- \"abc\"",
  578. "v <- TRUE",
  579. "v <- i",
  580. "v <- i + i",
  581. "v <- p()",
  582. "v <- void" // procedure type
  583. ),
  584. fail(["v <-", "initialization expression expected"],
  585. ["v <- void()", "procedure returning no result cannot be used in an expression"],
  586. ["v <- NIL", "cannot use NIL to initialize variable"])
  587. ),
  588. "read-only if initialized with string literal": testWithContext(
  589. context(grammar.declarationSequence, ""),
  590. pass(),
  591. fail(["PROCEDURE p(); BEGIN s <- \"abc\"; s := \"def\"; END p;", "cannot assign to string literal"],
  592. ["PROCEDURE p(); BEGIN s <- \"abc\"; s[0] := \"d\"; END p;", "cannot assign to read-only variable"])
  593. ),
  594. "scope": testWithContext(
  595. temporaryValues.context,
  596. temporaryValues.passStatements(
  597. "v1 <- 0; v2 <-0;",
  598. "i <- 0; ASSERT(i = 0);",
  599. "WHILE FALSE DO v <- 0; ASSERT(v = 0); END; WHILE FALSE DO v <- 0; END;",
  600. "WHILE FALSE DO i1 <- 0; WHILE FALSE DO i2 <- 0; ASSERT(i1 = 0); ASSERT(i2 = 0); END; END;",
  601. "WHILE bVar DO v <- 0; ELSIF ~bVar DO v <- 0 END;",
  602. "IF FALSE THEN v <- 0; ASSERT(v = 0); END; IF FALSE THEN v <- 0; END;",
  603. "IF FALSE THEN v <- 0; END; IF FALSE THEN v <- 0; END;",
  604. "IF FALSE THEN v <- 0; ELSIF FALSE THEN v <- 0; ELSE v <- 0; END;",
  605. "i <- 0; CASE i OF 0: v <- 0 | 1: v <- 1; ; ASSERT(v = 1); END;",
  606. "REPEAT v <- 0; UNTIL FALSE; REPEAT v <- 0; UNTIL FALSE;",
  607. "REPEAT v <- 0; ASSERT(v = 0); UNTIL v # 0;",
  608. "i <- 0; FOR i := 0 TO 10 DO v <- 0; END; FOR i := 0 TO 10 DO v <- 0; END;"
  609. ),
  610. fail(["PROCEDURE p(); BEGIN v <- 0; v <-0; END p;", "'v' already declared"],
  611. ["PROCEDURE p(); VAR v: INTEGER; BEGIN v <- 0; END p;", "'v' already declared"],
  612. ["PROCEDURE p(); BEGIN v <- 0; WHILE FALSE DO v <- 0; END; END p;",
  613. "'v' already declared in procedure scope"],
  614. ["PROCEDURE p(); BEGIN i <- 0; IF FALSE THEN i <- 0; END; END p;",
  615. "'i' already declared in procedure scope"],
  616. ["PROCEDURE p(); BEGIN i <- 0; IF TRUE THEN IF TRUE THEN i <- 0; END; END; END p;",
  617. "'i' already declared in procedure scope"],
  618. ["PROCEDURE p(); BEGIN WHILE FALSE DO i <- 0; WHILE FALSE DO i <- 0; END; END; END p;",
  619. "'i' already declared in operator scope"]
  620. )
  621. ),
  622. "type promotion in expression": testWithContext(
  623. temporaryValues.context,
  624. temporaryValues.passExpressions(
  625. "(b IS PDerived) & b.flag",
  626. "(b IS PDerived) & bVar & b.flag",
  627. "(b IS PDerived) & (bVar OR b.flag)",
  628. "(b IS PDerived) & (b2 IS PDerived) & b.flag & b2.flag",
  629. "(b IS PDerived) & proc(TRUE) & b.flag",
  630. "(b IS PDerived) & ~proc(TRUE) & b.flag",
  631. "~(~(b IS PDerived)) & b.flag",
  632. "~~(b IS PDerived) & b.flag",
  633. "(b IS PDerived) & ((b IS PDerived2) OR bVar) & b.flag",
  634. "(b IS PDerived) & (bVar OR (b IS PDerived2)) & b.flag",
  635. "(b IS PDerived) & ~(bVar OR ~(b IS PDerived2)) & b.flag2",
  636. "~(bVar & (b IS PDerived)) OR b.flag"
  637. //TODO: "((b IS PDerived) = TRUE) & b.flag); END p;",
  638. ),
  639. temporaryValues.failExpressions(
  640. "(b IS PDerived) OR b.flag",
  641. "(bVar OR (b IS PDerived)) & b.flag",
  642. "(b IS PDerived) OR bVar & b.flag",
  643. "~(b IS PDerived) & b.flag",
  644. "((b IS PDerived) & (b2 IS PDerived) OR bVar) & b.flag",
  645. "proc(b IS PDerived) & proc(b.flag)",
  646. "ORD(b IS PDerived) * ORD(b.flag) = 0",
  647. "((b IS PDerived) = FALSE) & b.flag",
  648. "((b IS PDerived) & bVar) = b.flag",
  649. "b IS PDerived); ASSERT(b.flag",
  650. "((b IS PDerived) OR (b IS PDerived)) & b.flag",
  651. "(b IS PDerived) OR (b IS PDerived) OR b.flag",
  652. "(bVar OR (b IS PDerived)) & b.flag",
  653. "~(bVar & ~(b IS PDerived)) & b.flag"
  654. )
  655. ),
  656. "invert type promotion in expression": testWithContext(
  657. temporaryValues.context,
  658. temporaryValues.passExpressions(
  659. "~(b IS PDerived) OR b.flag",
  660. "~(b IS PDerived) OR b.flag OR bVar",
  661. "~(b IS PDerived) OR b.flag & bVar",
  662. "~(b IS PDerived) OR bVar & b.flag",
  663. "~(b IS PDerived) OR (bVar & b.flag)",
  664. "~(b IS PDerived) OR bVar OR b.flag",
  665. "~(b IS PDerived) OR (bVar = b.flag)",
  666. "~(~(b IS PDerived) OR bVar) & b.flag",
  667. "~(~(b IS PDerived) OR b.flag) & b.flag",
  668. "~(b IS PDerived) OR ~(b2 IS PDerived) OR b2.flag",
  669. "~(b IS PDerived) OR b.flag OR ~(b2 IS PDerived) OR b2.flag",
  670. "~((b IS PDerived) & b.flag) OR b.flag OR ~(b2 IS PDerived) OR b2.flag",
  671. "~((b IS PDerived) & b.flag) OR b.flag OR ~((b2 IS PDerived) & b.flag & b2.flag) OR b2.flag"
  672. ),
  673. temporaryValues.failExpressions(
  674. "(~(b IS PDerived) OR bVar) & b.flag",
  675. "(ORD(~(b IS PDerived)) + ORD(b.flag)",
  676. "~(~(b IS PDerived) OR bVar) OR b.flag",
  677. "~(~(b IS PDerived) & bVar) & b.flag",
  678. "~(b IS PDerived) OR b.flag = b.flag"
  679. )
  680. ),
  681. "type promotion in separate statements": testWithContext(
  682. temporaryValues.context,
  683. pass(),
  684. temporaryValues.failStatements(
  685. "bVar := b IS PDerived; ASSERT(b.flag)",
  686. "bVar := (b IS PDerived) & bVar; ASSERT(b.flag)"
  687. )
  688. ),
  689. "type promotion in IF": testWithContext(
  690. temporaryValues.context,
  691. temporaryValues.passStatements(
  692. "IF b IS PDerived THEN b.flag := FALSE; END;",
  693. "IF (b IS PDerived) & bVar THEN b.flag := FALSE; END;",
  694. "IF bVar & (b IS PDerived) THEN b.flag := FALSE; END;",
  695. "IF FALSE THEN ELSIF b IS PDerived THEN b.flag := FALSE; END;",
  696. "IF b IS PDerived THEN bVar := (b IS PDerived2) & b.flag2; b.flag := FALSE; END;",
  697. "IF bVar THEN ELSIF b IS PDerived2 THEN ELSIF b IS PDerived THEN END;",
  698. "IF bVar THEN ELSIF b IS PDerived THEN ELSIF b IS PDerived THEN ELSIF b IS PDerived THEN END;",
  699. "IF b IS PDerived THEN IF bVar OR (b IS PDerived2) THEN b.flag := FALSE; END; END"
  700. ),
  701. temporaryValues.failStatements(
  702. "IF (b IS PDerived) OR bVar THEN b.flag := FALSE; END",
  703. "IF bVar OR (b IS PDerived) THEN b.flag := FALSE; END",
  704. "IF (b2 IS PDerived) OR (b IS PDerived) THEN b.flag := FALSE; END",
  705. "IF (b IS PDerived) OR (b IS PDerived) THEN b.flag := FALSE; END",
  706. "IF (b IS PDerived) OR (b IS PDerived) OR b.flag THEN END",
  707. "IF (b IS PDerived) OR (b IS PDerived) OR (b IS PDerived) THEN b.flag := FALSE; END",
  708. "IF ((b IS PDerived) OR (b IS PDerived)) THEN b.flag := FALSE; END",
  709. "IF (b IS PDerived) OR (b IS PDerived2) THEN b.flag := FALSE; END",
  710. "IF (b IS PDerived2) OR (b IS PDerived) THEN b.flag := FALSE; END",
  711. "IF b IS PDerived THEN END; b.flag := FALSE",
  712. "IF ~(b IS PDerived) THEN END; b.flag := FALSE",
  713. "IF ~(b IS PDerived) THEN ELSIF bVar THEN END; b.flag := FALSE",
  714. "IF ~(b IS PDerived) THEN ELSIF bVar THEN ELSE END; b.flag := FALSE",
  715. "IF bVar THEN ELSIF b IS PDerived THEN ELSE END; b.flag := FALSE",
  716. "IF b IS PDerived THEN ELSE b.flag := FALSE; END",
  717. "IF bVar OR (b IS PDerived) THEN b.flag := FALSE; END;",
  718. "IF bVar OR (b IS PDerived) THEN ELSE b.flag := FALSE; END;",
  719. "IF bVar OR ~(b IS PDerived) THEN b.flag := FALSE; END;",
  720. "IF b IS PDerived THEN ELSIF TRUE THEN b.flag := FALSE; END",
  721. "IF bVar THEN bVar := (b IS PDerived) & bVar; ASSERT(b.flag); END"
  722. )
  723. ),
  724. "invert type promotion in IF": testWithContext(
  725. temporaryValues.context,
  726. temporaryValues.passStatements(
  727. "IF ~(b IS PDerived) THEN ELSE b.flag := FALSE; END;",
  728. "IF ~(b IS PDerived) THEN ELSIF bVar THEN b.flag := FALSE; ELSE b.flag := FALSE; END;",
  729. "IF ~(b IS PDerived) THEN ELSIF ~(b2 IS PDerived) THEN b.flag := FALSE; ELSE b.flag := FALSE; b2.flag := FALSE; END;",
  730. "IF ~(b IS PDerived) OR bVar THEN ELSE b.flag := FALSE; END;",
  731. "IF ~(b IS PDerived) OR b.flag THEN ELSE b.flag := FALSE; END;",
  732. "IF ~(b IS PDerived) OR (b2 IS PDerived) THEN ELSE b.flag := FALSE; END;",
  733. "IF ~(b IS PDerived) OR ~(b2 IS PDerived) THEN ELSE b2.flag := FALSE; END;",
  734. "IF ~(b IS PDerived) THEN bVar := b IS PDerived; ELSE b.flag := FALSE; END;",
  735. "IF ~(b IS PDerived) THEN ASSERT((b IS PDerived) & b.flag); ELSE b.flag := FALSE; END;",
  736. "IF bVar OR ~(b IS PDerived) THEN ELSE b.flag := FALSE; END;"
  737. ),
  738. temporaryValues.failStatements(
  739. "IF ~(b IS PDerived) & bVar THEN ELSE b.flag := FALSE; END; END p;",
  740. "IF ~(b IS PDerived) THEN ELSIF ~(b2 IS PDerived) THEN b2.flag := FALSE; END;",
  741. "IF bVar OR (b IS PDerived) THEN ELSE b.flag := FALSE; END;"
  742. )
  743. ),
  744. "type promotion in WHILE": testWithContext(
  745. temporaryValues.context,
  746. temporaryValues.passStatements(
  747. "WHILE (b IS PDerived) & b.flag DO END;",
  748. "WHILE ~(b IS PDerived) OR b.flag DO END;",
  749. "WHILE b IS PDerived DO b.flag := FALSE; END;",
  750. "WHILE ~(b IS PDerived) DO ELSIF b.flag DO END;",
  751. "WHILE ~(b IS PDerived) DO ELSIF bVar DO b.flag := FALSE; END;"
  752. ),
  753. temporaryValues.failStatements(
  754. "WHILE b IS PDerived DO END; b.flag := FALSE;"
  755. )
  756. ),
  757. "type promotion cannot be reset by assignment": testWithContext(
  758. temporaryValues.context,
  759. pass(),
  760. fail(["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN b := pBase; b.flag := FALSE; END; END p;",
  761. "type mismatch: 'b' is 'PDerived' and cannot be assigned to 'POINTER TO Base' expression"]
  762. )
  763. ),
  764. "type promotion cannot be reset by passing as VAR argument": testWithContext(
  765. temporaryValues.context,
  766. pass(),
  767. 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;",
  768. "type mismatch for argument 1: cannot pass 'PDerived' as VAR parameter of type 'PBase'"]
  769. )
  770. ),
  771. "type promotion after dereferencing": testWithContext(
  772. temporaryValues.context,
  773. temporaryValues.passExpressions(
  774. "(b^ IS Derived) & b.flag")
  775. ),
  776. "IS expression after type promotion": testWithContext(
  777. temporaryValues.context,
  778. pass(),
  779. fail(["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN bVar := b IS PDerived; b.flag := FALSE; END; END p;",
  780. "invalid type test: 'Derived' is not an extension of 'Derived'"]
  781. )
  782. ),
  783. "record types as values": testWithContext(
  784. context(grammar.declarationSequence,
  785. "TYPE Base = RECORD pBase: POINTER TO Base END;"
  786. + "Derived = RECORD (Base) END;"
  787. + "VAR base: Base;"
  788. + "PROCEDURE procBaseVar(VAR b: Base); END procBaseVar;"
  789. ),
  790. pass("PROCEDURE p(b: Base); BEGIN base <- b; procBaseVar(base); base := b; END p;"),
  791. fail(["PROCEDURE p(); BEGIN baseVar <- base.pBase^; ASSERT(base IS Derived); END p;",
  792. "invalid type test: a value variable cannot be used"],
  793. ["PROCEDURE p(VAR b: Base); BEGIN base <- b; ASSERT(base IS Derived); END p;",
  794. "invalid type test: a value variable cannot be used"],
  795. ["PROCEDURE p(b: Base); BEGIN base <- b; ASSERT(base IS Derived); END p;",
  796. "invalid type test: a value variable cannot be used"],
  797. ["PROCEDURE p(); TYPE Abstract = RECORD PROCEDURE method() END; PROCEDURE test(a: Abstract); BEGIN v <- a; END test; END p;",
  798. "cannot instantiate 'Abstract' because it has abstract method(s): method"],
  799. ["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;",
  800. "cannot declare a variable of type 'T' (and derived types) because SELF(POINTER) was used in its method(s)"]
  801. )
  802. ),
  803. "arrays as values": testWithContext(
  804. context(grammar.declarationSequence,
  805. "TYPE A = ARRAY 3 OF INTEGER; T = RECORD a: A END;"
  806. + "VAR r: T;"
  807. + "PROCEDURE procArrayVar(VAR a: A); END procArrayVar;"
  808. ),
  809. pass("PROCEDURE p(r: T); BEGIN a <- r.a; a[0] := 123; procArrayVar(a); END p;",
  810. "PROCEDURE p(a: A); BEGIN tmp <- a; END p;",
  811. "PROCEDURE p(); VAR a: A; BEGIN tmp <- a; END p;",
  812. "PROCEDURE p(); VAR a: ARRAY 3 OF BOOLEAN; BEGIN tmp <- a; END p;"
  813. ),
  814. fail(["PROCEDURE p(a: ARRAY OF INTEGER); BEGIN v <- a; END p;",
  815. "cannot initialize variable 'v' with open array"]
  816. )
  817. ),
  818. "FOR variable": testWithContext(
  819. context(grammar.statement, ""),
  820. pass("FOR i <- 0 TO 10 DO END",
  821. "FOR i <- 0 TO 10 DO FOR j <- 0 TO 10 BY 1 DO END END",
  822. "IF TRUE THEN FOR i <- 0 TO 10 DO END; FOR i <- 0 TO 10 BY 1 DO END; END"
  823. ),
  824. fail(["FOR i <- 0.0 TO 10 DO END", "'INTEGER' expression expected to assign 'i', got 'REAL'"],
  825. ["IF TRUE THEN FOR i <- 0 TO 10 DO END; i := 1; END", "undeclared identifier: 'i'"]
  826. )
  827. )
  828. },
  829. "type promotion for VAR arguments": testWithContext(
  830. context(grammar.declarationSequence,
  831. "TYPE Base = RECORD END; PBase = POINTER TO Base;"
  832. + "Derived = RECORD (Base) flag: BOOLEAN END; PDerived = POINTER TO Derived;"),
  833. pass("PROCEDURE p(VAR b: Base); BEGIN ASSERT((b IS Derived) & b.flag); END p;"),
  834. fail(["PROCEDURE p(VAR b: PBase); BEGIN ASSERT((b IS PDerived) & b.flag); END p;",
  835. "type 'Base' has no 'flag' field"])
  836. ),
  837. "type promotion for non-VAR arguments": testWithContext(
  838. context(grammar.declarationSequence,
  839. "TYPE Base = RECORD END; PBase = POINTER TO Base;"
  840. + "Derived = RECORD (Base) flag: BOOLEAN END; PDerived = POINTER TO Derived;"),
  841. pass("PROCEDURE p(b: PBase); BEGIN ASSERT((b IS PDerived) & b.flag); END p;")
  842. ),
  843. "Non-VAR arguments cannot be modified": testWithContext(
  844. context(grammar.declarationSequence,
  845. "TYPE PBase = POINTER TO RECORD END; T = RECORD i: INTEGER END;"
  846. + "PROCEDURE pArrayRef(VAR a: ARRAY OF INTEGER); END pArrayRef;"
  847. + "PROCEDURE recordVar(VAR r: T); END recordVar;"),
  848. pass("PROCEDURE p(VAR i: INTEGER); BEGIN i := 0; END p;",
  849. "PROCEDURE p(VAR b: PBase); BEGIN b := NIL; END p;"),
  850. fail(["PROCEDURE p(i: INTEGER); BEGIN i := 0; END p;",
  851. "cannot assign to non-VAR formal parameter"],
  852. ["PROCEDURE p(b: PBase); BEGIN b := NIL; END p;",
  853. "cannot assign to non-VAR formal parameter"],
  854. ["PROCEDURE p(a: ARRAY OF INTEGER); BEGIN pArrayRef(a) END p",
  855. "non-VAR formal parameter cannot be used as VAR parameter"],
  856. ["PROCEDURE p(r: T); BEGIN recordVar(r); END p",
  857. "non-VAR formal parameter cannot be used as VAR parameter"],
  858. ["PROCEDURE p(s1, s2: ARRAY OF CHAR); BEGIN s1 := s2 END p",
  859. "cannot assign to non-VAR formal parameter"],
  860. ["PROCEDURE p(s: ARRAY OF CHAR); BEGIN s := \"abc\" END p",
  861. "cannot assign to non-VAR formal parameter"]
  862. )
  863. ),
  864. "dynamic ARRAY": {
  865. "declaration": testWithContext(
  866. context(grammar.declarationSequence,
  867. "TYPE DA = ARRAY * OF INTEGER;"),
  868. pass("TYPE A = ARRAY * OF INTEGER;",
  869. "TYPE A = ARRAY * OF ARRAY * OF INTEGER;",
  870. "TYPE A = ARRAY *, * OF INTEGER;",
  871. "TYPE A = ARRAY 3, * OF INTEGER;",
  872. "TYPE A = ARRAY *, 3 OF INTEGER;",
  873. "TYPE P = PROCEDURE(): DA;",
  874. "TYPE P = PROCEDURE(VAR a: DA): DA;",
  875. "TYPE P = PROCEDURE(VAR a: ARRAY * OF INTEGER): DA;",
  876. "VAR a: ARRAY * OF INTEGER;",
  877. "PROCEDURE p(VAR a: ARRAY * OF INTEGER);END p;",
  878. "PROCEDURE p(VAR a: ARRAY * OF ARRAY * OF INTEGER);END p;",
  879. "PROCEDURE p(VAR a: ARRAY OF ARRAY * OF INTEGER);END p;"
  880. ),
  881. fail(["TYPE A = ARRAY OF INTEGER;", "not parsed"],
  882. ["TYPE P = PROCEDURE(): ARRAY OF INTEGER;", "';' expected"],
  883. ["TYPE P = PROCEDURE(a: DA);", "dynamic array has no use as non-VAR argument 'a'"],
  884. ["TYPE P = PROCEDURE(a: ARRAY * OF INTEGER);", "dynamic array has no use as non-VAR argument 'a'"],
  885. ["PROCEDURE p(a: DA);END p;", "dynamic array has no use as non-VAR argument 'a'"],
  886. ["PROCEDURE p(a: ARRAY * OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"],
  887. ["PROCEDURE p(a: ARRAY OF ARRAY * OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"],
  888. ["PROCEDURE p(a: ARRAY * OF ARRAY OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"]
  889. )
  890. ),
  891. "return": testWithContext(
  892. context(grammar.declarationSequence,
  893. "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
  894. + "VAR a: A; b: B;"),
  895. pass("PROCEDURE p(): A; RETURN a END p;",
  896. "PROCEDURE p(): A; VAR static: ARRAY 3 OF INTEGER; RETURN static END p;"),
  897. fail(["PROCEDURE p(): ARRAY OF INTEGER; RETURN a; END p;", "not parsed"],
  898. ["PROCEDURE p(): A; RETURN b; END p;", "RETURN 'ARRAY * OF INTEGER' expected, got 'ARRAY * OF BOOLEAN'"])
  899. ),
  900. "pass as VAR argument": testWithContext(
  901. context(grammar.statement,
  902. "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
  903. + "VAR a: A; b: B; aStatic: ARRAY 3 OF INTEGER;"
  904. + "PROCEDURE paVar(VAR a: A); END paVar;"
  905. + "PROCEDURE paVarOpen(VAR a: ARRAY OF INTEGER); END paVarOpen;"),
  906. pass("paVar(a)",
  907. "paVarOpen(a)"),
  908. fail(["paVar(aStatic)", "type mismatch for argument 1: cannot pass 'ARRAY 3 OF INTEGER' as VAR parameter of type 'ARRAY * OF INTEGER'"])
  909. ),
  910. "assign": testWithContext(
  911. context(grammar.statement,
  912. "VAR stat: ARRAY 3 OF INTEGER; dynamic: ARRAY * OF INTEGER;"),
  913. pass("dynamic := stat"),
  914. fail(["stat := dynamic", "type mismatch: 'stat' is 'ARRAY 3 OF INTEGER' and cannot be assigned to 'ARRAY * OF INTEGER' expression"])
  915. ),
  916. "indexing": testWithContext(
  917. context(grammar.expression,
  918. "VAR a: ARRAY * OF INTEGER;"),
  919. pass("a[0]", "a[1]"),
  920. fail(["a[-1]", "index is negative: -1"],
  921. ["a[-2]", "index is negative: -2"])
  922. ),
  923. "add": testWithContext(
  924. context(grammar.statement,
  925. "VAR a: ARRAY * OF INTEGER;"),
  926. pass("a.add(123)"),
  927. fail(["a.add := NIL", "cannot assign to method"],
  928. ["v <- a.add", "standard procedure 'add' cannot be referenced"]
  929. )
  930. )
  931. }
  932. };