|
@@ -21,6 +21,31 @@ function testWithGrammar(parser, pass, faile){
|
|
|
return TestUnitCommon.testWithGrammar(parser, language, pass, fail);
|
|
|
}
|
|
|
|
|
|
+var typePromotion = {
|
|
|
+ context: context(
|
|
|
+ grammar.declarationSequence,
|
|
|
+ "TYPE Base = RECORD END;"
|
|
|
+ + "Derived = RECORD (Base) flag: BOOLEAN END;"
|
|
|
+ + "PDerived = POINTER TO Derived;"
|
|
|
+ + "VAR pBase: POINTER TO Base; bVar: BOOLEAN;"
|
|
|
+ + "PROCEDURE proc(b: BOOLEAN): BOOLEAN; RETURN b END proc;"),
|
|
|
+ expression: function(e){
|
|
|
+ return "PROCEDURE p(); BEGIN b <- pBase; b2 <- pBase; ASSERT(" + e + "); END p;";
|
|
|
+ },
|
|
|
+ passExpressions: function(){
|
|
|
+ var result = [];
|
|
|
+ for(var i = 0; i < arguments.length; ++i)
|
|
|
+ result.push(this.expression(arguments[i]));
|
|
|
+ return pass.apply(this, result);
|
|
|
+ },
|
|
|
+ failExpressions: function(){
|
|
|
+ var result = [];
|
|
|
+ for(var i = 0; i < arguments.length; ++i)
|
|
|
+ result.push([this.expression(arguments[i]), "type 'Base' has no 'flag' field"]);
|
|
|
+ return fail.apply(this, result);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
exports.suite = {
|
|
|
"arithmetic operators": testWithContext(
|
|
|
context(grammar.statement, "VAR b1: BOOLEAN;"),
|
|
@@ -392,54 +417,65 @@ exports.suite = {
|
|
|
)
|
|
|
),
|
|
|
"type promotion in expression": testWithContext(
|
|
|
- context(grammar.declarationSequence,
|
|
|
- "TYPE Base = RECORD END;"
|
|
|
- + "Derived = RECORD (Base) flag: BOOLEAN END;"
|
|
|
- + "PDerived = POINTER TO Derived;"
|
|
|
- + "VAR pBase: POINTER TO Base; bVar: BOOLEAN;"
|
|
|
- + "PROCEDURE proc(b: BOOLEAN): BOOLEAN; RETURN b END proc;"
|
|
|
- ),
|
|
|
- pass("PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & b.flag); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & bVar & b.flag); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) & (bVar OR b.flag)); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & (b2 IS PDerived) & b1.flag & b2.flag); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & proc(TRUE) & b1.flag); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT((b1 IS PDerived) & ~proc(TRUE) & b1.flag); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b <- pBase; ASSERT(~(~(b IS PDerived)) & b.flag); END p;",
|
|
|
- "PROCEDURE p(); BEGIN b <- pBase; ASSERT(~~(b IS PDerived) & b.flag); END p;"
|
|
|
- //TODO: "PROCEDURE p(); BEGIN b <- pBase; ASSERT(((b IS PDerived) = TRUE) & b.flag); END p;",
|
|
|
+ typePromotion.context,
|
|
|
+ typePromotion.passExpressions(
|
|
|
+ "(b IS PDerived) & b.flag",
|
|
|
+ "(b IS PDerived) & bVar & b.flag",
|
|
|
+ "(b IS PDerived) & (bVar OR b.flag)",
|
|
|
+ "(b IS PDerived) & (b2 IS PDerived) & b.flag & b2.flag",
|
|
|
+ "(b IS PDerived) & proc(TRUE) & b.flag",
|
|
|
+ "(b IS PDerived) & ~proc(TRUE) & b.flag",
|
|
|
+ "~(~(b IS PDerived)) & b.flag",
|
|
|
+ "~~(b IS PDerived) & b.flag"
|
|
|
+ //TODO: "((b IS PDerived) = TRUE) & b.flag); END p;",
|
|
|
),
|
|
|
- fail(["PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) OR b.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; ASSERT((b IS PDerived) OR bVar & b.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(~(b IS PDerived) & b.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b1 <- pBase; b2 <- pBase; ASSERT(((b1 IS PDerived) & (b2 IS PDerived) OR bVar) & b1.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(proc(b IS PDerived) & proc(b.flag)); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(ORD(b IS PDerived) * ORD(b.flag) = 0); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(((b IS PDerived) = FALSE) & b.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; ASSERT(b IS PDerived); ASSERT(b.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"],
|
|
|
- ["PROCEDURE p(); BEGIN b <- pBase; bVar := b IS PDerived; ASSERT(b.flag); END p;",
|
|
|
- "type 'Base' has no 'flag' field"]
|
|
|
+ typePromotion.failExpressions(
|
|
|
+ "(b IS PDerived) OR b.flag",
|
|
|
+ "(b IS PDerived) OR bVar & b.flag",
|
|
|
+ "~(b IS PDerived) & b.flag",
|
|
|
+ "((b IS PDerived) & (b2 IS PDerived) OR bVar) & b.flag",
|
|
|
+ "proc(b IS PDerived) & proc(b.flag)",
|
|
|
+ "ORD(b IS PDerived) * ORD(b.flag) = 0",
|
|
|
+ "((b IS PDerived) = FALSE) & b.flag",
|
|
|
+ "b IS PDerived); ASSERT(b.flag"
|
|
|
+ // TODO: move to statements test "bVar := b IS PDerived; ASSERT(b.flag)",
|
|
|
)
|
|
|
),
|
|
|
+ "invert type promotion in expression": testWithContext(
|
|
|
+ typePromotion.context,
|
|
|
+ typePromotion.passExpressions(
|
|
|
+ "~(b IS PDerived) OR b.flag",
|
|
|
+ "~(b IS PDerived) OR b.flag OR bVar",
|
|
|
+ "~(b IS PDerived) OR b.flag & bVar",
|
|
|
+ "~(b IS PDerived) OR bVar & b.flag",
|
|
|
+ "~(b IS PDerived) OR (bVar & b.flag)",
|
|
|
+ "~(b IS PDerived) OR bVar OR b.flag",
|
|
|
+ "~(b IS PDerived) OR (bVar = b.flag)",
|
|
|
+ "~(~(b IS PDerived) OR bVar) & b.flag",
|
|
|
+ "~(~(b IS PDerived) OR b.flag) & b.flag"
|
|
|
+ ),
|
|
|
+ typePromotion.failExpressions(
|
|
|
+ "(~(b IS PDerived) OR bVar) & b.flag",
|
|
|
+ "(ORD(~(b IS PDerived)) + ORD(b.flag)",
|
|
|
+ "~(~(b IS PDerived) OR bVar) OR b.flag",
|
|
|
+ "~(~(b IS PDerived) & bVar) & b.flag",
|
|
|
+ "~(b IS PDerived) OR b.flag = b.flag"
|
|
|
+ )
|
|
|
+ ),
|
|
|
"type promotion in condition": testWithContext(
|
|
|
context(grammar.declarationSequence,
|
|
|
"TYPE Base = RECORD END;"
|
|
|
+ "Derived = RECORD (Base) flag: BOOLEAN END;"
|
|
|
+ + "Derived2 = RECORD (Derived) flag2: BOOLEAN END;"
|
|
|
+ "PDerived = POINTER TO Derived;"
|
|
|
+ + "PDerived2 = POINTER TO Derived2;"
|
|
|
+ "VAR pBase: POINTER TO Base; bVar: BOOLEAN;"
|
|
|
+ "PROCEDURE proc(b: BOOLEAN): BOOLEAN; RETURN b END proc;"
|
|
|
),
|
|
|
pass("PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN b.flag := FALSE; END; END p;",
|
|
|
"PROCEDURE p(); BEGIN b <- pBase; IF (b IS PDerived) & bVar THEN b.flag := FALSE; END; END p;",
|
|
|
- "PROCEDURE p(); BEGIN b <- pBase; IF FALSE THEN ELSIF b IS PDerived THEN b.flag := FALSE; END; END p;"
|
|
|
+ "PROCEDURE p(); BEGIN b <- pBase; IF FALSE THEN ELSIF b IS PDerived THEN b.flag := FALSE; END; END p;",
|
|
|
+ "PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN bVar := (b IS PDerived2) & b.flag2; b.flag := FALSE; END; END p;"
|
|
|
),
|
|
|
fail(["PROCEDURE p(); BEGIN b <- pBase; IF (b IS PDerived) OR bVar THEN b.flag := FALSE; END; END p;",
|
|
|
"type 'Base' has no 'flag' field"],
|
|
@@ -448,10 +484,12 @@ exports.suite = {
|
|
|
["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN ELSE b.flag := FALSE; END; END p;",
|
|
|
"type 'Base' has no 'flag' field"],
|
|
|
["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN ELSIF TRUE THEN b.flag := FALSE; END; END p;",
|
|
|
- "type 'Base' has no 'flag' field"]
|
|
|
+ "type 'Base' has no 'flag' field"],
|
|
|
+ ["PROCEDURE p(); BEGIN b <- pBase; IF b IS PDerived THEN bVar := b IS PDerived; b.flag := FALSE; END; END p;",
|
|
|
+ "invalid type test: 'Derived' is not an extension of 'Derived'"]
|
|
|
)
|
|
|
),
|
|
|
- "negate type promotion in condition": testWithContext(
|
|
|
+ "invert type promotion in condition": testWithContext(
|
|
|
context(grammar.declarationSequence,
|
|
|
"TYPE Base = RECORD END;"
|
|
|
+ "Derived = RECORD (Base) flag: BOOLEAN END;"
|