From c00136fdd90d01f0870b5a9b711d6d42460fa0d5 Mon Sep 17 00:00:00 2001
From: Pieter Bos
Date: Thu, 29 Jun 2023 15:10:07 +0200
Subject: [PATCH 01/11] correct runClasspath for the benefit of e.g. tests
---
project/release.sc | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/project/release.sc b/project/release.sc
index a1544f7c38..33588739ee 100644
--- a/project/release.sc
+++ b/project/release.sc
@@ -66,13 +66,6 @@ trait SeparatePackedResourcesModule extends JavaModule {
)
}
- def compileClasspath: T[Agg[PathRef]] = T {
- transitiveLocalPackedClasspath() ++
- packedResources() ++
- unmanagedClasspath() ++
- resolvedIvyDeps()
- }
-
def runClasspathElements = T {
val paths = localPackedClasspath().map(_.path) ++
upstreamAssemblyClasspath().map(_.path) ++
@@ -80,6 +73,12 @@ trait SeparatePackedResourcesModule extends JavaModule {
transitiveBareResourcePaths()
paths.map(_.toString)
}
+
+ def runClasspath = T {
+ localPackedClasspath() ++
+ upstreamAssemblyClasspath() ++
+ (bareResourcePaths() ++ transitiveBareResourcePaths()).map(PathRef(_))
+ }
}
trait ReleaseModule extends JavaModule with SeparatePackedResourcesModule {
From f51395f7e0e00dc571632c8c8ed566d98923f84b Mon Sep 17 00:00:00 2001
From: Pieter Bos
Date: Thu, 29 Jun 2023 15:23:00 +0200
Subject: [PATCH 02/11] bump mill
---
.mill-version | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.mill-version b/.mill-version
index 1f2780b9d6..027934ea1a 100644
--- a/.mill-version
+++ b/.mill-version
@@ -1 +1 @@
-0.11.0-M11
\ No newline at end of file
+0.11.1
\ No newline at end of file
From 3c4cf8317b043aef2cbcef485032dd88f3f463ea Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Fri, 30 Jun 2023 13:12:36 +0200
Subject: [PATCH 03/11] Basic C++ implementation
---
build.sc | 1 +
examples/concepts/cpp/Arrays.cpp | 23 +
examples/concepts/cpp/Conditionals.cpp | 33 +
examples/concepts/cpp/Loops.cpp | 37 +
examples/concepts/cpp/Operators.cpp | 88 ++
examples/concepts/cpp/Pointers.cpp | 36 +
examples/concepts/cpp/Scoping.cpp | 17 +
examples/concepts/cpp/Types.cpp | 19 +
.../concepts/cpp/methods/AbstractMethod.cpp | 13 +
.../methods/ContextAndContextEverywhere.cpp | 23 +
examples/concepts/cpp/methods/Decreases.cpp | 12 +
.../cpp/methods/GhostMethodsAndVariables.cpp | 26 +
.../cpp/methods/GhostParamsAndResults.cpp | 21 +
.../concepts/cpp/methods/InlineFunction.cpp | 9 +
examples/concepts/cpp/methods/Permissions.cpp | 15 +
examples/concepts/cpp/methods/Predicates.cpp | 27 +
.../concepts/cpp/methods/PureGhostMethod.cpp | 10 +
project/antlr.sc | 9 +
res/universal/res/cpp/stdbool.h | 3 +
src/col/vct/col/ast/Node.scala | 80 +-
.../declaration/singular/VariableImpl.scala | 2 +-
.../ambiguous/AmbiguousSubscriptImpl.scala | 2 +
.../expr/context/AmbiguousResultImpl.scala | 6 +-
.../coercion/CoerceCPPArrayPointerImpl.scala | 7 +
.../CoerceCPPPrimitiveToColImpl.scala | 7 +
.../CoerceColToCPPPrimitiveImpl.scala | 7 +
.../ast/lang/CPPAbstractDeclarationImpl.scala | 7 +
.../col/ast/lang/CPPArrayDeclaratorImpl.scala | 9 +
src/col/vct/col/ast/lang/CPPBoolImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPCharImpl.scala | 8 +
.../vct/col/ast/lang/CPPDeclarationImpl.scala | 26 +
.../lang/CPPDeclarationSpecifierImpl.scala | 7 +
.../lang/CPPDeclarationStatementImpl.scala | 8 +
.../vct/col/ast/lang/CPPDeclaratorImpl.scala | 7 +
src/col/vct/col/ast/lang/CPPExprImpl.scala | 7 +
.../ast/lang/CPPFunctionDefinitionImpl.scala | 14 +
.../ast/lang/CPPGlobalDeclarationImpl.scala | 9 +
src/col/vct/col/ast/lang/CPPInitImpl.scala | 9 +
src/col/vct/col/ast/lang/CPPInlineImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPIntImpl.scala | 8 +
.../vct/col/ast/lang/CPPInvocationImpl.scala | 28 +
.../ast/lang/CPPLocalDeclarationImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPLocalImpl.scala | 32 +
src/col/vct/col/ast/lang/CPPLongImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPNameImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPParamImpl.scala | 9 +
.../ast/lang/CPPPointerDeclaratorImpl.scala | 9 +
src/col/vct/col/ast/lang/CPPPointerImpl.scala | 8 +
.../col/ast/lang/CPPPrimitiveTypeImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPPureImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPShortImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPSignedImpl.scala | 8 +
.../lang/CPPSpecificationModifierImpl.scala | 7 +
.../ast/lang/CPPSpecificationTypeImpl.scala | 8 +
.../vct/col/ast/lang/CPPStatementImpl.scala | 7 +
src/col/vct/col/ast/lang/CPPTArrayImpl.scala | 10 +
.../col/ast/lang/CPPTranslationUnitImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPTypeImpl.scala | 7 +
.../col/ast/lang/CPPTypeSpecifierImpl.scala | 7 +
.../lang/CPPTypedFunctionDeclaratorImpl.scala | 9 +
.../vct/col/ast/lang/CPPTypedefNameImpl.scala | 8 +
.../vct/col/ast/lang/CPPUnsignedImpl.scala | 8 +
src/col/vct/col/ast/lang/CPPVoidImpl.scala | 8 +
.../vct/col/ast/type/typeclass/TypeImpl.scala | 1 +
.../col/ast/util/CheckFoldUnfoldTarget.scala | 5 +
src/col/vct/col/feature/Feature.scala | 1 +
src/col/vct/col/feature/FeatureRainbow.scala | 31 +
src/col/vct/col/print/Ctx.scala | 2 +-
src/col/vct/col/print/Namer.scala | 4 +-
src/col/vct/col/resolve/ResolutionError.scala | 2 +-
src/col/vct/col/resolve/Resolve.scala | 30 +-
src/col/vct/col/resolve/ctx/Referrable.scala | 29 +-
src/col/vct/col/resolve/lang/C.scala | 1 -
src/col/vct/col/resolve/lang/CPP.scala | 113 ++
src/col/vct/col/resolve/lang/Spec.scala | 3 +
.../vct/col/rewrite/NonLatchingRewriter.scala | 7 +-
.../vct/col/typerules/CoercingRewriter.scala | 90 +-
src/col/vct/col/typerules/CoercionUtils.scala | 65 +
src/colhelper/ColDefs.scala | 10 +
src/main/vct/main/stages/Parsing.scala | 13 +-
src/main/vct/main/stages/Resolution.scala | 21 +-
src/main/vct/options/Options.scala | 5 +-
src/main/vct/options/types/ReadLanguage.scala | 2 +
src/main/vct/resources/Resources.scala | 8 +-
src/parsers/antlr4/CPPParser.g4 | 19 +
src/parsers/antlr4/LangCLexer.g4 | 1 +
src/parsers/antlr4/LangCPPLexer.g4 | 318 ++++
src/parsers/antlr4/LangCPPParser.g4 | 903 ++++++++++++
src/parsers/antlr4/LangJavaLexer.g4 | 1 +
src/parsers/antlr4/SpecLexer.g4 | 2 +-
src/parsers/vct/parsers/ColCPPParser.scala | 86 ++
src/parsers/vct/parsers/ColIPPParser.scala | 29 +
src/parsers/vct/parsers/ColIParser.scala | 1 -
.../vct/parsers/transform/CPPToCol.scala | 1296 +++++++++++++++++
.../vct/rewrite/lang/LangCPPToCol.scala | 254 ++++
.../vct/rewrite/lang/LangSpecificToCol.scala | 18 +-
.../vct/rewrite/lang/LangTypesToCol.scala | 71 +-
.../test/integration/examples/CPPSpec.scala | 23 +
98 files changed, 4309 insertions(+), 53 deletions(-)
create mode 100644 examples/concepts/cpp/Arrays.cpp
create mode 100644 examples/concepts/cpp/Conditionals.cpp
create mode 100644 examples/concepts/cpp/Loops.cpp
create mode 100644 examples/concepts/cpp/Operators.cpp
create mode 100644 examples/concepts/cpp/Pointers.cpp
create mode 100644 examples/concepts/cpp/Scoping.cpp
create mode 100644 examples/concepts/cpp/Types.cpp
create mode 100644 examples/concepts/cpp/methods/AbstractMethod.cpp
create mode 100644 examples/concepts/cpp/methods/ContextAndContextEverywhere.cpp
create mode 100644 examples/concepts/cpp/methods/Decreases.cpp
create mode 100644 examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp
create mode 100644 examples/concepts/cpp/methods/GhostParamsAndResults.cpp
create mode 100644 examples/concepts/cpp/methods/InlineFunction.cpp
create mode 100644 examples/concepts/cpp/methods/Permissions.cpp
create mode 100644 examples/concepts/cpp/methods/Predicates.cpp
create mode 100644 examples/concepts/cpp/methods/PureGhostMethod.cpp
create mode 100644 res/universal/res/cpp/stdbool.h
create mode 100644 src/col/vct/col/ast/family/coercion/CoerceCPPArrayPointerImpl.scala
create mode 100644 src/col/vct/col/ast/family/coercion/CoerceCPPPrimitiveToColImpl.scala
create mode 100644 src/col/vct/col/ast/family/coercion/CoerceColToCPPPrimitiveImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPAbstractDeclarationImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPArrayDeclaratorImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPBoolImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPCharImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPDeclarationImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPDeclarationSpecifierImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPDeclarationStatementImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPDeclaratorImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPExprImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPFunctionDefinitionImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPGlobalDeclarationImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPInitImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPInlineImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPIntImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPInvocationImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPLocalImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPLongImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPNameImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPParamImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPPointerDeclaratorImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPPointerImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPPrimitiveTypeImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPPureImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPShortImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPSignedImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPSpecificationModifierImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPSpecificationTypeImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPStatementImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPTArrayImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPTranslationUnitImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPTypeImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPTypeSpecifierImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPTypedFunctionDeclaratorImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPUnsignedImpl.scala
create mode 100644 src/col/vct/col/ast/lang/CPPVoidImpl.scala
create mode 100644 src/col/vct/col/resolve/lang/CPP.scala
create mode 100644 src/parsers/antlr4/CPPParser.g4
create mode 100644 src/parsers/antlr4/LangCPPLexer.g4
create mode 100644 src/parsers/antlr4/LangCPPParser.g4
create mode 100644 src/parsers/vct/parsers/ColCPPParser.scala
create mode 100644 src/parsers/vct/parsers/ColIPPParser.scala
create mode 100644 src/parsers/vct/parsers/transform/CPPToCol.scala
create mode 100644 src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
create mode 100644 test/main/vct/test/integration/examples/CPPSpec.scala
diff --git a/build.sc b/build.sc
index 8dfd16ba32..ab99aca15c 100644
--- a/build.sc
+++ b/build.sc
@@ -46,6 +46,7 @@ object parsers extends VercorsModule {
def generatedSources = T.sources {
Seq(
antlr.c.generate(),
+ antlr.cpp.generate(),
antlr.java.generate(),
antlr.pvl.generate()
)
diff --git a/examples/concepts/cpp/Arrays.cpp b/examples/concepts/cpp/Arrays.cpp
new file mode 100644
index 0000000000..a5c3696b16
--- /dev/null
+++ b/examples/concepts/cpp/Arrays.cpp
@@ -0,0 +1,23 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Loops
+//:: tools silicon
+//:: verdict Pass
+
+void test() {
+ // Not supported atm
+// int arr[10];
+ // assert \array(arr, 10);
+ // assert \pointer(arr, 10, write);
+// arr[5] = 8;
+ // assert arr[5] == 8;
+}
+
+//@ requires a != nullptr && size > 0;
+//@ context \pointer(a, size, read);
+//@ requires (\forall int i = 0 .. size; {: a[i] :} == 0);
+//@ ensures \result == b;
+int sumWithLast(int a[], int size, int b) {
+ int sum = a[size-1] + b;
+ //@ assert a[size-1] == 0;
+ return sum;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Conditionals.cpp b/examples/concepts/cpp/Conditionals.cpp
new file mode 100644
index 0000000000..3ed2e6bc18
--- /dev/null
+++ b/examples/concepts/cpp/Conditionals.cpp
@@ -0,0 +1,33 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Conditionals
+//:: tools silicon
+//:: verdict Pass
+
+void onlyAssignInIf() {
+ int num = 5;
+ int result;
+ if (num < 10) {
+ result = 10;
+ }
+ //@ assert result == 10;
+}
+
+void matchIf() {
+ int num = 5;
+ int result = 0;
+ if (num < 10) {
+ result = 10;
+ }
+ //@ assert result == 10;
+}
+
+void matchElse() {
+ int num = 5;
+ int result = 0;
+ if (num < 5) {
+ result = 10;
+ } else {
+ result = 20;
+ }
+ //@ assert result == 20;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Loops.cpp b/examples/concepts/cpp/Loops.cpp
new file mode 100644
index 0000000000..21470b7192
--- /dev/null
+++ b/examples/concepts/cpp/Loops.cpp
@@ -0,0 +1,37 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Loops
+//:: tools silicon
+//:: verdict Pass
+
+
+void whileLoop() {
+ int numLoops = 10;
+ //@ decreases numLoops;
+ //@ loop_invariant numLoops >= 0;
+ while(numLoops > 0) {
+ numLoops--;
+ }
+}
+
+// context_everywhere \pointer(arr, size + 1, read); -- does work for the foralll statement
+//@ context_everywhere \pointer(arr, size, read);
+void forArrayLoop(bool arr[], int size) {
+ bool sum = true;
+ //@ loop_invariant i >= 0 && i <= size;
+ //@ loop_invariant sum == (\forall int j; j >= 0 && j < i; arr[i]);
+ for(int i = 0; i < size; i++) {
+ sum = sum && arr[i];
+ }
+}
+
+void forLoop() {
+ int numLoops = 10;
+ int sum = 0;
+ //@ loop_invariant i >= 0 && i <= numLoops;
+ //@ decreases numLoops;
+ //@ loop_invariant sum == i * (i+1) / 2;
+ for(int i = 0; i < numLoops; i++) {
+ numLoops--;
+ sum += (i + 1);
+ }
+}
diff --git a/examples/concepts/cpp/Operators.cpp b/examples/concepts/cpp/Operators.cpp
new file mode 100644
index 0000000000..37e4da2ff6
--- /dev/null
+++ b/examples/concepts/cpp/Operators.cpp
@@ -0,0 +1,88 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Operators
+//:: tools silicon
+//:: verdict Pass
+
+void test() {
+
+ int num = 5;
+
+ int numPlus = num + 5;
+ //@ assert numPlus == 10;
+
+ int numMinus = num - 5;
+ //@ assert numMinus == 0;
+
+ int numMult = num * 5;
+ //@ assert numMult == 25;
+
+ int numDiv = num / 5;
+ //@ assert numDiv == 1;
+
+ int numMod = num % 5;
+ //@ assert numMod == 0;
+
+ num++;
+ //@ assert num == 6;
+
+ num--;
+ //@ assert num == 5;
+
+ num += 5;
+ //@ assert num == 10;
+
+ num -= 5;
+ //@ assert num == 5;
+
+ num *= 5;
+ //@ assert num == 25;
+
+ num /= 5;
+ //@ assert num == 5;
+
+ num %= 5;
+ //@ assert num == 0;
+
+ int numMinus2 = -5;
+ //@ assert numMinus2 == -5;
+
+ int numPlus2 = +5;
+ //@ assert numPlus2 == 5;
+
+ bool boolean = true;
+
+ bool booleanNot = !boolean;
+ //@ assert booleanNot == false;
+
+ bool booleanNot2 = not boolean;
+ //@ assert booleanNot2 == false;
+
+ bool booleanAnd = boolean && false;
+ //@ assert booleanAnd == false;
+
+ bool booleanOr = boolean || false;
+ //@ assert booleanOr == true;
+
+ bool booleanEquals = boolean == true;
+ //@ assert booleanEquals == true;
+
+ bool booleanNotEquals = boolean != true;
+ //@ assert booleanNotEquals == false;
+
+ num = 5;
+
+ bool booleanLess = num < 6;
+ //@ assert booleanLess == true;
+
+ bool booleanLessEq = num <= 5;
+ //@ assert booleanLessEq == true;
+
+ bool booleanGreater = num > 4;
+ //@ assert booleanGreater == true;
+
+ bool booleanGreaterEq = num >= 5;
+ //@ assert booleanGreaterEq == true;
+
+ //@ assert 4 - 3 - 2 - 1 == (((4 - 3) - 2) - 1);
+
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Pointers.cpp b/examples/concepts/cpp/Pointers.cpp
new file mode 100644
index 0000000000..2806e4777f
--- /dev/null
+++ b/examples/concepts/cpp/Pointers.cpp
@@ -0,0 +1,36 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Pointers
+//:: tools silicon
+//:: verdict Pass
+
+// Examples taken from https://en.cppreference.com/w/cpp/language/pointer
+
+
+// &x is not supported but I do need it for SYCL buffers
+//@ context \pointer(ints, size, write);
+void test(int ints[], int size, int* p) {
+ // char x = 'a';
+ // char* charPtr = &x;
+ // assert *charPtr == x;
+
+ int arr[5];
+ // int* arrPtr[5] = &arr;
+ // assert arrPtr[4] == arr[4];
+
+// Does not support arrays containing pointers?
+// int* ptrArr[5];
+// ptrArr[2] = p;
+
+
+ void* voidPtr = nullptr;
+
+ int n;
+ // int* p = &n;
+ // *p = 10;
+ // assert n == 10;
+
+ if (size >= 4) {
+ ints[3] = 5;
+ }
+ //@ assert size >= 4 ==> ints[3] == 5;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Scoping.cpp b/examples/concepts/cpp/Scoping.cpp
new file mode 100644
index 0000000000..93a0bc3e8e
--- /dev/null
+++ b/examples/concepts/cpp/Scoping.cpp
@@ -0,0 +1,17 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Scoping
+//:: tools silicon
+//:: verdict Pass
+void test() {
+ int a = 10;
+ int b = 10;
+
+ { // CompoundStatement { statements }
+ a = 20;
+ int b = 20;
+ //@ assert a == 20;
+ //@ assert b == 20;
+ }
+ //@ assert a == 20;
+ //@ assert b == 10;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Types.cpp b/examples/concepts/cpp/Types.cpp
new file mode 100644
index 0000000000..faa28e7d79
--- /dev/null
+++ b/examples/concepts/cpp/Types.cpp
@@ -0,0 +1,19 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Types
+//:: tools silicon
+//:: verdict Pass
+
+void test() {
+ bool aBool = true;
+
+ int anInt = 5;
+ //short aShort = 5;
+ long aLong = 5;
+ double aDouble = 5.1;
+ float aFloat = 5.1;
+
+ char aChar = 'a';
+// char aCharArray[] = "Hello there";
+
+ void* voidPtr = nullptr;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/methods/AbstractMethod.cpp b/examples/concepts/cpp/methods/AbstractMethod.cpp
new file mode 100644
index 0000000000..c47b09298a
--- /dev/null
+++ b/examples/concepts/cpp/methods/AbstractMethod.cpp
@@ -0,0 +1,13 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases AbstractMethod
+//:: tools silicon
+//:: verdict Pass
+
+/*@ ghost
+ ensures \result == a >= 0;
+ bool isPositive(int a);
+*/
+
+//@ requires b != 0;
+//@ ensures \result == a / b;
+int div(int a, int b);
\ No newline at end of file
diff --git a/examples/concepts/cpp/methods/ContextAndContextEverywhere.cpp b/examples/concepts/cpp/methods/ContextAndContextEverywhere.cpp
new file mode 100644
index 0000000000..1624f1dce1
--- /dev/null
+++ b/examples/concepts/cpp/methods/ContextAndContextEverywhere.cpp
@@ -0,0 +1,23 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases ContextAndContextEverywhere
+//:: tools silicon
+//:: verdict Pass
+
+//@ context b != 0;
+// requires b != 0;
+// ensures b != 0;
+int div(int a, int b) {
+ return a / b;
+}
+
+//@ context_everywhere number > 0;
+// requires number > 0;
+// ensures number > 0;
+int factorial(int number) {
+ int result = 1;
+ // loop_invariant number > 0;
+ for(int i = 2; i <= number; i++) {
+ result *= i;
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/methods/Decreases.cpp b/examples/concepts/cpp/methods/Decreases.cpp
new file mode 100644
index 0000000000..f5dfdeee49
--- /dev/null
+++ b/examples/concepts/cpp/methods/Decreases.cpp
@@ -0,0 +1,12 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Decreases
+//:: tools silicon
+//:: verdict Pass
+
+//@ decreases number;
+int factorial(int number) {
+ if (number <= 1) {
+ return 1;
+ }
+ return number * factorial(number - 1);
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp b/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp
new file mode 100644
index 0000000000..d248c2e7a0
--- /dev/null
+++ b/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp
@@ -0,0 +1,26 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases GhostMethodsAndVariables
+//:: tools silicon
+//:: verdict Pass
+
+/*@ ghost
+ ensures \result == (current && a >= 0);
+ bool isPositive(bool current, int a) {
+ return current && a >= 0;
+ }
+*/
+
+//@ context_everywhere \pointer(a, size, read);
+int sum(int a[], int size) {
+ //@ ghost bool positive = true;
+ int result = 0;
+ //@ loop_invariant i >= 0 && i <= size;
+ //@ loop_invariant positive ==> (\forall int j = 0 .. i; a[j] >= 0);
+ //@ loop_invariant (\forall int j = 0 .. i; a[j] >= 0) ==> result >= 0;
+ for(int i = 0; i < size; i++) {
+ //@ ghost positive = isPositive(positive, a[i]);
+ result += a[i];
+ }
+ //@ assert positive ==> result >= 0;
+ return result;
+}
diff --git a/examples/concepts/cpp/methods/GhostParamsAndResults.cpp b/examples/concepts/cpp/methods/GhostParamsAndResults.cpp
new file mode 100644
index 0000000000..89c7456435
--- /dev/null
+++ b/examples/concepts/cpp/methods/GhostParamsAndResults.cpp
@@ -0,0 +1,21 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases GhostParamsAndResults
+//:: tools silicon
+//:: verdict Pass
+
+/*@
+ given int min;
+ yields bool all_ge_min;
+ requires min >= 0;
+ ensures all_ge_min ==> \result >= min * 2;
+*/
+int add(int a, int b) {
+ //@ ghost all_ge_min = a >= min && b >= min;
+ return a + b;
+}
+
+int caller(int a, int b) {
+ //@ ghost bool items_ge_5;
+ int result = add(a, b) /*@ given { min = 5 } */ /*@ yields { items_ge_5 = all_ge_min } */ ;
+ return result;
+}
diff --git a/examples/concepts/cpp/methods/InlineFunction.cpp b/examples/concepts/cpp/methods/InlineFunction.cpp
new file mode 100644
index 0000000000..04b5ed9576
--- /dev/null
+++ b/examples/concepts/cpp/methods/InlineFunction.cpp
@@ -0,0 +1,9 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases InlineFunction
+//:: tools silicon
+//:: verdict Pass
+
+//@ inline pure bool isPositive(int a) = (a >= 0);
+
+//@ requires isPositive(number);
+bool incr(int number);
\ No newline at end of file
diff --git a/examples/concepts/cpp/methods/Permissions.cpp b/examples/concepts/cpp/methods/Permissions.cpp
new file mode 100644
index 0000000000..3f06a001bd
--- /dev/null
+++ b/examples/concepts/cpp/methods/Permissions.cpp
@@ -0,0 +1,15 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Permissions
+//:: tools silicon
+//:: verdict Pass
+
+
+int amount = 0;
+
+//@ requires Perm(amount, 1);
+//@ ensures Perm(amount, 1) ** amount == x;
+void set(int x) {
+ amount = x;
+}
+
+
diff --git a/examples/concepts/cpp/methods/Predicates.cpp b/examples/concepts/cpp/methods/Predicates.cpp
new file mode 100644
index 0000000000..b3c65d7d94
--- /dev/null
+++ b/examples/concepts/cpp/methods/Predicates.cpp
@@ -0,0 +1,27 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Predicates
+//:: tools silicon
+//:: verdict Pass
+
+int amount = 0;
+
+//@ resource pre_state() = Perm(amount, write);
+//@ resource state(int value) = Perm(amount, write) ** amount == value;
+
+//@ requires pre_state();
+//@ ensures state(x);
+void set(int x) {
+ // pre_state();
+ //@ unfold pre_state();
+ // Perm(amount, write);
+ amount = x;
+ // Perm(amount, write) ** amount == x;
+ //@ fold state(x);
+ // state(x);
+}
+
+//@ requires pre_state();
+//@ ensures state(50);
+void manageAccount() {
+ set(50);
+}
diff --git a/examples/concepts/cpp/methods/PureGhostMethod.cpp b/examples/concepts/cpp/methods/PureGhostMethod.cpp
new file mode 100644
index 0000000000..55231fd64a
--- /dev/null
+++ b/examples/concepts/cpp/methods/PureGhostMethod.cpp
@@ -0,0 +1,10 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases PureGhostMethod
+//:: tools silicon
+//:: verdict Pass
+
+/*@
+ ensures \result == a >= 0;
+ pure bool isPositive(int a) = a >= 0;
+*/
+
diff --git a/project/antlr.sc b/project/antlr.sc
index a306c3cec2..4b597104bd 100644
--- a/project/antlr.sc
+++ b/project/antlr.sc
@@ -58,6 +58,15 @@ object c extends GenModule {
)
}
+object cpp extends GenModule {
+ def lexer = "LangCPPLexer.g4"
+ def parser = "CPPParser.g4"
+ def deps = Seq(
+ "SpecParser.g4", "SpecLexer.g4",
+ "LangCPPParser.g4", "LangCPPLexer.g4"
+ )
+}
+
object java extends GenModule {
def lexer = "LangJavaLexer.g4"
def parser = "JavaParser.g4"
diff --git a/res/universal/res/cpp/stdbool.h b/res/universal/res/cpp/stdbool.h
new file mode 100644
index 0000000000..c82a3f85b6
--- /dev/null
+++ b/res/universal/res/cpp/stdbool.h
@@ -0,0 +1,3 @@
+#define bool _Bool
+#define true 1
+#define false 0
diff --git a/src/col/vct/col/ast/Node.scala b/src/col/vct/col/ast/Node.scala
index afb5c15f79..487d2802c8 100644
--- a/src/col/vct/col/ast/Node.scala
+++ b/src/col/vct/col/ast/Node.scala
@@ -17,7 +17,6 @@ import vct.col.ast.expr.ambiguous._
import vct.col.ast.expr.apply._
import vct.col.ast.expr.binder._
import vct.col.ast.expr.bip._
-import vct.col.ast.family.coercion._
import vct.col.ast.expr.context._
import vct.col.ast.expr.heap.alloc._
import vct.col.ast.expr.heap.read._
@@ -42,9 +41,12 @@ import vct.col.ast.expr.resource._
import vct.col.ast.expr.sideeffect._
import vct.col.ast.family.accountedpredicate._
import vct.col.ast.family.bipdata._
+import vct.col.ast.family.bipglueelement._
+import vct.col.ast.family.bipporttype._
import vct.col.ast.family.catchclause._
import vct.col.ast.family.coercion._
import vct.col.ast.family.contract._
+import vct.col.ast.family.data._
import vct.col.ast.family.decreases._
import vct.col.ast.family.fieldflag._
import vct.col.ast.family.invoking._
@@ -54,9 +56,6 @@ import vct.col.ast.family.location._
import vct.col.ast.family.loopcontract._
import vct.col.ast.family.parregion._
import vct.col.ast.family.signals._
-import vct.col.ast.family.bipglueelement._
-import vct.col.ast.family.bipporttype._
-import vct.col.ast.family.data._
import vct.col.ast.lang._
import vct.col.ast.lang.smt._
import vct.col.ast.node._
@@ -67,15 +66,10 @@ import vct.col.ast.statement.nonexecutable._
import vct.col.ast.statement.terminal._
import vct.col.ast.statement.veymont._
import vct.col.ast.util.Declarator
-import vct.col.debug._
import vct.col.origin._
-import vct.col.ref.{DirectRef, Ref}
-import vct.col.resolve._
+import vct.col.ref.Ref
import vct.col.resolve.ctx._
import vct.col.resolve.lang.JavaAnnotationData
-import vct.col.resolve.lang.Java
-import vct.col.typerules.{CoercionUtils, Types}
-import vct.result.VerificationError.Unreachable
/** @inheritdoc */ sealed trait Node[G] extends NodeImpl[G]
@@ -354,6 +348,7 @@ final case class CoerceNullPointer[G](pointerElementType: Type[G])(implicit val
final case class CoerceNullEnum[G](targetEnum: Ref[G, Enum[G]])(implicit val o: Origin) extends Coercion[G] with CoerceNullEnumImpl[G]
final case class CoerceCArrayPointer[G](elementType: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceCArrayPointerImpl[G]
+final case class CoerceCPPArrayPointer[G](elementType: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceCPPArrayPointerImpl[G]
final case class CoerceFracZFrac[G]()(implicit val o: Origin) extends Coercion[G] with CoerceFracZFracImpl[G]
final case class CoerceZFracRat[G]()(implicit val o: Origin) extends Coercion[G] with CoerceZFracRatImpl[G]
@@ -377,6 +372,9 @@ final case class CoerceJavaClassAnyClass[G](sourceClass: Ref[G, JavaClassOrInter
final case class CoerceCPrimitiveToCol[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceCPrimitiveToColImpl[G]
final case class CoerceColToCPrimitive[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceColToCPrimitiveImpl[G]
+final case class CoerceCPPPrimitiveToCol[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceCPPPrimitiveToColImpl[G]
+final case class CoerceColToCPPPrimitive[G](source: Type[G], target: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceColToCPPPrimitiveImpl[G]
+
final case class CoerceMapOption[G](inner: Coercion[G], sourceOptionElement: Type[G], targetOptionElement: Type[G])(implicit val o: Origin) extends Coercion[G] with CoerceMapOptionImpl[G]
final case class CoerceMapTuple[G](inner: Seq[Coercion[G]], sourceTypes: Seq[Type[G]], targetTypes: Seq[Type[G]])(implicit val o: Origin) extends Coercion[G] with CoerceMapTupleImpl[G]
final case class CoerceMapEither[G](inner: (Coercion[G], Coercion[G]), sourceTypes: (Type[G], Type[G]), targetTypes: (Type[G], Type[G]))(implicit val o: Origin) extends Coercion[G] with CoerceMapEitherImpl[G]
@@ -953,6 +951,68 @@ final case class CTPointer[G](innerType: Type[G])(implicit val o: Origin = Diagn
final case class CTArray[G](size: Option[Expr[G]], innerType: Type[G])(val blame: Blame[ArraySizeError])(implicit val o: Origin = DiagnosticOrigin) extends CType[G] with CTArrayImpl[G]
final case class CTCudaVec[G]()(implicit val o: Origin = DiagnosticOrigin) extends CType[G] with CTCudaVecImpl[G]
+sealed trait CPPDeclarationSpecifier[G] extends NodeFamily[G] with CPPDeclarationSpecifierImpl[G]
+
+sealed trait CPPSpecificationModifier[G] extends CPPDeclarationSpecifier[G] with CPPSpecificationModifierImpl[G]
+final case class CPPPure[G]()(implicit val o: Origin) extends CPPSpecificationModifier[G] with CPPPureImpl[G]
+final case class CPPInline[G]()(implicit val o: Origin) extends CPPSpecificationModifier[G] with CPPInlineImpl[G]
+
+sealed trait CPPTypeSpecifier[G] extends CPPDeclarationSpecifier[G] with CPPTypeSpecifierImpl[G]
+final case class CPPVoid[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPVoidImpl[G]
+final case class CPPChar[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPCharImpl[G]
+final case class CPPShort[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPShortImpl[G]
+final case class CPPInt[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPIntImpl[G]
+final case class CPPLong[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPLongImpl[G]
+final case class CPPSigned[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPSignedImpl[G]
+final case class CPPUnsigned[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPUnsignedImpl[G]
+final case class CPPBool[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPBoolImpl[G]
+final case class CPPTypedefName[G](name: String)(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPTypedefNameImpl[G] {
+ var ref: Option[CPPTypeNameTarget[G]] = None
+}
+
+final case class CPPSpecificationType[G](t: Type[G])(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPSpecificationTypeImpl[G]
+
+final case class CPPPointer[G]()(implicit val o: Origin) extends NodeFamily[G] with CPPPointerImpl[G]
+
+final class CPPParam[G](val specifiers: Seq[CPPDeclarationSpecifier[G]], val declarator: CPPDeclarator[G])(implicit val o: Origin) extends Declaration[G] with CPPParamImpl[G]
+
+sealed trait CPPDeclarator[G] extends NodeFamily[G] with CPPDeclaratorImpl[G]
+final case class CPPPointerDeclarator[G](pointers: Seq[CPPPointer[G]], inner: CPPDeclarator[G])(implicit val o: Origin) extends CPPDeclarator[G] with CPPPointerDeclaratorImpl[G]
+final case class CPPArrayDeclarator[G](inner: CPPDeclarator[G], size: Option[Expr[G]])(val blame: Blame[ArraySizeError])(implicit val o: Origin) extends CPPDeclarator[G] with CPPArrayDeclaratorImpl[G]
+final case class CPPTypedFunctionDeclarator[G](params: Seq[CPPParam[G]], varargs: Boolean, inner: CPPDeclarator[G])(implicit val o: Origin) extends CPPDeclarator[G] with CPPTypedFunctionDeclaratorImpl[G]
+final case class CPPName[G](name: String)(implicit val o: Origin) extends CPPDeclarator[G] with CPPNameImpl[G]
+
+final case class CPPInit[G](decl: CPPDeclarator[G], init: Option[Expr[G]])(implicit val o: Origin) extends NodeFamily[G] with CPPInitImpl[G] {
+ var ref: Option[RefCPPFunctionDefinition[G]] = None
+}
+
+final case class CPPDeclaration[G](val contract: ApplicableContract[G], val specs: Seq[CPPDeclarationSpecifier[G]], val inits: Seq[CPPInit[G]])(implicit val o: Origin) extends NodeFamily[G] with CPPDeclarationImpl[G]
+
+final class CPPTranslationUnit[G](val declarations: Seq[GlobalDeclaration[G]])(implicit val o: Origin) extends GlobalDeclaration[G] with Declarator[G] with CPPTranslationUnitImpl[G]
+
+sealed trait CPPAbstractDeclaration[G] extends GlobalDeclaration[G] with CPPAbstractDeclarationImpl[G]
+
+final class CPPGlobalDeclaration[G](val decl: CPPDeclaration[G])(implicit val o: Origin) extends CPPAbstractDeclaration[G] with CPPGlobalDeclarationImpl[G]
+final class CPPLocalDeclaration[G](val decl: CPPDeclaration[G])(implicit val o: Origin) extends Declaration[G] with CPPLocalDeclarationImpl[G]
+final class CPPFunctionDefinition[G](val contract: ApplicableContract[G], val specs: Seq[CPPDeclarationSpecifier[G]], val declarator: CPPDeclarator[G], val body: Statement[G])(val blame: Blame[CallableFailure])(implicit val o: Origin) extends GlobalDeclaration[G] with CPPFunctionDefinitionImpl[G] {
+ var ref: Option[RefCPPGlobalDeclaration[G]] = None
+}
+
+sealed trait CPPStatement[G] extends Statement[G] with CPPStatementImpl[G]
+final case class CPPDeclarationStatement[G](decl: CPPLocalDeclaration[G])(implicit val o: Origin) extends CPPStatement[G] with CPPDeclarationStatementImpl[G]
+
+sealed trait CPPExpr[G] extends Expr[G] with CPPExprImpl[G]
+final case class CPPLocal[G](name: String)(val blame: Blame[DerefInsufficientPermission])(implicit val o: Origin) extends CPPExpr[G] with CPPLocalImpl[G] {
+ var ref: Option[CPPNameTarget[G]] = None
+}
+final case class CPPInvocation[G](applicable: Expr[G], args: Seq[Expr[G]], givenArgs: Seq[(Ref[G, Variable[G]], Expr[G])], yields: Seq[(Expr[G], Ref[G, Variable[G]])])(val blame: Blame[FrontendInvocationError])(implicit val o: Origin) extends CPPExpr[G] with CPPInvocationImpl[G] {
+ var ref: Option[CPPInvocationTarget[G]] = None
+}
+
+sealed trait CPPType[G] extends Type[G] with CPPTypeImpl[G]
+final case class CPPPrimitiveType[G](specifiers: Seq[CPPDeclarationSpecifier[G]])(implicit val o: Origin = DiagnosticOrigin) extends CPPType[G] with CPPPrimitiveTypeImpl[G]
+final case class CPPTArray[G](size: Option[Expr[G]], innerType: Type[G])(val blame: Blame[ArraySizeError])(implicit val o: Origin = DiagnosticOrigin) extends CPPType[G] with CPPTArrayImpl[G]
+
final case class JavaName[G](names: Seq[String])(implicit val o: Origin) extends NodeFamily[G] with JavaNameImpl[G] {
var ref: Option[JavaTypeNameTarget[G]] = None
}
diff --git a/src/col/vct/col/ast/declaration/singular/VariableImpl.scala b/src/col/vct/col/ast/declaration/singular/VariableImpl.scala
index a4b634273b..78f8c2d855 100644
--- a/src/col/vct/col/ast/declaration/singular/VariableImpl.scala
+++ b/src/col/vct/col/ast/declaration/singular/VariableImpl.scala
@@ -5,7 +5,7 @@ import vct.col.print._
trait VariableImpl[G] { this: Variable[G] =>
override def layout(implicit ctx: Ctx): Doc = ctx.syntax match {
- case Ctx.C | Ctx.Cuda | Ctx.OpenCL =>
+ case Ctx.C | Ctx.Cuda | Ctx.OpenCL | Ctx.CPP =>
val (spec, decl) = t.layoutSplitDeclarator
spec <+> decl <> ctx.name(this)
case Ctx.PVL | Ctx.Java => t.show <+> ctx.name(this)
diff --git a/src/col/vct/col/ast/expr/ambiguous/AmbiguousSubscriptImpl.scala b/src/col/vct/col/ast/expr/ambiguous/AmbiguousSubscriptImpl.scala
index f61023d4eb..92e0362557 100644
--- a/src/col/vct/col/ast/expr/ambiguous/AmbiguousSubscriptImpl.scala
+++ b/src/col/vct/col/ast/expr/ambiguous/AmbiguousSubscriptImpl.scala
@@ -9,6 +9,7 @@ trait AmbiguousSubscriptImpl[G] { this: AmbiguousSubscript[G] =>
def isSeqOp: Boolean = CoercionUtils.getAnySeqCoercion(collection.t).isDefined
def isArrayOp: Boolean = CoercionUtils.getAnyArrayCoercion(collection.t).isDefined
def isCArrayOp: Boolean = CoercionUtils.getAnyCArrayCoercion(collection.t).isDefined
+ def isCPPArrayOp: Boolean = CoercionUtils.getAnyCPPArrayCoercion(collection.t).isDefined
def isPointerOp: Boolean = CoercionUtils.getAnyPointerCoercion(collection.t).isDefined
def isMapOp: Boolean = CoercionUtils.getAnyMapCoercion(collection.t).isDefined
@@ -16,6 +17,7 @@ trait AmbiguousSubscriptImpl[G] { this: AmbiguousSubscript[G] =>
if (isSeqOp) collection.t.asSeq.get.element
else if (isArrayOp) collection.t.asArray.get.element
else if (isCArrayOp) collection.t.asCArray.get.innerType
+ else if (isCPPArrayOp) collection.t.asCPPArray.get.innerType
else if (isPointerOp) collection.t.asPointer.get.element
else if (isMapOp) collection.t.asMap.get.value
else throw Unreachable(s"Trying to subscript ($this) a non subscriptable variable with type ${collection.t}")
diff --git a/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala b/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala
index 5eaddc9763..efff4cd4eb 100644
--- a/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala
+++ b/src/col/vct/col/ast/expr/context/AmbiguousResultImpl.scala
@@ -6,7 +6,7 @@ import vct.col.check.{CheckContext, CheckError, ResultOutsidePostcondition}
import vct.col.err
import vct.col.print._
import vct.col.resolve.ctx._
-import vct.col.resolve.lang.C
+import vct.col.resolve.lang.{C, CPP}
trait AmbiguousResultImpl[G] extends NodeFamilyImpl[G] { this: AmbiguousResult[G] =>
override lazy val t: Type[G] = ref.getOrElse(
@@ -15,6 +15,10 @@ trait AmbiguousResultImpl[G] extends NodeFamilyImpl[G] { this: AmbiguousResult[G
C.typeOrReturnTypeFromDeclaration(decl.specs, decl.declarator)
case RefCGlobalDeclaration(decls, initIdx) =>
C.typeOrReturnTypeFromDeclaration(decls.decl.specs, decls.decl.inits(initIdx).decl)
+ case RefCPPFunctionDefinition(decl) =>
+ CPP.typeOrReturnTypeFromDeclaration(decl.specs, decl.declarator)
+ case RefCPPGlobalDeclaration(decls, initIdx) =>
+ CPP.typeOrReturnTypeFromDeclaration(decls.decl.specs, decls.decl.inits(initIdx).decl)
case RefFunction(decl) => decl.returnType
case RefProcedure(decl) => decl.returnType
case RefJavaMethod(decl) => decl.returnType
diff --git a/src/col/vct/col/ast/family/coercion/CoerceCPPArrayPointerImpl.scala b/src/col/vct/col/ast/family/coercion/CoerceCPPArrayPointerImpl.scala
new file mode 100644
index 0000000000..f424079e17
--- /dev/null
+++ b/src/col/vct/col/ast/family/coercion/CoerceCPPArrayPointerImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.family.coercion
+
+import vct.col.ast.{CoerceCPPArrayPointer, TPointer}
+
+trait CoerceCPPArrayPointerImpl[G] { this: CoerceCPPArrayPointer[G] =>
+ override def target: TPointer[G] = TPointer(elementType)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/family/coercion/CoerceCPPPrimitiveToColImpl.scala b/src/col/vct/col/ast/family/coercion/CoerceCPPPrimitiveToColImpl.scala
new file mode 100644
index 0000000000..69a4f1ecf9
--- /dev/null
+++ b/src/col/vct/col/ast/family/coercion/CoerceCPPPrimitiveToColImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.family.coercion
+
+import vct.col.ast.CoerceCPPPrimitiveToCol
+
+trait CoerceCPPPrimitiveToColImpl[G] { this: CoerceCPPPrimitiveToCol[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/family/coercion/CoerceColToCPPPrimitiveImpl.scala b/src/col/vct/col/ast/family/coercion/CoerceColToCPPPrimitiveImpl.scala
new file mode 100644
index 0000000000..263a5fb505
--- /dev/null
+++ b/src/col/vct/col/ast/family/coercion/CoerceColToCPPPrimitiveImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.family.coercion
+
+import vct.col.ast.CoerceColToCPPPrimitive
+
+trait CoerceColToCPPPrimitiveImpl[G] { this: CoerceColToCPPPrimitive[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPAbstractDeclarationImpl.scala b/src/col/vct/col/ast/lang/CPPAbstractDeclarationImpl.scala
new file mode 100644
index 0000000000..0998d2988d
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPAbstractDeclarationImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPAbstractDeclaration
+
+trait CPPAbstractDeclarationImpl[G] { this: CPPAbstractDeclaration[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPArrayDeclaratorImpl.scala b/src/col/vct/col/ast/lang/CPPArrayDeclaratorImpl.scala
new file mode 100644
index 0000000000..4fcad5e33b
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPArrayDeclaratorImpl.scala
@@ -0,0 +1,9 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPArrayDeclarator
+import vct.col.print.{Ctx, Doc, Group}
+
+trait CPPArrayDeclaratorImpl[G] { this: CPPArrayDeclarator[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ Group(inner.show <> "[" <> Doc.arg(Doc.stack(size.toSeq)) <> "]")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPBoolImpl.scala b/src/col/vct/col/ast/lang/CPPBoolImpl.scala
new file mode 100644
index 0000000000..4ee8f9efb6
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPBoolImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPBool
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPBoolImpl[G] { this: CPPBool[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("_Bool")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPCharImpl.scala b/src/col/vct/col/ast/lang/CPPCharImpl.scala
new file mode 100644
index 0000000000..acc57512be
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPCharImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPChar
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPCharImpl[G] { this: CPPChar[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("char")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPDeclarationImpl.scala b/src/col/vct/col/ast/lang/CPPDeclarationImpl.scala
new file mode 100644
index 0000000000..f901e91714
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPDeclarationImpl.scala
@@ -0,0 +1,26 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPDeclaration
+import vct.col.print._
+
+trait CPPDeclarationImpl[G] { this: CPPDeclaration[G] =>
+ // PB: Please keep in sync with ApplicableContractImpl
+ def layoutContract(implicit ctx: Ctx): Doc =
+ Doc.stack(Seq(
+ Doc.stack(contract.givenArgs.map(Text("given") <+> _.show <> ";")),
+ Doc.stack(contract.yieldsArgs.map(Text("yields") <+> _.show <> ";")),
+ DocUtil.clauses("context_everywhere", contract.contextEverywhere),
+ DocUtil.clauses("requires", contract.requires),
+ Doc.stack(contract.decreases.toSeq),
+ DocUtil.clauses("ensures", contract.ensures),
+ Doc.stack(contract.signals),
+ ))
+
+ override def layout(implicit ctx: Ctx): Doc =
+ Doc.stack(Seq(
+ layoutContract,
+ Group(
+ Doc.spread(specs) <>> Doc.args(inits)
+ ),
+ ))
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPDeclarationSpecifierImpl.scala b/src/col/vct/col/ast/lang/CPPDeclarationSpecifierImpl.scala
new file mode 100644
index 0000000000..938805162d
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPDeclarationSpecifierImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPDeclarationSpecifier
+
+trait CPPDeclarationSpecifierImpl[G] { this: CPPDeclarationSpecifier[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPDeclarationStatementImpl.scala b/src/col/vct/col/ast/lang/CPPDeclarationStatementImpl.scala
new file mode 100644
index 0000000000..a22698c559
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPDeclarationStatementImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPDeclarationStatement
+import vct.col.print.{Ctx, Doc}
+
+trait CPPDeclarationStatementImpl[G] { this: CPPDeclarationStatement[G] =>
+ override def layout(implicit ctx: Ctx): Doc = decl.show <> ";"
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPDeclaratorImpl.scala b/src/col/vct/col/ast/lang/CPPDeclaratorImpl.scala
new file mode 100644
index 0000000000..0bbabca1d4
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPDeclaratorImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPDeclarator
+
+trait CPPDeclaratorImpl[G] { this: CPPDeclarator[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPExprImpl.scala b/src/col/vct/col/ast/lang/CPPExprImpl.scala
new file mode 100644
index 0000000000..de4c24348b
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPExprImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPExpr
+
+trait CPPExprImpl[G] { this: CPPExpr[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPFunctionDefinitionImpl.scala b/src/col/vct/col/ast/lang/CPPFunctionDefinitionImpl.scala
new file mode 100644
index 0000000000..645cc52967
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPFunctionDefinitionImpl.scala
@@ -0,0 +1,14 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPFunctionDefinition
+import vct.col.print.{Ctx, Doc, Group}
+
+trait CPPFunctionDefinitionImpl[G] { this: CPPFunctionDefinition[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ Doc.stack(Seq(
+ contract,
+ Group(
+ Doc.spread(specs) <>> declarator
+ ) <+> body.layoutAsBlock,
+ ))
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPGlobalDeclarationImpl.scala b/src/col/vct/col/ast/lang/CPPGlobalDeclarationImpl.scala
new file mode 100644
index 0000000000..c178df89fa
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPGlobalDeclarationImpl.scala
@@ -0,0 +1,9 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPGlobalDeclaration
+import vct.col.print._
+
+trait CPPGlobalDeclarationImpl[G] { this: CPPGlobalDeclaration[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ decl.show <> ";"
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPInitImpl.scala b/src/col/vct/col/ast/lang/CPPInitImpl.scala
new file mode 100644
index 0000000000..901bc2e3b6
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPInitImpl.scala
@@ -0,0 +1,9 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPInit
+import vct.col.print.{Ctx, Doc, Group}
+
+trait CPPInitImpl[G] { this: CPPInit[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ if(init.isEmpty) decl.show else Group(decl.show <+> "=" <>> init.get)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPInlineImpl.scala b/src/col/vct/col/ast/lang/CPPInlineImpl.scala
new file mode 100644
index 0000000000..5894e5bed8
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPInlineImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPInline
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPInlineImpl[G] { this: CPPInline[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("inline")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPIntImpl.scala b/src/col/vct/col/ast/lang/CPPIntImpl.scala
new file mode 100644
index 0000000000..5a72d5ae25
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPIntImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPInt
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPIntImpl[G] { this: CPPInt[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("int")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPInvocationImpl.scala b/src/col/vct/col/ast/lang/CPPInvocationImpl.scala
new file mode 100644
index 0000000000..e08c12b319
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPInvocationImpl.scala
@@ -0,0 +1,28 @@
+package vct.col.ast.lang
+
+import vct.col.ast.{CPPInvocation, Type}
+import vct.col.print._
+import vct.col.resolve.ctx._
+import vct.col.resolve.lang.CPP
+import vct.result.VerificationError.Unreachable
+
+trait CPPInvocationImpl[G] { this: CPPInvocation[G] =>
+ override lazy val t: Type[G] = ref.get match {
+ case RefFunction(decl) => decl.returnType
+ case RefProcedure(decl) => decl.returnType
+ case RefPredicate(decl) => decl.returnType
+ case RefADTFunction(decl) => decl.returnType
+ case RefModelProcess(decl) => decl.returnType
+ case RefModelAction(decl) => decl.returnType
+ case RefCPPFunctionDefinition(decl) => CPP.typeOrReturnTypeFromDeclaration(decl.specs, decl.declarator)
+ case RefCPPGlobalDeclaration(decls, initIdx) => CPP.typeOrReturnTypeFromDeclaration(decls.decl.specs, decls.decl.inits(initIdx).decl)
+ case RefInstanceMethod(decl) => decl.returnType
+ case RefInstanceFunction(decl) => decl.returnType
+ case RefInstancePredicate(decl) => decl.returnType
+ }
+
+ override def precedence: Int = Precedence.POSTFIX
+
+ override def layout(implicit ctx: Ctx): Doc =
+ Group(assoc(applicable) <> "(" <> Doc.args(args) <> ")" <> DocUtil.givenYields(givenArgs, yields))
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala b/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala
new file mode 100644
index 0000000000..30860d3502
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPLocalDeclaration
+import vct.col.print.{Ctx, Doc}
+
+trait CPPLocalDeclarationImpl[G] { this: CPPLocalDeclaration[G] =>
+ override def layout(implicit ctx: Ctx): Doc = decl.show <> ";"
+}
diff --git a/src/col/vct/col/ast/lang/CPPLocalImpl.scala b/src/col/vct/col/ast/lang/CPPLocalImpl.scala
new file mode 100644
index 0000000000..5246f352dd
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPLocalImpl.scala
@@ -0,0 +1,32 @@
+package vct.col.ast.lang
+
+import vct.col.ast.{CPPLocal, CPPPrimitiveType, Type}
+import vct.col.print.{Ctx, Doc, Text}
+import vct.col.resolve.ctx._
+import vct.col.resolve.lang.CPP
+import vct.col.typerules.Types
+
+trait CPPLocalImpl[G] { this: CPPLocal[G] =>
+ override lazy val t: Type[G] = ref.get match {
+ case ref: RefCPPParam[G] => CPP.typeOrReturnTypeFromDeclaration(ref.decl.specifiers, ref.decl.declarator)
+ case ref: RefAxiomaticDataType[G] => Types.notAValue(ref)
+ case RefVariable(decl) => decl.t
+ case ref: RefCPPFunctionDefinition[G] => Types.notAValue(ref)
+ case ref @ RefCPPGlobalDeclaration(decls, initIdx) =>
+ val declInfo = CPP.getDeclaratorInfo(decls.decl.inits(initIdx).decl)
+ declInfo.params match {
+ case Some(_) => Types.notAValue(ref) // Function declaration
+ case None => declInfo.typeOrReturnType(CPPPrimitiveType(decls.decl.specs)) // Static declaration
+ }
+ case ref @ RefCPPLocalDeclaration(decls, initIdx) =>
+ val declInfo = CPP.getDeclaratorInfo(decls.decl.inits(initIdx).decl)
+ declInfo.params match {
+ case Some(_) => Types.notAValue(ref) // Function declaration
+ case None => declInfo.typeOrReturnType(CPPPrimitiveType(decls.decl.specs)) // Static declaration
+ }
+ case RefModelField(field) => field.t
+ case target: SpecInvocationTarget[G] => Types.notAValue(target)
+ }
+
+ override def layout(implicit ctx: Ctx): Doc = Text(name)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPLongImpl.scala b/src/col/vct/col/ast/lang/CPPLongImpl.scala
new file mode 100644
index 0000000000..205b138cd5
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPLongImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPLong
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPLongImpl[G] { this: CPPLong[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("long")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPNameImpl.scala b/src/col/vct/col/ast/lang/CPPNameImpl.scala
new file mode 100644
index 0000000000..e8377813d0
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPNameImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPName
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPNameImpl[G] { this: CPPName[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text(name)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPParamImpl.scala b/src/col/vct/col/ast/lang/CPPParamImpl.scala
new file mode 100644
index 0000000000..aefeaadb3a
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPParamImpl.scala
@@ -0,0 +1,9 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPParam
+import vct.col.print.{Ctx, Doc}
+
+trait CPPParamImpl[G] { this: CPPParam[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ Doc.spread(specifiers) <+> declarator
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPPointerDeclaratorImpl.scala b/src/col/vct/col/ast/lang/CPPPointerDeclaratorImpl.scala
new file mode 100644
index 0000000000..67e08082b5
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPPointerDeclaratorImpl.scala
@@ -0,0 +1,9 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPPointerDeclarator
+import vct.col.print.{Ctx, Doc}
+
+trait CPPPointerDeclaratorImpl[G] { this: CPPPointerDeclarator[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ inner.show <> Doc.fold(pointers)(_ <> _)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPPointerImpl.scala b/src/col/vct/col/ast/lang/CPPPointerImpl.scala
new file mode 100644
index 0000000000..88edbb44ca
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPPointerImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPPointer
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPPointerImpl[G] { this: CPPPointer[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("*")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPPrimitiveTypeImpl.scala b/src/col/vct/col/ast/lang/CPPPrimitiveTypeImpl.scala
new file mode 100644
index 0000000000..320e841cc9
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPPrimitiveTypeImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPPrimitiveType
+import vct.col.print.{Ctx, Doc}
+
+trait CPPPrimitiveTypeImpl[G] { this: CPPPrimitiveType[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Doc.spread(specifiers)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPPureImpl.scala b/src/col/vct/col/ast/lang/CPPPureImpl.scala
new file mode 100644
index 0000000000..30cbeb5353
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPPureImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPPure
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPPureImpl[G] { this: CPPPure[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Doc.inlineSpec(Text("pure"))
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPShortImpl.scala b/src/col/vct/col/ast/lang/CPPShortImpl.scala
new file mode 100644
index 0000000000..6bc77908c4
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPShortImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPShort
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPShortImpl[G] { this: CPPShort[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("short")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPSignedImpl.scala b/src/col/vct/col/ast/lang/CPPSignedImpl.scala
new file mode 100644
index 0000000000..b4502c7236
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPSignedImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPSigned
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPSignedImpl[G] { this: CPPSigned[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("signed")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPSpecificationModifierImpl.scala b/src/col/vct/col/ast/lang/CPPSpecificationModifierImpl.scala
new file mode 100644
index 0000000000..b569102e66
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPSpecificationModifierImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPSpecificationModifier
+
+trait CPPSpecificationModifierImpl[G] { this: CPPSpecificationModifier[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPSpecificationTypeImpl.scala b/src/col/vct/col/ast/lang/CPPSpecificationTypeImpl.scala
new file mode 100644
index 0000000000..3568a0c777
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPSpecificationTypeImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPSpecificationType
+import vct.col.print.{Ctx, Doc}
+
+trait CPPSpecificationTypeImpl[G] { this: CPPSpecificationType[G] =>
+ override def layout(implicit ctx: Ctx): Doc = t.show
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPStatementImpl.scala b/src/col/vct/col/ast/lang/CPPStatementImpl.scala
new file mode 100644
index 0000000000..38840a879f
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPStatementImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPStatement
+
+trait CPPStatementImpl[G] { this: CPPStatement[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPTArrayImpl.scala b/src/col/vct/col/ast/lang/CPPTArrayImpl.scala
new file mode 100644
index 0000000000..e6a78feafe
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPTArrayImpl.scala
@@ -0,0 +1,10 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPTArray
+import vct.col.print.{Ctx, Doc, Group}
+
+trait CPPTArrayImpl[G] { this: CPPTArray[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ Group(innerType.show <> "[" <> Doc.args(size.toSeq) <> "]")
+}
+
diff --git a/src/col/vct/col/ast/lang/CPPTranslationUnitImpl.scala b/src/col/vct/col/ast/lang/CPPTranslationUnitImpl.scala
new file mode 100644
index 0000000000..e60e344d6a
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPTranslationUnitImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPTranslationUnit
+import vct.col.print.{Ctx, Doc}
+
+trait CPPTranslationUnitImpl[G] { this: CPPTranslationUnit[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Doc.stack(declarations)
+}
diff --git a/src/col/vct/col/ast/lang/CPPTypeImpl.scala b/src/col/vct/col/ast/lang/CPPTypeImpl.scala
new file mode 100644
index 0000000000..17e6176125
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPTypeImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPType
+
+trait CPPTypeImpl[G] { this: CPPType[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPTypeSpecifierImpl.scala b/src/col/vct/col/ast/lang/CPPTypeSpecifierImpl.scala
new file mode 100644
index 0000000000..7d747b3063
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPTypeSpecifierImpl.scala
@@ -0,0 +1,7 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPTypeSpecifier
+
+trait CPPTypeSpecifierImpl[G] { this: CPPTypeSpecifier[G] =>
+
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPTypedFunctionDeclaratorImpl.scala b/src/col/vct/col/ast/lang/CPPTypedFunctionDeclaratorImpl.scala
new file mode 100644
index 0000000000..de89578f31
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPTypedFunctionDeclaratorImpl.scala
@@ -0,0 +1,9 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPTypedFunctionDeclarator
+import vct.col.print.{Ctx, Doc, Group, Text}
+
+trait CPPTypedFunctionDeclaratorImpl[G] { this: CPPTypedFunctionDeclarator[G] =>
+ override def layout(implicit ctx: Ctx): Doc =
+ Group(inner.show <> "(" <> Doc.args(params ++ (if(varargs) Seq(Text("...")) else Nil)) <> ")")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala b/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
new file mode 100644
index 0000000000..b2e42cbe4b
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPTypedefName
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPTypedefNameImpl[G] { this: CPPTypedefName[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text(name)
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPUnsignedImpl.scala b/src/col/vct/col/ast/lang/CPPUnsignedImpl.scala
new file mode 100644
index 0000000000..1f5073907f
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPUnsignedImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPUnsigned
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPUnsignedImpl[G] { this: CPPUnsigned[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("unsigned")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPVoidImpl.scala b/src/col/vct/col/ast/lang/CPPVoidImpl.scala
new file mode 100644
index 0000000000..ca1dfe05ea
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPVoidImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPVoid
+import vct.col.print.{Ctx, Doc, Text}
+
+trait CPPVoidImpl[G] { this: CPPVoid[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("void")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/type/typeclass/TypeImpl.scala b/src/col/vct/col/ast/type/typeclass/TypeImpl.scala
index e5f01d072b..1dbf62a12f 100644
--- a/src/col/vct/col/ast/type/typeclass/TypeImpl.scala
+++ b/src/col/vct/col/ast/type/typeclass/TypeImpl.scala
@@ -19,6 +19,7 @@ trait TypeImpl[G] { this: Type[G] =>
def asPointer: Option[TPointer[G]] = CoercionUtils.getAnyPointerCoercion(this).map(_._2)
def asArray: Option[TArray[G]] = CoercionUtils.getAnyArrayCoercion(this).map(_._2)
def asCArray: Option[CTArray[G]] = CoercionUtils.getAnyCArrayCoercion(this).map(_._2)
+ def asCPPArray: Option[CPPTArray[G]] = CoercionUtils.getAnyCPPArrayCoercion(this).map(_._2)
def asOption: Option[TOption[G]] = CoercionUtils.getAnyOptionCoercion(this).map(_._2)
def asMap: Option[TMap[G]] = CoercionUtils.getAnyMapCoercion(this).map(_._2)
def asTuple: Option[TTuple[G]] = CoercionUtils.getAnyTupleCoercion(this).map(_._2)
diff --git a/src/col/vct/col/ast/util/CheckFoldUnfoldTarget.scala b/src/col/vct/col/ast/util/CheckFoldUnfoldTarget.scala
index 8ab7faa0a0..f3801b1afb 100644
--- a/src/col/vct/col/ast/util/CheckFoldUnfoldTarget.scala
+++ b/src/col/vct/col/ast/util/CheckFoldUnfoldTarget.scala
@@ -36,6 +36,11 @@ trait CheckFoldUnfoldTarget[G] extends NodeFamilyImpl[G] { this: NodeFamily[G] =
case RefInstancePredicate(decl) => checkNonAbstract(decl, inv)
case _ => Some(NotAPredicateApplication(e))
}
+ case inv: CPPInvocation[G] => inv.ref.get match {
+ case RefPredicate(decl) => checkNonAbstract(decl, inv)
+ case RefInstancePredicate(decl) => checkNonAbstract(decl, inv)
+ case _ => Some(NotAPredicateApplication(e))
+ }
case _ => Some(NotAPredicateApplication(e))
}
diff --git a/src/col/vct/col/feature/Feature.scala b/src/col/vct/col/feature/Feature.scala
index 67cdb4c457..1f9e34ff0e 100644
--- a/src/col/vct/col/feature/Feature.scala
+++ b/src/col/vct/col/feature/Feature.scala
@@ -78,6 +78,7 @@ case object AxiomaticDataTypes extends Feature
case object SmtOperators extends Feature
case object JavaSpecific extends Feature
case object CSpecific extends Feature
+case object CPPSpecific extends Feature
case object PvlSpecific extends Feature
case object SilverSpecific extends Feature
case object Contracts extends Feature
diff --git a/src/col/vct/col/feature/FeatureRainbow.scala b/src/col/vct/col/feature/FeatureRainbow.scala
index 11c6947792..889a8891a1 100644
--- a/src/col/vct/col/feature/FeatureRainbow.scala
+++ b/src/col/vct/col/feature/FeatureRainbow.scala
@@ -112,6 +112,8 @@ class FeatureRainbow[G] {
case node: CoerceClassAnyClass[G] => Coercions
case node: CoerceColToCPrimitive[G] => Coercions
case node: CoerceCPrimitiveToCol[G] => Coercions
+ case node: CoerceColToCPPPrimitive[G] => Coercions
+ case node: CoerceCPPPrimitiveToCol[G] => Coercions
case node: CoerceFloatRat[G] => Coercions
case node: CoerceFracZFrac[G] => Coercions
case node: CoerceIdentity[G] => Coercions
@@ -208,6 +210,31 @@ class FeatureRainbow[G] {
case node: OpenCLKernel[G] => CSpecific
case node: SharedMemSize[G] => CSpecific
+ case node: CPPArrayDeclarator[G] => CPPSpecific
+ case node: CPPBool[G] => CPPSpecific
+ case node: CPPDeclaration[G] => CPPSpecific
+ case node: CPPFunctionDefinition[G] => CPPSpecific
+ case node: CPPGlobalDeclaration[G] => CPPSpecific
+ case node: CPPInit[G] => CPPSpecific
+ case node: CPPInline[G] => CPPSpecific
+ case node: CPPInt[G] => CPPSpecific
+ case node: CPPInvocation[G] => CPPSpecific
+ case node: CPPLocal[G] => CPPSpecific
+ case node: CPPLocalDeclaration[G] => CPPSpecific
+ case node: CPPLong[G] => CPPSpecific
+ case node: CPPName[G] => CPPSpecific
+ case node: CPPParam[G] => CPPSpecific
+ case node: CPPPrimitiveType[G] => CPPSpecific
+ case node: CPPPure[G] => CPPSpecific
+ case node: CPPShort[G] => CPPSpecific
+ case node: CPPSigned[G] => CPPSpecific
+ case node: CPPSpecificationType[G] => CPPSpecific
+ case node: CPPTranslationUnit[G] => CPPSpecific
+ case node: CPPTypedefName[G] => CPPSpecific
+ case node: CPPTypedFunctionDeclarator[G] => CPPSpecific
+ case node: CPPUnsigned[G] => CPPSpecific
+ case node: CPPVoid[G] => CPPSpecific
+
case node: CurrentThreadId[G] => CurrentThread
case node: UntypedLiteralSeq[G] => DynamicallyTypedCollection
@@ -643,6 +670,10 @@ class FeatureRainbow[G] {
case node: CGoto[G] => return Seq(CSpecific, Gotos)
case node: CPointer[G] => return Seq(CSpecific, Pointers)
case node: CPointerDeclarator[G] => return Seq(CSpecific, Pointers)
+ case node: CPPChar[G] => return Seq(CPPSpecific, TextTypes)
+ case node: CPPDeclarationStatement[G] => return Seq(CPPSpecific, UnscopedDeclaration)
+ case node: CPPPointer[G] => return Seq(CPPSpecific, Pointers)
+ case node: CPPPointerDeclarator[G] => return Seq(CPPSpecific, Pointers)
case node: Result[G] => return scanFlatly(node.applicable.decl)
case node: SilverNewRef[G] => return Seq(Assignment, Resources)
diff --git a/src/col/vct/col/print/Ctx.scala b/src/col/vct/col/print/Ctx.scala
index 8b3970d4a5..9ec0e78f7b 100644
--- a/src/col/vct/col/print/Ctx.scala
+++ b/src/col/vct/col/print/Ctx.scala
@@ -2,7 +2,6 @@ package vct.col.print
import vct.col.ast.{Declaration, Node}
import vct.col.ref.Ref
-import vct.col.resolve.ctx.Referrable
import scala.util.Try
@@ -12,6 +11,7 @@ object Ctx {
case object Silver extends Syntax
case object Java extends Syntax
case object C extends Syntax
+ case object CPP extends Syntax
case object Cuda extends Syntax
case object OpenCL extends Syntax
}
diff --git a/src/col/vct/col/print/Namer.scala b/src/col/vct/col/print/Namer.scala
index 2d43790e85..6f1522674d 100644
--- a/src/col/vct/col/print/Namer.scala
+++ b/src/col/vct/col/print/Namer.scala
@@ -4,7 +4,6 @@ import hre.util.ScopedStack
import vct.col.ast._
import scala.collection.mutable
-import scala.reflect.ClassTag
case class Namer[G](syntax: Ctx.Syntax) {
private val stack = ScopedStack[Node[G]]()
@@ -58,6 +57,7 @@ case class Namer[G](syntax: Ctx.Syntax) {
case _: JavaConstructor[G] => ()
case _: PVLConstructor[G] => ()
case _: CFunctionDefinition[G] => ()
+ case _: CPPFunctionDefinition[G] => ()
}
def unpackName(name: String): (String, Int) = {
@@ -104,6 +104,8 @@ case class Namer[G](syntax: Ctx.Syntax) {
case decl: ParInvariantDecl[G] => nameKeyed(nearest { case _: ParInvariant[G] => () }, decl)
case decl: CLocalDeclaration[G] => nameKeyed(nearestVariableScope, decl)
case decl: CParam[G] => nameKeyed(nearestCallable, decl)
+ case decl: CPPLocalDeclaration[G] => nameKeyed(nearestVariableScope, decl)
+ case decl: CPPParam[G] => nameKeyed(nearestCallable, decl)
case decl: JavaLocalDeclaration[G] => nameKeyed(nearestCallable, decl)
case decl: VeyMontThread[G] => nameKeyed(nearest { case _: VeyMontSeqProg[G] => () }, decl)
case decl: JavaParam[G] => nameKeyed(nearestCallable, decl)
diff --git a/src/col/vct/col/resolve/ResolutionError.scala b/src/col/vct/col/resolve/ResolutionError.scala
index 8a368c4744..c2331fb7ca 100644
--- a/src/col/vct/col/resolve/ResolutionError.scala
+++ b/src/col/vct/col/resolve/ResolutionError.scala
@@ -6,7 +6,7 @@ import vct.result.VerificationError.{SystemError, UserError}
trait ResolutionError extends UserError
-case class MultipleForwardDeclarationContractError(declaration: CGlobalDeclaration[_]) extends ResolutionError {
+case class MultipleForwardDeclarationContractError(declaration: GlobalDeclaration[_]) extends ResolutionError {
override def code: String = "multipleForwardDeclarationContract"
override def text: String = declaration.o.messageInContext("Cannot simultaneously bind a contract to multiple global declarations.")
diff --git a/src/col/vct/col/resolve/Resolve.scala b/src/col/vct/col/resolve/Resolve.scala
index e6c5c87e01..a5351c46d8 100644
--- a/src/col/vct/col/resolve/Resolve.scala
+++ b/src/col/vct/col/resolve/Resolve.scala
@@ -9,7 +9,7 @@ import vct.col.origin._
import vct.col.resolve.ResolveReferences.scanScope
import vct.col.ref.Ref
import vct.col.resolve.ctx._
-import vct.col.resolve.lang.{C, Java, PVL, Spec}
+import vct.col.resolve.lang.{C, CPP, Java, PVL, Spec}
import vct.col.resolve.Resolve.{MalformedBipAnnotation, SpecExprParser, getLit, isBip}
import vct.col.resolve.lang.JavaAnnotationData.{BipComponent, BipData, BipGuard, BipInvariant, BipPort, BipPure, BipStatePredicate, BipTransition}
import vct.col.rewrite.InitialGeneration
@@ -120,6 +120,10 @@ case object ResolveTypes {
t.ref = Some(C.findCTypeName(name, ctx).getOrElse(
throw NoSuchNameError("struct", name, t)
))
+ case t@CPPTypedefName(name) =>
+ t.ref = Some(CPP.findCPPTypeName(name, ctx).getOrElse(
+ throw NoSuchNameError("class or struct", name, t)
+ ))
case t @ PVLNamedType(name, typeArgs) =>
t.ref = Some(PVL.findTypeName(name, ctx).getOrElse(
throw NoSuchNameError("class", name, t)))
@@ -205,6 +209,7 @@ case object ResolveReferences extends LazyLogging {
// Remove shared memory locations from the body level of a GPU kernel, we want to reason about them at the top level
case CDeclarationStatement(decl) if !(inGPUKernel && decl.decl.specs.collectFirst{case GPULocal() => ()}.isDefined)
=> Seq(decl)
+ case CPPDeclarationStatement(decl) => Seq(decl)
case JavaLocalDeclarationStatement(decl) => Seq(decl)
case LocalDecl(v) => Seq(v)
case other => other.subnodes.flatMap(scanScope(_, inGPUKernel))
@@ -298,6 +303,18 @@ case object ResolveReferences extends LazyLogging {
.declare(C.paramsFromDeclarator(func.decl.inits.head.decl) ++ func.decl.contract.givenArgs ++ func.decl.contract.yieldsArgs)
.copy(currentResult=C.getDeclaratorInfo(func.decl.inits.head.decl)
.params.map(_ => RefCGlobalDeclaration(func, initIdx = 0)))
+ case func: CPPFunctionDefinition[G] =>
+ ctx
+ .copy(currentResult = Some(RefCPPFunctionDefinition(func)))
+ .declare(CPP.paramsFromDeclarator(func.declarator) ++ scanLabels(func.body) ++ func.contract.givenArgs ++ func.contract.yieldsArgs)
+ case func: CPPGlobalDeclaration[G] =>
+ if (func.decl.contract.nonEmpty && func.decl.inits.size > 1) {
+ throw MultipleForwardDeclarationContractError(func)
+ }
+ ctx
+ .declare(CPP.paramsFromDeclarator(func.decl.inits.head.decl) ++ func.decl.contract.givenArgs ++ func.decl.contract.yieldsArgs)
+ .copy(currentResult = CPP.getDeclaratorInfo(func.decl.inits.head.decl)
+ .params.map(_ => RefCPPGlobalDeclaration(func, initIdx = 0)))
case par: ParStatement[G] => ctx
.declare(scanBlocks(par.impl).map(_.decl))
case Scope(locals, body) => ctx
@@ -312,6 +329,8 @@ case object ResolveReferences extends LazyLogging {
def resolveFlatly[G](node: Node[G], ctx: ReferenceResolutionContext[G]): Unit = node match {
case local@CLocal(name) =>
local.ref = Some(C.findCName(name, ctx).getOrElse(throw NoSuchNameError("local", name, local)))
+ case local@CPPLocal(name) =>
+ local.ref = Some(CPP.findCPPName(name, ctx).getOrElse(throw NoSuchNameError("local", name, local)))
case local @ JavaLocal(name) =>
val start: Option[JavaNameTarget[G]] = if (ctx.javaBipGuardsEnabled) {
Java.findJavaBipGuard(ctx, name).map(RefJavaBipGuard(_))
@@ -362,6 +381,10 @@ case object ResolveReferences extends LazyLogging {
inv.ref = Some(C.resolveInvocation(obj, ctx))
Spec.resolveGiven(givenMap, inv.ref.get, inv)
Spec.resolveYields(ctx, yields, inv.ref.get, inv)
+ case inv@CPPInvocation(obj, _, givenMap, yields) =>
+ inv.ref = Some(CPP.resolveInvocation(obj))
+ Spec.resolveGiven(givenMap, inv.ref.get, inv)
+ Spec.resolveYields(ctx, yields, inv.ref.get, inv)
case inv@GpgpuCudaKernelInvocation(name, blocks, threads, args, givenMap, yields) =>
val kernel = C.findCName(name, ctx).getOrElse(throw NoSuchNameError("kernel", name, inv))
inv.ref = Some(kernel match {
@@ -449,6 +472,11 @@ case object ResolveReferences extends LazyLogging {
case decl: CInit[G] =>
decl.ref = C.findDefinition(decl.decl, ctx)
+ case defn: CPPFunctionDefinition[G] =>
+ defn.ref = CPP.findForwardDeclaration(defn.declarator, ctx)
+ case decl: CPPInit[G] =>
+ decl.ref = CPP.findDefinition(decl.decl, ctx)
+
case goto@CGoto(name) =>
goto.ref = Some(Spec.findLabel(name, ctx).getOrElse(throw NoSuchNameError("label", name, goto)))
case goto@Goto(lbl) =>
diff --git a/src/col/vct/col/resolve/ctx/Referrable.scala b/src/col/vct/col/resolve/ctx/Referrable.scala
index 262b4bed35..79c065802e 100644
--- a/src/col/vct/col/resolve/ctx/Referrable.scala
+++ b/src/col/vct/col/resolve/ctx/Referrable.scala
@@ -3,7 +3,7 @@ package vct.col.resolve.ctx
import vct.col.ast._
import vct.col.origin.SourceNameOrigin
import vct.col.resolve.NameLost
-import vct.col.resolve.lang.C
+import vct.col.resolve.lang.{C, CPP}
/**
* Collection of all things that can be cross-referenced in the AST. This includes all declarations, indices at
@@ -19,6 +19,11 @@ sealed trait Referrable[G] {
case RefCFunctionDefinition(decl) => C.nameFromDeclarator(decl.declarator)
case RefCGlobalDeclaration(decls, initIdx) => C.nameFromDeclarator(decls.decl.inits(initIdx).decl)
case RefCLocalDeclaration(decls, initIdx) => C.nameFromDeclarator(decls.decl.inits(initIdx).decl)
+ case RefCPPTranslationUnit(_) => ""
+ case RefCPPParam(decl) => CPP.nameFromDeclarator(decl.declarator)
+ case RefCPPFunctionDefinition(decl) => CPP.nameFromDeclarator(decl.declarator)
+ case RefCPPGlobalDeclaration(decls, initIdx) => CPP.nameFromDeclarator(decls.decl.inits(initIdx).decl)
+ case RefCPPLocalDeclaration(decls, initIdx) => CPP.nameFromDeclarator(decls.decl.inits(initIdx).decl)
case RefJavaNamespace(_) => ""
case RefUnloadedJavaNamespace(_) => ""
case RefJavaClass(decl) => decl.name
@@ -84,6 +89,10 @@ case object Referrable {
case decl: CParam[G] => RefCParam(decl)
case decl: CFunctionDefinition[G] => RefCFunctionDefinition(decl)
case decl: CGlobalDeclaration[G] => return decl.decl.inits.indices.map(RefCGlobalDeclaration(decl, _))
+ case decl: CPPTranslationUnit[G] => RefCPPTranslationUnit(decl)
+ case decl: CPPParam[G] => RefCPPParam(decl)
+ case decl: CPPFunctionDefinition[G] => RefCPPFunctionDefinition(decl)
+ case decl: CPPGlobalDeclaration[G] => return decl.decl.inits.indices.map(RefCPPGlobalDeclaration(decl, _))
case decl: JavaNamespace[G] => RefJavaNamespace(decl)
case decl: JavaClass[G] => RefJavaClass(decl)
case decl: JavaInterface[G] => RefJavaClass(decl)
@@ -122,6 +131,7 @@ case object Referrable {
case decl: ModelProcess[G] => RefModelProcess(decl)
case decl: ModelAction[G] => RefModelAction(decl)
case decl: CLocalDeclaration[G] => return decl.decl.inits.indices.map(RefCLocalDeclaration(decl, _))
+ case decl: CPPLocalDeclaration[G] => return decl.decl.inits.indices.map(RefCPPLocalDeclaration(decl, _))
case decl: JavaLocalDeclaration[G] => return decl.decls.indices.map(RefJavaLocalDeclaration(decl, _))
case decl: PVLConstructor[G] => RefPVLConstructor(decl)
case decl: VeyMontSeqProg[G] => RefSeqProg(decl)
@@ -150,13 +160,15 @@ name in Java, we can just search for in-scope JavaNameTarget's with the correct
sealed trait JavaTypeNameTarget[G] extends Referrable[G] with JavaDerefTarget[G]
sealed trait CTypeNameTarget[G] extends Referrable[G]
+sealed trait CPPTypeNameTarget[G] extends Referrable[G]
sealed trait PVLTypeNameTarget[G] extends Referrable[G]
-sealed trait SpecTypeNameTarget[G] extends JavaTypeNameTarget[G] with CTypeNameTarget[G] with PVLTypeNameTarget[G]
+sealed trait SpecTypeNameTarget[G] extends JavaTypeNameTarget[G] with CTypeNameTarget[G] with CPPTypeNameTarget[G] with PVLTypeNameTarget[G]
sealed trait JavaNameTarget[G] extends Referrable[G]
sealed trait CNameTarget[G] extends Referrable[G]
+sealed trait CPPNameTarget[G] extends Referrable[G]
sealed trait PVLNameTarget[G] extends Referrable[G]
-sealed trait SpecNameTarget[G] extends CNameTarget[G] with JavaNameTarget[G] with PVLNameTarget[G]
+sealed trait SpecNameTarget[G] extends CNameTarget[G] with CPPNameTarget[G] with JavaNameTarget[G] with PVLNameTarget[G]
sealed trait CDerefTarget[G] extends Referrable[G]
sealed trait JavaDerefTarget[G] extends Referrable[G]
@@ -165,11 +177,15 @@ sealed trait SpecDerefTarget[G] extends CDerefTarget[G] with JavaDerefTarget[G]
sealed trait JavaInvocationTarget[G] extends Referrable[G]
sealed trait CInvocationTarget[G] extends Referrable[G]
+sealed trait CPPInvocationTarget[G] extends Referrable[G]
sealed trait PVLInvocationTarget[G] extends Referrable[G]
sealed trait SpecInvocationTarget[G]
extends JavaInvocationTarget[G]
with CNameTarget[G]
- with CDerefTarget[G] with CInvocationTarget[G]
+ with CDerefTarget[G]
+ with CInvocationTarget[G]
+ with CPPNameTarget[G]
+ with CPPInvocationTarget[G]
with PVLInvocationTarget[G]
sealed trait ThisTarget[G] extends Referrable[G]
@@ -186,6 +202,11 @@ case class RefCParam[G](decl: CParam[G]) extends Referrable[G] with CNameTarget[
case class RefCFunctionDefinition[G](decl: CFunctionDefinition[G]) extends Referrable[G] with CNameTarget[G] with CInvocationTarget[G] with ResultTarget[G]
case class RefCGlobalDeclaration[G](decls: CGlobalDeclaration[G], initIdx: Int) extends Referrable[G] with CNameTarget[G] with CInvocationTarget[G] with ResultTarget[G]
case class RefCLocalDeclaration[G](decls: CLocalDeclaration[G], initIdx: Int) extends Referrable[G] with CNameTarget[G]
+case class RefCPPTranslationUnit[G](decl: CPPTranslationUnit[G]) extends Referrable[G]
+case class RefCPPParam[G](decl: CPPParam[G]) extends Referrable[G] with CPPNameTarget[G]
+case class RefCPPFunctionDefinition[G](decl: CPPFunctionDefinition[G]) extends Referrable[G] with CPPNameTarget[G] with CPPInvocationTarget[G] with ResultTarget[G]
+case class RefCPPGlobalDeclaration[G](decls: CPPGlobalDeclaration[G], initIdx: Int) extends Referrable[G] with CPPNameTarget[G] with CPPInvocationTarget[G] with ResultTarget[G]
+case class RefCPPLocalDeclaration[G](decls: CPPLocalDeclaration[G], initIdx: Int) extends Referrable[G] with CPPNameTarget[G]
case class RefJavaNamespace[G](decl: JavaNamespace[G]) extends Referrable[G]
case class RefUnloadedJavaNamespace[G](names: Seq[String]) extends Referrable[G] with JavaNameTarget[G] with JavaDerefTarget[G]
case class RefJavaClass[G](decl: JavaClassOrInterface[G]) extends Referrable[G] with JavaTypeNameTarget[G] with JavaNameTarget[G] with JavaDerefTarget[G] with ThisTarget[G]
diff --git a/src/col/vct/col/resolve/lang/C.scala b/src/col/vct/col/resolve/lang/C.scala
index 0baa8fc084..8b7f27889a 100644
--- a/src/col/vct/col/resolve/lang/C.scala
+++ b/src/col/vct/col/resolve/lang/C.scala
@@ -2,7 +2,6 @@ package vct.col.resolve.lang
import hre.util.FuncTools
import vct.col.ast._
-import vct.col.ast.`type`.TFloats
import vct.col.origin._
import vct.col.resolve._
import vct.col.resolve.ctx._
diff --git a/src/col/vct/col/resolve/lang/CPP.scala b/src/col/vct/col/resolve/lang/CPP.scala
new file mode 100644
index 0000000000..ab82452c54
--- /dev/null
+++ b/src/col/vct/col/resolve/lang/CPP.scala
@@ -0,0 +1,113 @@
+package vct.col.resolve.lang
+
+import hre.util.FuncTools
+import vct.col.ast._
+import vct.col.origin._
+import vct.col.resolve._
+import vct.col.resolve.ctx._
+import vct.col.typerules.Types
+import vct.result.VerificationError.UserError
+
+case object CPP {
+ implicit private val o: Origin = DiagnosticOrigin
+
+ case class CPPTypeNotSupported(node: Option[Node[_]]) extends UserError {
+ override def code: String = "cppTypeNotSupported"
+
+ override def text: String = {
+ (node match {
+ case Some(node) => node.o.messageInContext(_)
+ case None => (text: String) => text
+ })("This type is not supported by VerCors.")
+ }
+ }
+
+ val NUMBER_LIKE_PREFIXES: Seq[Seq[CPPDeclarationSpecifier[_]]] = Seq(
+ Nil,
+ Seq(CPPUnsigned()),
+ Seq(CPPSigned()),
+ )
+
+ val NUMBER_LIKE_TYPES: Seq[Seq[CPPDeclarationSpecifier[_]]] = Seq(
+ Seq(CPPInt()),
+ Seq(CPPLong()),
+ Seq(CPPLong(), CPPInt()),
+ Seq(CPPLong(), CPPLong()),
+ Seq(CPPLong(), CPPLong(), CPPInt()),
+ )
+
+ val NUMBER_LIKE_SPECIFIERS: Seq[Seq[CPPDeclarationSpecifier[_]]] =
+ for (prefix <- NUMBER_LIKE_PREFIXES; t <- NUMBER_LIKE_TYPES)
+ yield prefix ++ t
+
+ case class DeclaratorInfo[G](params: Option[Seq[CPPParam[G]]], typeOrReturnType: Type[G] => Type[G], name: String)
+
+ def getDeclaratorInfo[G](decl: CPPDeclarator[G]): DeclaratorInfo[G] = decl match {
+ case CPPPointerDeclarator(pointers, inner) =>
+ val innerInfo = getDeclaratorInfo(inner)
+ DeclaratorInfo(
+ innerInfo.params,
+ t => innerInfo.typeOrReturnType(FuncTools.repeat[Type[G]](TPointer(_), pointers.size, t)),
+ innerInfo.name)
+ case array @ CPPArrayDeclarator(inner, size) =>
+ val innerInfo = getDeclaratorInfo(inner)
+ DeclaratorInfo(innerInfo.params, t => innerInfo.typeOrReturnType(CPPTArray(size, t)(array.blame)), innerInfo.name)
+ case CPPTypedFunctionDeclarator(params, _, inner) =>
+ val innerInfo = getDeclaratorInfo(inner)
+ DeclaratorInfo(params = Some(params), typeOrReturnType = (t => t), innerInfo.name)
+ case CPPName(name) => DeclaratorInfo(params = None, typeOrReturnType = (t => t), name)
+ }
+
+ def getPrimitiveType[G](specs: Seq[CPPDeclarationSpecifier[G]], context: Option[Node[G]] = None): Type[G] =
+ specs.collect { case spec: CPPTypeSpecifier[G] => spec } match {
+ case Seq(CPPVoid()) => TVoid()
+ case Seq(CPPChar()) => TChar()
+ case t if CPP.NUMBER_LIKE_SPECIFIERS.contains(t) => TInt()
+ case Seq(CPPSpecificationType(t@TFloat(_, _))) => t
+ case Seq(CPPBool()) => TBool()
+ case Seq(defn@CPPTypedefName(_)) => Types.notAValue(defn.ref.get)
+ case Seq(CPPSpecificationType(typ)) => typ
+ case spec +: _ => throw CPPTypeNotSupported(context.orElse(Some(spec)))
+ case _ => throw CPPTypeNotSupported(context)
+ }
+
+ def nameFromDeclarator(declarator: CPPDeclarator[_]): String =
+ getDeclaratorInfo(declarator).name
+
+ def typeOrReturnTypeFromDeclaration[G](specs: Seq[CPPDeclarationSpecifier[G]], decl: CPPDeclarator[G]): Type[G] =
+ getDeclaratorInfo(decl).typeOrReturnType(CPPPrimitiveType(specs))
+
+ def paramsFromDeclarator[G](declarator: CPPDeclarator[G]): Seq[CPPParam[G]] =
+ getDeclaratorInfo(declarator).params.get
+
+ def findCPPTypeName[G](name: String, ctx: TypeResolutionContext[G]): Option[CPPTypeNameTarget[G]] =
+ ctx.stack.flatten.collectFirst {
+ case target: CPPTypeNameTarget[G] if target.name == name => target
+ }
+
+ def findCPPName[G](name: String, ctx: ReferenceResolutionContext[G]): Option[CPPNameTarget[G]] =
+ name match {
+ case _ => ctx.stack.flatten.collectFirst {
+ case target: CPPNameTarget[G] if target.name == name => target
+ }
+ }
+
+ def findForwardDeclaration[G](declarator: CPPDeclarator[G], ctx: ReferenceResolutionContext[G]): Option[RefCPPGlobalDeclaration[G]] =
+ ctx.stack.flatten.collectFirst {
+ case target: RefCPPGlobalDeclaration[G] if target.name == nameFromDeclarator(declarator) => target
+ }
+
+ def findDefinition[G](declarator: CPPDeclarator[G], ctx: ReferenceResolutionContext[G]): Option[RefCPPFunctionDefinition[G]] =
+ ctx.stack.flatten.collectFirst {
+ case target: RefCPPFunctionDefinition[G] if target.name == nameFromDeclarator(declarator) => target
+ }
+
+ def resolveInvocation[G](obj: Expr[G]): CPPInvocationTarget[G] =
+ obj.t match {
+ case t: TNotAValue[G] => t.decl.get match {
+ case target: CPPInvocationTarget[G] => target
+ case _ => throw NotApplicable(obj)
+ }
+ case _ => throw NotApplicable(obj)
+ }
+}
diff --git a/src/col/vct/col/resolve/lang/Spec.scala b/src/col/vct/col/resolve/lang/Spec.scala
index c679410bd3..1063a02627 100644
--- a/src/col/vct/col/resolve/lang/Spec.scala
+++ b/src/col/vct/col/resolve/lang/Spec.scala
@@ -16,6 +16,9 @@ case object Spec {
case RefCLocalDeclaration(decls, _) => decls.decl.contract
case RefCGlobalDeclaration(decls, _) => decls.decl.contract
// case RefCFunctionDefinition(decl) =>
+ case RefCPPLocalDeclaration(decls, _) => decls.decl.contract
+ case RefCPPGlobalDeclaration(decls, _) => decls.decl.contract
+ case RefCPPFunctionDefinition(decl) => decl.contract
case RefJavaConstructor(decl) => decl.contract
case RefJavaMethod(decl) => decl.contract
case RefPVLConstructor(decl) => decl.contract
diff --git a/src/col/vct/col/rewrite/NonLatchingRewriter.scala b/src/col/vct/col/rewrite/NonLatchingRewriter.scala
index a5fc43f125..1e2ec1d4b7 100644
--- a/src/col/vct/col/rewrite/NonLatchingRewriter.scala
+++ b/src/col/vct/col/rewrite/NonLatchingRewriter.scala
@@ -1,6 +1,5 @@
package vct.col.rewrite
-import hre.debug.TimeTravel
import vct.col.ast._
import vct.col.util.CurrentProgramRewriteContext
import vct.result.VerificationError
@@ -41,6 +40,12 @@ class NonLatchingRewriter[Pre, Post]() extends AbstractRewriter[Pre, Post] {
override def dispatch(node: CInit[Pre]): CInit[Post] = rewriteDefault(node)
override def dispatch(node: CDeclaration[Pre]): CDeclaration[Post] = rewriteDefault(node)
+ override def dispatch(node: CPPDeclarator[Pre]): CPPDeclarator[Post] = rewriteDefault(node)
+ override def dispatch(node: CPPDeclarationSpecifier[Pre]): CPPDeclarationSpecifier[Post] = rewriteDefault(node)
+ override def dispatch(node: CPPPointer[Pre]): CPPPointer[Post] = rewriteDefault(node)
+ override def dispatch(node: CPPInit[Pre]): CPPInit[Post] = rewriteDefault(node)
+ override def dispatch(node: CPPDeclaration[Pre]): CPPDeclaration[Post] = rewriteDefault(node)
+
override def dispatch(node: JavaVariableDeclaration[Pre]): JavaVariableDeclaration[Post] = rewriteDefault(node)
override def dispatch(node: JavaModifier[Pre]): JavaModifier[Post] = rewriteDefault(node)
override def dispatch(node: JavaImport[Pre]): JavaImport[Post] = rewriteDefault(node)
diff --git a/src/col/vct/col/typerules/CoercingRewriter.scala b/src/col/vct/col/typerules/CoercingRewriter.scala
index 21984d108d..ffcbfeb7e5 100644
--- a/src/col/vct/col/typerules/CoercingRewriter.scala
+++ b/src/col/vct/col/typerules/CoercingRewriter.scala
@@ -217,7 +217,11 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
case node: CTypeQualifier[Pre] => node
case node: CPointer[Pre] => node
case node: CInit[Pre] => node
- case node: CDeclaration[Pre] => node
+ case node: CPPDeclarator[Pre] => node
+ case node: CPPDeclarationSpecifier[Pre] => node
+ case node: CPPDeclaration[Pre] => node
+ case node: CPPPointer[Pre] => node
+ case node: CPPInit[Pre] => node
case node: GpuMemoryFence[Pre] => node
case node: JavaModifier[Pre] => node
case node: JavaImport[Pre] => node
@@ -347,6 +351,26 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
def postCoerce(node: CDeclaration[Pre]): CDeclaration[Post] = rewriteDefault(node)
override final def dispatch(node: CDeclaration[Pre]): CDeclaration[Post] = postCoerce(coerce(preCoerce(node)))
+ def preCoerce(node: CPPDeclarator[Pre]): CPPDeclarator[Pre] = node
+ def postCoerce(node: CPPDeclarator[Pre]): CPPDeclarator[Post] = rewriteDefault(node)
+ override final def dispatch(node: CPPDeclarator[Pre]): CPPDeclarator[Post] = postCoerce(coerce(preCoerce(node)))
+
+ def preCoerce(node: CPPDeclarationSpecifier[Pre]): CPPDeclarationSpecifier[Pre] = node
+ def postCoerce(node: CPPDeclarationSpecifier[Pre]): CPPDeclarationSpecifier[Post] = rewriteDefault(node)
+ override final def dispatch(node: CPPDeclarationSpecifier[Pre]): CPPDeclarationSpecifier[Post] = postCoerce(coerce(preCoerce(node)))
+
+ def preCoerce(node: CPPDeclaration[Pre]): CPPDeclaration[Pre] = node
+ def postCoerce(node: CPPDeclaration[Pre]): CPPDeclaration[Post] = rewriteDefault(node)
+ override final def dispatch(node: CPPDeclaration[Pre]): CPPDeclaration[Post] = postCoerce(coerce(preCoerce(node)))
+
+ def preCoerce(node: CPPPointer[Pre]): CPPPointer[Pre] = node
+ def postCoerce(node: CPPPointer[Pre]): CPPPointer[Post] = rewriteDefault(node)
+ override final def dispatch(node: CPPPointer[Pre]): CPPPointer[Post] = postCoerce(coerce(preCoerce(node)))
+
+ def preCoerce(node: CPPInit[Pre]): CPPInit[Pre] = node
+ def postCoerce(node: CPPInit[Pre]): CPPInit[Post] = rewriteDefault(node)
+ override final def dispatch(node: CPPInit[Pre]): CPPInit[Post] = postCoerce(coerce(preCoerce(node)))
+
def preCoerce(node: GpuMemoryFence[Pre]): GpuMemoryFence[Pre] = node
def postCoerce(node: GpuMemoryFence[Pre]): GpuMemoryFence[Post] = rewriteDefault(node)
override final def dispatch(node: GpuMemoryFence[Pre]): GpuMemoryFence[Post] = postCoerce(coerce(preCoerce(node)))
@@ -878,6 +902,9 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
val (coercedXs, TSeq(element)) = seq(xs)
val sharedType = Types.leastCommonSuperType(x.t, element)
Cons(coerce(x, sharedType), coerce(xs, TSeq(sharedType)))
+ case inv@CPPInvocation(applicable, args, givenArgs, yields) =>
+ CPPInvocation(applicable, args, givenArgs, yields)(inv.blame)
+ case CPPLocal(name) => e
case StringConcat(left, right) =>
StringConcat(string(left), string(right))
case acc @ CStructAccess(struct, field) =>
@@ -1536,6 +1563,7 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
case CGoto(label) => CGoto(label)
case c @ Commit(obj) => Commit(cls(obj))(c.blame)
case Continue(label) => Continue(label)
+ case CPPDeclarationStatement(decl) => CPPDeclarationStatement(decl)
case DefaultCase() => DefaultCase()
case Eval(expr) => Eval(expr)
case e @ Exhale(assn) => Exhale(res(assn))(e.blame)
@@ -1596,6 +1624,8 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
decl match {
case unit: CTranslationUnit[Pre] =>
new CTranslationUnit(unit.declarations)
+ case unit: CPPTranslationUnit[Pre] =>
+ new CPPTranslationUnit(unit.declarations)
case rule: SimplificationRule[Pre] =>
new SimplificationRule[Pre](bool(rule.axiom))
case dataType: AxiomaticDataType[Pre] =>
@@ -1618,6 +1648,10 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
definition
case declaration: CGlobalDeclaration[Pre] =>
declaration
+ case definition: CPPFunctionDefinition[Pre] =>
+ definition
+ case declaration: CPPGlobalDeclaration[Pre] =>
+ declaration
case namespace: JavaNamespace[Pre] =>
namespace
case clazz: JavaClass[Pre] =>
@@ -1684,6 +1718,10 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
param
case decl: CLocalDeclaration[Pre] =>
decl
+ case param: CPPParam[Pre] =>
+ param
+ case decl: CPPLocalDeclaration[Pre] =>
+ decl
case declaration: JavaLocalDeclaration[Pre] =>
new JavaLocalDeclaration[Pre](declaration.modifiers, declaration.t, declaration.decls.map {
case JavaVariableDeclaration(name, dims, None) => JavaVariableDeclaration(name, dims, None)
@@ -1917,6 +1955,56 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
}
}
+ def coerce(node: CPPDeclarator[Pre]): CPPDeclarator[Pre] = {
+ implicit val o: Origin = node.o
+ node match {
+ case CPPPointerDeclarator(pointers, inner) =>
+ CPPPointerDeclarator(pointers, inner)
+ case array @ CPPArrayDeclarator(inner, size) =>
+ CPPArrayDeclarator(inner, size.map(int))(array.blame)
+ case CPPTypedFunctionDeclarator(params, varargs, inner) =>
+ CPPTypedFunctionDeclarator(params, varargs, inner)
+ case CPPName(name) =>
+ CPPName(name)
+ }
+ }
+
+ def coerce(node: CPPDeclarationSpecifier[Pre]): CPPDeclarationSpecifier[Pre] = {
+ implicit val o: Origin = node.o
+ node match {
+ case CPPPure() => CPPPure()
+ case CPPInline() => CPPInline()
+ case CPPVoid() => CPPVoid()
+ case CPPChar() => CPPChar()
+ case CPPShort() => CPPShort()
+ case CPPInt() => CPPInt()
+ case CPPLong() => CPPLong()
+ case CPPSigned() => CPPSigned()
+ case CPPUnsigned() => CPPUnsigned()
+ case CPPBool() => CPPBool()
+ case CPPTypedefName(name) => CPPTypedefName(name)
+ case CPPSpecificationType(t) => CPPSpecificationType(t)
+ }
+ }
+
+ def coerce(node: CPPDeclaration[Pre]): CPPDeclaration[Pre] = {
+ implicit val o: Origin = node.o
+ val CPPDeclaration(contract, specs, init) = node
+ CPPDeclaration(contract, specs, init)
+ }
+
+ def coerce(node: CPPPointer[Pre]): CPPPointer[Pre] = {
+ implicit val o: Origin = node.o
+ val CPPPointer() = node
+ CPPPointer()
+ }
+
+ def coerce(node: CPPInit[Pre]): CPPInit[Pre] = {
+ implicit val o: Origin = node.o
+ val CPPInit(decl, init) = node
+ CPPInit(decl, init)
+ }
+
def coerce(node: JavaName[Pre]): JavaName[Pre] = {
implicit val o: Origin = node.o
val JavaName(names) = node
diff --git a/src/col/vct/col/typerules/CoercionUtils.scala b/src/col/vct/col/typerules/CoercionUtils.scala
index 6d87e9f72f..1e12e8dc3b 100644
--- a/src/col/vct/col/typerules/CoercionUtils.scala
+++ b/src/col/vct/col/typerules/CoercionUtils.scala
@@ -57,6 +57,8 @@ case object CoercionUtils {
case (_ @ CTArray(_, innerType), _ @ TArray(element)) if element == innerType =>
CoerceCArrayPointer(element)
+ case (_@CPPTArray(_, innerType), _@TArray(element)) if element == innerType =>
+ CoerceCPPArrayPointer(element)
case (TBool(), TResource()) => CoerceBoolResource()
case (TFraction(), TZFraction()) => CoerceFracZFrac()
@@ -122,6 +124,26 @@ case object CoercionUtils {
case None => return None
}
+ case (source@CPPPrimitiveType(specs), target) =>
+ specs.collectFirst { case spec: CPPSpecificationType[G] => spec } match {
+ case Some(CPPSpecificationType(t)) =>
+ CoercionSequence(Seq(
+ CoerceCPPPrimitiveToCol(source, t),
+ getCoercion(t, target).getOrElse(return None),
+ ))
+ case None => return None
+ }
+
+ case (source, target@CPPPrimitiveType(specs)) =>
+ specs.collectFirst { case spec: CPPSpecificationType[G] => spec } match {
+ case Some(CPPSpecificationType(t)) =>
+ CoercionSequence(Seq(
+ getCoercion(source, t).getOrElse(return None),
+ CoerceColToCPPPrimitive(t, target),
+ ))
+ case None => return None
+ }
+
// Something with TVar?
// Unsafe coercions
@@ -157,26 +179,48 @@ case object CoercionUtils {
case None => None
}
+ def getAnyCPPCoercion[G](source: Type[G]): Option[(Coercion[G], Type[G])] = source match {
+ case t: CPPPrimitiveType[G] =>
+ t.specifiers.collectFirst { case spec: CPPSpecificationType[G] => spec }.map {
+ case CPPSpecificationType(inner) => (CoerceCPPPrimitiveToCol(t, inner), inner)
+ }
+ case _ => None
+ }
+
+ def chainCPPCoercion[G, T](source: CPPPrimitiveType[G], next: Type[G] => Option[(Coercion[G], T)]): Option[(Coercion[G], T)] =
+ getAnyCPPCoercion(source) match {
+ case Some(inner) => next(inner._2) match {
+ case Some((coercion, finalType)) =>
+ Some((CoercionSequence(Seq(coercion, inner._1)), finalType))
+ case None => None
+ }
+ case None => None
+ }
+
def getAnySeqCoercion[G](source: Type[G]): Option[(Coercion[G], TSeq[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnySeqCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnySeqCoercion)
case t: TSeq[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnySetCoercion[G](source: Type[G]): Option[(Coercion[G], TSet[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnySetCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnySetCoercion)
case t: TSet[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyBagCoercion[G](source: Type[G]): Option[(Coercion[G], TBag[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyBagCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyBagCoercion)
case t: TBag[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnySizedCoercion[G](source: Type[G]): Option[(Coercion[G], SizedType[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnySizedCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnySizedCoercion)
case t: TSeq[G] => Some((CoerceIdentity(source), t))
case t: TSet[G] => Some((CoerceIdentity(source), t))
case t: TBag[G] => Some((CoerceIdentity(source), t))
@@ -189,6 +233,8 @@ case object CoercionUtils {
case t: TPointer[G] => Some((CoerceIdentity(source), t))
case t: CTPointer[G] => Some((CoerceIdentity(source), TPointer(t.innerType)))
case t: CTArray[G] => Some((CoerceCArrayPointer(t.innerType), TPointer(t.innerType)))
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyPointerCoercion)
+ case t: CPPTArray[G] => Some((CoerceCPPArrayPointer(t.innerType), TPointer(t.innerType)))
case _: TNull[G] =>
val t = TPointer[G](TAny())
Some((CoerceNullPointer(t), t))
@@ -201,8 +247,15 @@ case object CoercionUtils {
case _ => None
}
+ def getAnyCPPArrayCoercion[G](source: Type[G]): Option[(Coercion[G], CPPTArray[G])] = source match {
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyCPPArrayCoercion)
+ case t: CPPTArray[G] => Some((CoerceIdentity(source), t))
+ case _ => None
+ }
+
def getAnyArrayCoercion[G](source: Type[G]): Option[(Coercion[G], TArray[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyArrayCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyArrayCoercion)
case t: TArray[G] => Some((CoerceIdentity(source), t))
case _: TNull[G] =>
val t = TArray[G](TAny())
@@ -212,6 +265,7 @@ case object CoercionUtils {
def getAnyMatrixArrayCoercion[G](source: Type[G]): Option[(Coercion[G], TArray[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyMatrixArrayCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyMatrixArrayCoercion)
case t @ TArray(TArray(_)) => Some((CoerceIdentity(source), t))
case TArray(TNull()) => Some(???)
case TNull() =>
@@ -222,36 +276,42 @@ case object CoercionUtils {
def getAnyOptionCoercion[G](source: Type[G]): Option[(Coercion[G], TOption[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyOptionCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyOptionCoercion)
case t: TOption[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyMapCoercion[G](source: Type[G]): Option[(Coercion[G], TMap[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyMapCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyMapCoercion)
case t: TMap[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyTupleCoercion[G](source: Type[G]): Option[(Coercion[G], TTuple[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyTupleCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyTupleCoercion)
case t: TTuple[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyMatrixCoercion[G](source: Type[G]): Option[(Coercion[G], TMatrix[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyMatrixCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyMatrixCoercion)
case t: TMatrix[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyModelCoercion[G](source: Type[G]): Option[(Coercion[G], TModel[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyModelCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyModelCoercion)
case t: TModel[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyClassCoercion[G](source: Type[G]): Option[(Coercion[G], TClass[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyClassCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyClassCoercion)
case t: TClass[G] => Some((CoerceIdentity(source), t))
case t: TUnion[G] =>
@@ -271,30 +331,35 @@ case object CoercionUtils {
def getAnyEitherCoercion[G](source: Type[G]): Option[(Coercion[G], TEither[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyEitherCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyEitherCoercion)
case t: TEither[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnyBitvecCoercion[G](source: Type[G]): Option[(Coercion[G], TSmtlibBitVector[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnyBitvecCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnyBitvecCoercion)
case t: TSmtlibBitVector[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnySmtlibFloatCoercion[G](source: Type[G]): Option[(Coercion[G], TSmtlibFloatingPoint[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnySmtlibFloatCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnySmtlibFloatCoercion)
case t: TSmtlibFloatingPoint[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnySmtlibArrayCoercion[G](source: Type[G]): Option[(Coercion[G], TSmtlibArray[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnySmtlibArrayCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnySmtlibArrayCoercion)
case t: TSmtlibArray[G] => Some((CoerceIdentity(source), t))
case _ => None
}
def getAnySmtlibSeqCoercion[G](source: Type[G]): Option[(Coercion[G], TSmtlibSeq[G])] = source match {
case t: CPrimitiveType[G] => chainCCoercion(t, getAnySmtlibSeqCoercion)
+ case t: CPPPrimitiveType[G] => chainCPPCoercion(t, getAnySmtlibSeqCoercion)
case t: TSmtlibSeq[G] => Some((CoerceIdentity(source), t))
case _ => None
}
diff --git a/src/colhelper/ColDefs.scala b/src/colhelper/ColDefs.scala
index b1cd9c6172..051c6d6531 100644
--- a/src/colhelper/ColDefs.scala
+++ b/src/colhelper/ColDefs.scala
@@ -37,6 +37,8 @@ object ColDefs {
"ParInvariantDecl",
"CLocalDeclaration",
"CParam",
+ "CPPLocalDeclaration",
+ "CPPParam",
"JavaLocalDeclaration",
"VeyMontThread",
"JavaParam",
@@ -70,6 +72,7 @@ object ColDefs {
"InstanceFunction", "InstanceMethod",
"JavaConstructor", "JavaMethod",
"CFunctionDefinition",
+ "CPPFunctionDefinition",
"PVLConstructor",
"LlvmFunctionDefinition"
// Potentially ParBlocks and other execution contexts (lambdas?) should be a scope too.
@@ -84,6 +87,13 @@ object ColDefs {
"CParam" -> Seq(
"CGlobalDeclaration", "CFunctionDefinition",
),
+ "CPPLocalDeclaration" -> Seq(
+ "CPPGlobalDeclaration", "CPPFunctionDefinition",
+ "Scope",
+ ),
+ "CPPParam" -> Seq(
+ "CPPGlobalDeclaration", "CPPFunctionDefinition",
+ ),
"JavaLocalDeclaration" -> Seq(
"JavaConstructor", "JavaMethod",
"Scope",
diff --git a/src/main/vct/main/stages/Parsing.scala b/src/main/vct/main/stages/Parsing.scala
index c4b32e76bd..fa24a72562 100644
--- a/src/main/vct/main/stages/Parsing.scala
+++ b/src/main/vct/main/stages/Parsing.scala
@@ -5,11 +5,10 @@ import hre.stages.Stage
import vct.col.rewrite.Generation
import vct.main.stages.Parsing.{Language, UnknownFileExtension}
import vct.options.Options
-import vct.parsers.transform.{BlameProvider, ReadableOriginProvider}
import vct.parsers._
+import vct.parsers.transform.{BlameProvider, ReadableOriginProvider}
import vct.resources.Resources
import vct.result.VerificationError.UserError
-import viper.api
import viper.api.transform.ColSilverParser
import java.nio.file.Path
@@ -21,7 +20,9 @@ case object Parsing {
def fromFilename(filename: String): Option[Language] =
filename.split('.').last match {
case "cl" | "c" | "cu" => Some(C)
+ case "cpp" => Some(CPP)
case "i" => Some(InterpretedC)
+ case "ipp" => Some(InterpretedCPP)
case "java" => Some(Java)
case "pvl" => Some(PVL)
case "sil" | "vpr" => Some(Silver)
@@ -32,6 +33,8 @@ case object Parsing {
case object C extends Language
case object InterpretedC extends Language
+ case object CPP extends Language
+ case object InterpretedCPP extends Language
case object Java extends Language
case object PVL extends Language
case object Silver extends Language
@@ -63,6 +66,10 @@ case class Parsing[G <: Generation]
cSystemInclude: Path = Resources.getCIncludePath,
cOtherIncludes: Seq[Path] = Nil,
cDefines: Map[String, String] = Map.empty,
+ ccpp: Path = Resources.getCPPcPath,
+ cppSystemInclude: Path = Resources.getCPPIncludePath,
+ cppOtherIncludes: Seq[Path] = Nil,
+ cppDefines: Map[String, String] = Map.empty,
) extends Stage[Seq[Readable], ParseResult[G]] {
override def friendlyName: String = "Parsing"
override def progressWeight: Int = 4
@@ -78,6 +85,8 @@ case class Parsing[G <: Generation]
val parser = language match {
case Language.C => ColCParser(originProvider, blameProvider, cc, cSystemInclude, cOtherIncludes, cDefines)
case Language.InterpretedC => ColIParser(originProvider, blameProvider)
+ case Language.CPP => ColCPPParser(originProvider, blameProvider, ccpp, cppSystemInclude, cppOtherIncludes, cppDefines)
+ case Language.InterpretedCPP => ColIPPParser(originProvider, blameProvider)
case Language.Java => ColJavaParser(originProvider, blameProvider)
case Language.PVL => ColPVLParser(originProvider, blameProvider)
case Language.Silver => ColSilverParser(originProvider, blameProvider)
diff --git a/src/main/vct/main/stages/Resolution.scala b/src/main/vct/main/stages/Resolution.scala
index d0733cb185..278c491b31 100644
--- a/src/main/vct/main/stages/Resolution.scala
+++ b/src/main/vct/main/stages/Resolution.scala
@@ -2,32 +2,26 @@ package vct.main.stages
import com.typesafe.scalalogging.LazyLogging
import hre.stages.Stage
-import vct.col.ast.{AddrOf, CGlobalDeclaration, Program, Refute, Verification, VerificationContext}
import org.antlr.v4.runtime.CharStreams
-import vct.col.ast.{AddrOf, CGlobalDeclaration, Expr, Program, Refute, VerificationContext}
+import vct.col.ast._
import vct.col.check.CheckError
-import vct.col.rewrite.lang.{LangSpecificToCol, LangTypesToCol}
-import vct.col.origin.{ExpectedError, FileSpanningOrigin, Origin}
-import vct.col.resolve.lang.{C, Java}
+import vct.col.origin.{FileSpanningOrigin, Origin}
+import vct.col.resolve.lang.{C, CPP}
import vct.col.resolve.{Resolve, ResolveReferences, ResolveTypes}
import vct.col.rewrite.Generation
import vct.col.rewrite.bip.IsolateBipGlue
+import vct.col.rewrite.lang.{LangSpecificToCol, LangTypesToCol}
import vct.importer.JavaLibraryLoader
import vct.main.Main.TemporarilyUnsupported
import vct.main.stages.Resolution.InputResolutionError
-import vct.main.stages.Transformation.TransformationCheckError
import vct.options.Options
import vct.options.types.ClassPathEntry
-import vct.parsers.ParseResult
-import vct.parsers.transform.BlameProvider
+import vct.parsers.transform.{BlameProvider, RedirectOriginProvider}
import vct.parsers.{ColJavaParser, FileNotFound, ParseResult}
-import vct.parsers.transform.{BlameProvider, ReadableOriginProvider, RedirectOriginProvider}
import vct.resources.Resources
import vct.result.VerificationError.UserError
-import viper.silver.frontend.DefaultStates.Initial
import java.io.{FileNotFoundException, Reader}
-import java.nio.file.Path
case object Resolution {
case class InputResolutionError(errors: Seq[CheckError]) extends UserError {
@@ -93,6 +87,11 @@ case class Resolution[G <: Generation]
throw TemporarilyUnsupported("GlobalCVariable", Seq(decl))
}
})
+ case decl: CPPGlobalDeclaration[_] => decl.decl.inits.foreach(init => {
+ if (CPP.getDeclaratorInfo(init.decl).params.isEmpty) {
+ throw TemporarilyUnsupported("GlobalCPPVariable", Seq(decl))
+ }
+ })
case _ =>
})
diff --git a/src/main/vct/options/Options.scala b/src/main/vct/options/Options.scala
index c196af97bb..34e8eeec13 100644
--- a/src/main/vct/options/Options.scala
+++ b/src/main/vct/options/Options.scala
@@ -1,10 +1,10 @@
package vct.options
-import scopt.{OParser, OptionDef}
+import scopt.OParser
import scopt.Read._
import vct.main.BuildInfo
import vct.main.stages.Parsing.Language
-import vct.options.types.{Backend, ClassPathEntry, Mode, PathOrStd, ReadLanguage, Verbosity}
+import vct.options.types._
import vct.resources.Resources
import java.nio.file.{Path, Paths}
@@ -344,6 +344,7 @@ case class Options
simplifyPathsAfterRelations: Seq[PathOrStd] = Seq("simplify").map(name => PathOrStd.Path(Resources.getSimplificationPath(name))),
adtPath: Path = Resources.getAdtPath,
cc: Path = Resources.getCcPath,
+ ccpp: Path = Resources.getCPPcPath,
cIncludePath: Path = Resources.getCIncludePath,
classPath: Seq[ClassPathEntry] = Seq(ClassPathEntry.DefaultJre, ClassPathEntry.SourcePackageRoot),
z3Path: Path = viper.api.Resources.getZ3Path,
diff --git a/src/main/vct/options/types/ReadLanguage.scala b/src/main/vct/options/types/ReadLanguage.scala
index aa64ca6c6e..92e8915eca 100644
--- a/src/main/vct/options/types/ReadLanguage.scala
+++ b/src/main/vct/options/types/ReadLanguage.scala
@@ -7,6 +7,8 @@ case object ReadLanguage extends ReadEnum[Language] {
"java" -> Language.Java,
"c" -> Language.C,
"i" -> Language.InterpretedC,
+ "cpp" -> Language.CPP,
+ "ipp" -> Language.InterpretedCPP,
"pvl" -> Language.PVL,
"silver" -> Language.Silver,
"systemc" -> Language.SystemC,
diff --git a/src/main/vct/resources/Resources.scala b/src/main/vct/resources/Resources.scala
index 9507218be9..61af891ad2 100644
--- a/src/main/vct/resources/Resources.scala
+++ b/src/main/vct/resources/Resources.scala
@@ -1,11 +1,7 @@
package vct.resources
-import hre.platform.Platform
-import hre.resource.ResourceUtil.{getPlatformBinary, getResource}
-import vct.result.VerificationError.SystemError
+import hre.resource.ResourceUtil.getResource
-import java.io.File
-import java.net.URISyntaxException
import java.nio.file.{Path, Paths}
case object Resources {
@@ -14,7 +10,9 @@ case object Resources {
def getAdtPath: Path = getResource("/adt")
def getCIncludePath: Path = getResource("/c")
+ def getCPPIncludePath: Path = getResource("/cpp")
def getJrePath: Path = getResource("/jdk")
def getCcPath: Path = Paths.get("clang")
+ def getCPPcPath: Path = Paths.get("clang++")
def getSystemCConfig: Path = getResource("/systemc/config")
}
diff --git a/src/parsers/antlr4/CPPParser.g4 b/src/parsers/antlr4/CPPParser.g4
new file mode 100644
index 0000000000..b029041617
--- /dev/null
+++ b/src/parsers/antlr4/CPPParser.g4
@@ -0,0 +1,19 @@
+parser grammar CPPParser;
+options {tokenVocab = LangCPPLexer;}
+import LangCPPParser, SpecParser;
+
+@parser::members {
+ public int specLevel = 0;
+}
+
+langExpr: expression;
+langId: clangppIdentifier;
+langConstInt: literal;
+langType: typeSpecifier;
+langStatement: statement;
+langStatic: EOF EOF;
+langGlobalDecl: declaration;
+langClassDecl: EOF EOF;
+
+startSpec: LineStartSpec {specLevel++;} | BlockStartSpec {specLevel++;} | BlockStartSpecImmediate {specLevel++;};
+endSpec: EndSpec {specLevel--;};
diff --git a/src/parsers/antlr4/LangCLexer.g4 b/src/parsers/antlr4/LangCLexer.g4
index ad7a04e181..4035d02477 100644
--- a/src/parsers/antlr4/LangCLexer.g4
+++ b/src/parsers/antlr4/LangCLexer.g4
@@ -17,6 +17,7 @@ VAL_TRUE: 'true';
VAL_FALSE: 'false';
VAL_SIZEOF: EOF EOF;
VAL_PACKAGE: 'package';
+CONS: '::';
Placeholder : EOF EOF ;
diff --git a/src/parsers/antlr4/LangCPPLexer.g4 b/src/parsers/antlr4/LangCPPLexer.g4
new file mode 100644
index 0000000000..43f217c708
--- /dev/null
+++ b/src/parsers/antlr4/LangCPPLexer.g4
@@ -0,0 +1,318 @@
+lexer grammar LangCPPLexer;
+import SpecLexer;
+
+@lexer::members {
+ private static boolean inBlockSpec = false;
+ private static boolean inLineSpec = false;
+}
+
+channels {
+ EXPECTED_ERROR_CHANNEL,
+ LINE_DIRECTIVE_CHANNEL
+}
+
+// lexer tokens needed for the SpecParser
+VAL_INLINE: EOF EOF;
+VAL_ASSERT: 'assert';
+VAL_PACKAGE: 'package';
+VAL_BOOL: EOF EOF;
+
+IntegerLiteral:
+ DecimalLiteral Integersuffix?
+ | OctalLiteral Integersuffix?
+ | HexadecimalLiteral Integersuffix?
+ | BinaryLiteral Integersuffix?;
+
+CharacterLiteral:
+ ('u' | 'U' | 'L')? '\'' Cchar+ '\'';
+
+FloatingLiteral:
+ Fractionalconstant Exponentpart? Floatingsuffix?
+ | Digitsequence Exponentpart Floatingsuffix?;
+
+StringLiteral:
+ Encodingprefix?
+ (Rawstring
+ |'"' Schar* '"');
+
+BooleanLiteral: False | True;
+
+PointerLiteral: Nullptr;
+
+UserDefinedLiteral:
+ UserDefinedIntegerLiteral
+ | UserDefinedFloatingLiteral
+ | UserDefinedStringLiteral
+ | UserDefinedCharacterLiteral;
+
+MultiLineMacro:
+ '#' (~[\n]*? '\\' '\r'? '\n')+ ~ [\n]+ -> channel (LINE_DIRECTIVE_CHANNEL);
+
+Directive: '#' ~ [\n]* -> channel (LINE_DIRECTIVE_CHANNEL);
+
+Alignas: 'alignas';
+Alignof: 'alignof';
+Asm: 'asm';
+Auto: 'auto';
+Bool: 'bool';
+Break: 'break';
+Case: 'case';
+Catch: 'catch';
+Char: 'char';
+Char16: 'char16_t';
+Char32: 'char32_t';
+Class: 'class';
+Const: 'const';
+Constexpr: 'constexpr';
+Const_cast: 'const_cast';
+Continue: 'continue';
+Decltype: 'decltype';
+Default: 'default';
+Delete: 'delete';
+Do: 'do';
+Double: 'double';
+Dynamic_cast: 'dynamic_cast';
+Else: 'else';
+Enum: 'enum';
+Explicit: 'explicit';
+Export: 'export';
+Extern: 'extern';
+False: 'false';
+Final: 'final';
+Float: 'float';
+For: 'for';
+Friend: 'friend';
+Goto: 'goto';
+If: 'if';
+Inline: 'inline';
+Int: 'int';
+Long: 'long';
+Mutable: 'mutable';
+Namespace: 'namespace';
+New: 'new';
+Noexcept: 'noexcept';
+Nullptr: 'nullptr';
+Operator: 'operator';
+Override: 'override';
+Private: 'private';
+Protected: 'protected';
+Public: 'public';
+Register: 'register';
+Reinterpret_cast: 'reinterpret_cast';
+Return: 'return';
+Short: 'short';
+Signed: 'signed';
+Sizeof: 'sizeof';
+Static: 'static';
+Static_assert: 'static_assert';
+Static_cast: 'static_cast';
+Struct: 'struct';
+Switch: 'switch';
+Template: 'template';
+This: 'this';
+Thread_local: '_thread_local';
+Throw: 'throw';
+True: 'true';
+Try: 'try';
+Typedef: 'typedef';
+Typeid_: 'typeid';
+Typename_: 'typename';
+Union: 'union';
+Unsigned: 'unsigned';
+Using: 'using';
+Virtual: 'virtual';
+Void: 'void';
+Volatile: 'volatile';
+Wchar: 'wchar_t';
+While: 'while';
+
+LeftParen: '(';
+RightParen: ')';
+LeftBracket: '[';
+RightBracket: ']';
+LeftBrace: '{';
+RightBrace: '}';
+Plus: '+';
+Minus: '-';
+Star: '*';
+Div: '/';
+Mod: '%';
+Caret: '^';
+And: '&';
+Or: '|';
+Tilde: '~';
+Not: '!';
+NotWord: 'not';
+Assign: '=';
+Less: '<';
+Greater: '>';
+PlusAssign: '+=';
+MinusAssign: '-=';
+StarAssign: '*=';
+DivAssign: '/=';
+ModAssign: '%=';
+XorAssign: '^=';
+AndAssign: '&=';
+OrAssign: '|=';
+LeftShiftAssign: '<<=';
+RightShiftAssign: '>>=';
+Equal: '==';
+NotEqual: '!=';
+LessEqual: '<=';
+GreaterEqual: '>=';
+AndAnd: '&&' | 'and';
+OrOr: '||' | 'or';
+PlusPlus: '++';
+MinusMinus: '--';
+Comma: ',';
+ArrowStar: '->*';
+Arrow: '->';
+Question: '?';
+Colon: ':';
+Doublecolon: '::';
+Semi: ';';
+Dot: '.';
+DotStar: '.*';
+Ellipsis: '...';
+fragment Hexquad:
+ HEXADECIMALDIGIT HEXADECIMALDIGIT HEXADECIMALDIGIT HEXADECIMALDIGIT;
+
+fragment Universalcharactername:
+ '\\u' Hexquad
+ | '\\U' Hexquad Hexquad;
+
+fragment Identifiernondigit: NONDIGIT | Universalcharactername;
+
+fragment NONDIGIT: [a-zA-Z_];
+
+fragment DIGIT: [0-9];
+
+DecimalLiteral: NONZERODIGIT ('\''? DIGIT)*;
+
+OctalLiteral: '0' ('\''? OCTALDIGIT)*;
+
+HexadecimalLiteral: ('0x' | '0X') HEXADECIMALDIGIT (
+ '\''? HEXADECIMALDIGIT
+ )*;
+
+BinaryLiteral: ('0b' | '0B') BINARYDIGIT ('\''? BINARYDIGIT)*;
+
+fragment NONZERODIGIT: [1-9];
+
+fragment OCTALDIGIT: [0-7];
+
+fragment HEXADECIMALDIGIT: [0-9a-fA-F];
+
+fragment BINARYDIGIT: [01];
+
+Integersuffix:
+ Unsignedsuffix Longsuffix?
+ | Unsignedsuffix Longlongsuffix?
+ | Longsuffix Unsignedsuffix?
+ | Longlongsuffix Unsignedsuffix?;
+
+fragment Unsignedsuffix: [uU];
+
+fragment Longsuffix: [lL];
+
+fragment Longlongsuffix: 'll' | 'LL';
+
+fragment Cchar:
+ ~ ['\\\r\n]
+ | Escapesequence
+ | Universalcharactername;
+
+fragment Escapesequence:
+ Simpleescapesequence
+ | Octalescapesequence
+ | Hexadecimalescapesequence;
+
+fragment Simpleescapesequence:
+ '\\\''
+ | '\\"'
+ | '\\?'
+ | '\\\\'
+ | '\\a'
+ | '\\b'
+ | '\\f'
+ | '\\n'
+ | '\\r'
+ | ('\\' ('\r' '\n'? | '\n'))
+ | '\\t'
+ | '\\v';
+
+fragment Octalescapesequence:
+ '\\' OCTALDIGIT
+ | '\\' OCTALDIGIT OCTALDIGIT
+ | '\\' OCTALDIGIT OCTALDIGIT OCTALDIGIT;
+
+fragment Hexadecimalescapesequence: '\\x' HEXADECIMALDIGIT+;
+
+fragment Fractionalconstant:
+ Digitsequence? '.' Digitsequence
+ | Digitsequence '.';
+
+fragment Exponentpart:
+ 'e' SIGN? Digitsequence
+ | 'E' SIGN? Digitsequence;
+
+fragment SIGN: [+-];
+
+fragment Digitsequence: DIGIT ('\''? DIGIT)*;
+
+fragment Floatingsuffix: [flFL];
+
+fragment Encodingprefix: 'u8' | 'u' | 'U' | 'L';
+
+fragment Schar:
+ ~ ["\\\r\n]
+ | Escapesequence
+ | Universalcharactername;
+
+fragment Rawstring: 'R"' (( '\\' ["()] )|~[\r\n (])*? '(' ~[)]*? ')' (( '\\' ["()]) | ~[\r\n "])*? '"';
+
+UserDefinedIntegerLiteral:
+ DecimalLiteral Udsuffix
+ | OctalLiteral Udsuffix
+ | HexadecimalLiteral Udsuffix
+ | BinaryLiteral Udsuffix;
+
+UserDefinedFloatingLiteral:
+ Fractionalconstant Exponentpart? Udsuffix
+ | Digitsequence Exponentpart Udsuffix;
+
+UserDefinedStringLiteral: StringLiteral Udsuffix;
+
+UserDefinedCharacterLiteral: CharacterLiteral Udsuffix;
+
+fragment Udsuffix: Identifier;
+
+BlockStartSpecImmediate: '/*' [ \t\u000C]* '@' {inBlockSpec = true;};
+
+BlockCommentStart: '/*' -> mode(COMMENT), skip;
+
+LineCommentStart: '//' -> mode(LINE_COMMENT), skip;
+
+EndSpec:
+ '@'? '*/' {inBlockSpec}? {inBlockSpec = false;}
+ | ('\n'|'\r\n') {inLineSpec}? {inLineSpec = false;};
+
+Whitespace: [ \t]+ -> skip;
+
+Newline: ('\r' '\n'? | '\n') -> skip;
+
+
+mode DEFAULT_MODE;
+Identifier: Identifiernondigit (Identifiernondigit | DIGIT)*;
+
+ExtraAt: ('\n'|'\r\n') [ \t\u000C]* '@' {inBlockSpec}? -> skip;
+
+mode COMMENT;
+BlockCommentStop: '*/' -> mode(DEFAULT_MODE), skip;
+BlockStartSpec: ('\n'|'\r\n') [ \t\u000C]* '@' {inBlockSpec = true;} -> mode(DEFAULT_MODE);
+BlockCommentContent: .+? -> skip;
+
+mode LINE_COMMENT;
+LineCommentStop: ('\n'|'\r\n') -> mode(DEFAULT_MODE), skip;
+LineStartSpec: '@' {inLineSpec = true;} -> mode(DEFAULT_MODE);
+LineCommentContent: .+? -> skip;
\ No newline at end of file
diff --git a/src/parsers/antlr4/LangCPPParser.g4 b/src/parsers/antlr4/LangCPPParser.g4
new file mode 100644
index 0000000000..b38176f9b8
--- /dev/null
+++ b/src/parsers/antlr4/LangCPPParser.g4
@@ -0,0 +1,903 @@
+/*******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Camilo Sanchez (Camiloasc1) 2020 Martin Mirchev (Marti2203)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+ * associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ****************************************************************************
+ */
+
+// Grammar for C++ 14
+parser grammar LangCPPParser;
+
+// Root
+translationUnit: declarationseq? EOF;
+
+// Identifiers
+clangppIdentifier:
+ Identifier
+ | valIdentifier;
+
+// Expressions
+primaryExpression:
+ valExpr
+ | literal+
+ | This
+ | LeftParen expression RightParen
+ | idExpression
+ | lambdaExpression;
+
+annotatedPrimaryExpression: valEmbedWith? primaryExpression valEmbedThen?;
+
+idExpression: unqualifiedId | qualifiedId;
+
+unqualifiedId:
+ clangppIdentifier
+ | operatorFunctionId
+ | conversionFunctionId
+ | literalOperatorId
+ | Tilde (className | decltypeSpecifier)
+ | templateId;
+
+qualifiedId: nestedNameSpecifier Template? unqualifiedId;
+
+nestedNameSpecifier:
+ (theTypeName | namespaceName | decltypeSpecifier)? Doublecolon
+ | nestedNameSpecifier (
+ clangppIdentifier
+ | Template? simpleTemplateId
+ ) Doublecolon;
+
+lambdaExpression:
+ lambdaIntroducer lambdaDeclarator? compoundStatement;
+
+lambdaIntroducer: LeftBracket lambdaCapture? RightBracket;
+
+lambdaCapture:
+ captureList
+ | captureDefault (Comma captureList)?;
+
+captureDefault: And | Assign;
+
+captureList: capture (Comma capture)* Ellipsis?;
+
+capture: simpleCapture | initcapture;
+
+simpleCapture: And? clangppIdentifier | This;
+
+initcapture: And? clangppIdentifier initializer;
+
+lambdaDeclarator:
+ LeftParen parameterDeclarationClause? RightParen Mutable? exceptionSpecification?
+ attributeSpecifierSeq? trailingReturnType?;
+
+postfixExpression:
+ annotatedPrimaryExpression
+ | postfixExpression LeftBracket expression RightBracket
+ | postfixExpression LeftBracket bracedInitList RightBracket
+ | postfixExpression LeftParen expressionList? RightParen valEmbedGiven? valEmbedYields?
+ | postfixExpression Dot Template? idExpression
+ | postfixExpression Dot pseudoDestructorName
+ | postfixExpression Arrow Template? idExpression
+ | postfixExpression Arrow pseudoDestructorName
+ | postfixExpression PlusPlus
+ | postfixExpression MinusMinus
+ | postfixExpression specPostfix
+ | simpleTypeSpecifier LeftParen expressionList? RightParen valEmbedGiven? valEmbedYields?
+ | simpleTypeSpecifier bracedInitList
+ | typeNameSpecifier LeftParen expressionList? RightParen valEmbedGiven? valEmbedYields?
+ | typeNameSpecifier bracedInitList
+ | (
+ Dynamic_cast
+ | Static_cast
+ | Reinterpret_cast
+ | Const_cast
+ ) Less theTypeId Greater LeftParen expression RightParen
+ | typeIdOfTheTypeId LeftParen (expression | theTypeId) RightParen;
+
+specPostfix: {specLevel>0}? valPostfix;
+
+/*
+ add a middle layer to eliminate duplicated function declarations
+ */
+
+typeIdOfTheTypeId: Typeid_;
+
+expressionList: initializerList;
+
+pseudoDestructorName:
+ nestedNameSpecifier? (theTypeName Doublecolon)? Tilde theTypeName
+ | nestedNameSpecifier Template simpleTemplateId Doublecolon Tilde theTypeName
+ | Tilde decltypeSpecifier;
+
+unaryExpression:
+ postfixExpression
+ | PlusPlus unaryExpression
+ | MinusMinus unaryExpression
+ | unaryOperator unaryExpression
+ | Sizeof unaryExpression
+ | Sizeof (
+ LeftParen theTypeId RightParen
+ | Ellipsis LeftParen clangppIdentifier RightParen
+ )
+ | Alignof LeftParen theTypeId RightParen
+ | noExceptExpression
+ | newExpression
+ | deleteExpression
+ | specPrefix unaryExpression;
+
+specPrefix: {specLevel>0}? valPrefix;
+
+unaryOperator: And | Star | Plus | Minus | Tilde | Not | NotWord;
+
+newExpression:
+ Doublecolon? New newPlacement? newTypePtr newInitializer? valEmbedGiven? valEmbedYields?;
+
+newPlacement: LeftParen expressionList RightParen;
+
+newTypePtr:
+ newTypeId
+ | LeftParen theTypeId RightParen;
+
+newTypeId: typeSpecifierSeq newDeclarator?;
+
+newDeclarator:
+ pointerOperator newDeclarator?
+ | noPointerNewDeclarator;
+
+noPointerNewDeclarator:
+ LeftBracket expression RightBracket attributeSpecifierSeq?
+ | noPointerNewDeclarator LeftBracket constantExpression RightBracket attributeSpecifierSeq?;
+
+newInitializer:
+ LeftParen expressionList? RightParen
+ | bracedInitList;
+
+deleteExpression:
+ Doublecolon? Delete (LeftBracket RightBracket)? castExpression;
+
+noExceptExpression: Noexcept LeftParen expression RightParen;
+
+castExpression:
+ unaryExpression
+ | LeftParen theTypeId RightParen castExpression;
+
+pointerMemberExpression:
+ prependExpression
+ | pointerMemberExpression DotStar prependExpression
+ | pointerMemberExpression ArrowStar prependExpression;
+
+prependExpression:
+ castExpression prependOp prependExpression
+ | castExpression;
+
+prependOp: {specLevel>0}? valPrependOp;
+
+multiplicativeExpression:
+ pointerMemberExpression
+ | multiplicativeExpression multiplicativeOp pointerMemberExpression;
+
+multiplicativeOp:
+ Star
+ | Div
+ | Mod
+ | {specLevel>0}? valMulOp;
+
+additiveExpression:
+ multiplicativeExpression
+ | additiveExpression Plus multiplicativeExpression
+ | additiveExpression Minus multiplicativeExpression;
+
+shiftExpression:
+ additiveExpression
+ | shiftExpression Less Less additiveExpression
+ | shiftExpression Greater Greater additiveExpression;
+
+relationalExpression:
+ shiftExpression
+ | relationalExpression relationalOp shiftExpression;
+
+relationalOp:
+ (Less | Greater | LessEqual | GreaterEqual)
+ | {specLevel>0}? valInOp;
+
+equalityExpression:
+ relationalExpression
+ | equalityExpression Equal relationalExpression
+ | equalityExpression NotEqual relationalExpression;
+
+andExpression:
+ equalityExpression
+ | andExpression And equalityExpression;
+
+exclusiveOrExpression:
+ andExpression
+ | exclusiveOrExpression Caret andExpression;
+
+inclusiveOrExpression:
+ exclusiveOrExpression
+ | inclusiveOrExpression Or exclusiveOrExpression;
+
+logicalAndExpression:
+ inclusiveOrExpression
+ | logicalAndExpression logicalAndOp inclusiveOrExpression;
+
+logicalAndOp:
+ AndAnd
+ | {specLevel>0}? valAndOp;
+
+logicalOrExpression:
+ logicalAndExpression
+ | logicalOrExpression OrOr logicalAndExpression;
+
+implicationExpression:
+ logicalOrExpression
+ | logicalOrExpression implicationOp implicationExpression;
+
+implicationOp: {specLevel>0}? valImpOp;
+
+conditionalExpression:
+ implicationExpression
+ | implicationExpression Question expression Colon assignmentExpression;
+
+assignmentExpression:
+ valEmbedWith? conditionalExpression valEmbedThen?
+ | valEmbedWith? logicalOrExpression assignmentOperator initializerClause valEmbedThen?
+ | throwExpression;
+
+assignmentOperator:
+ Assign
+ | StarAssign
+ | DivAssign
+ | ModAssign
+ | PlusAssign
+ | MinusAssign
+ | RightShiftAssign
+ | LeftShiftAssign
+ | AndAssign
+ | XorAssign
+ | OrAssign;
+
+expression:
+ assignmentExpression
+ | expression Comma assignmentExpression;
+
+constantExpression: conditionalExpression;
+
+// Statements
+statement:
+ attributeSpecifierSeq? statementTwo
+ | labeledStatement
+ | blockDeclaration;
+
+statementTwo:
+ expressionStatement
+ | compoundStatement
+ | selectionStatement
+ | iterationStatement
+ | jumpStatement
+ | tryBlock
+ | valEmbedStatementBlock
+ | {specLevel>0}? valStatement;
+
+labeledStatement:
+ attributeSpecifierSeq? (
+ clangppIdentifier
+ | Case constantExpression
+ | Default
+ ) Colon statement;
+
+expressionStatement: expression? Semi;
+
+compoundStatement: LeftBrace statementSeq? RightBrace;
+
+statementSeq: statement+;
+
+selectionStatement:
+ ifStatement
+ | switchStatement;
+
+ifStatement:
+ If LeftParen condition RightParen statement Else statement
+ | If LeftParen condition RightParen statement;
+
+switchStatement: Switch LeftParen condition RightParen statement;
+
+condition:
+ expression
+ | attributeSpecifierSeq? declSpecifierSeq declarator (
+ Assign initializerClause
+ | bracedInitList
+ );
+
+iterationStatement:
+ valEmbedContract? While LeftParen condition RightParen valEmbedContract? statement
+ | Do statement While LeftParen expression RightParen Semi
+ | valEmbedContract? For LeftParen forInitStatement condition? Semi expression? RightParen valEmbedContract? statement
+ | valEmbedContract? For LeftParen forRangeDeclaration Colon forRangeInitializer RightParen valEmbedContract? statement;
+
+forInitStatement: expressionStatement | simpleDeclaration;
+
+forRangeDeclaration:
+ attributeSpecifierSeq? declSpecifierSeq declarator;
+
+forRangeInitializer: expression | bracedInitList;
+
+jumpStatement:
+ Break Semi
+ | Continue Semi
+ | Return expression Semi
+ | Return bracedInitList Semi
+ | Return Semi
+ | Goto clangppIdentifier Semi;
+
+// Declarations
+declarationseq: declaration+;
+
+declaration:
+ blockDeclaration
+ | functionDefinition
+ | templateDeclaration
+ | explicitInstantiation
+ | explicitSpecialization
+ | linkageSpecification
+ | namespaceDefinition
+ | emptyDeclaration
+ | attributeDeclaration
+ | valEmbedGlobalDeclarationBlock;
+
+blockDeclaration:
+ simpleDeclaration
+ | asmDefinition
+ | namespaceAliasDefinition
+ | usingDeclaration
+ | usingDirective
+ | staticAssertDeclaration
+ | aliasDeclaration
+ | opaqueEnumDeclaration;
+
+aliasDeclaration:
+ Using clangppIdentifier attributeSpecifierSeq? Assign theTypeId Semi;
+
+simpleDeclaration:
+ valEmbedContract? declSpecifierSeq? initDeclaratorList? Semi
+ | valEmbedContract? attributeSpecifierSeq declSpecifierSeq? initDeclaratorList Semi;
+
+staticAssertDeclaration:
+ Static_assert LeftParen constantExpression Comma StringLiteral RightParen Semi;
+
+emptyDeclaration: Semi;
+
+attributeDeclaration: attributeSpecifierSeq Semi;
+
+declSpecifier:
+ storageClassSpecifier
+ | typeSpecifier
+ | functionSpecifier
+ | Friend
+ | Typedef
+ | Constexpr
+ | valEmbedModifier;
+
+declSpecifierSeq: declSpecifier+? attributeSpecifierSeq?;
+
+storageClassSpecifier:
+ Register
+ | Static
+ | Thread_local
+ | Extern
+ | Mutable;
+
+functionSpecifier: Inline | Virtual | Explicit;
+
+typedefName: clangppIdentifier;
+
+typeSpecifier:
+ trailingTypeSpecifier
+ | classSpecifier
+ | enumSpecifier;
+
+trailingTypeSpecifier:
+ simpleTypeSpecifier
+ | elaboratedTypeSpecifier
+ | typeNameSpecifier
+ | cvQualifier;
+
+typeSpecifierSeq: typeSpecifier+ attributeSpecifierSeq?;
+
+trailingTypeSpecifierSeq:
+ trailingTypeSpecifier+ attributeSpecifierSeq?;
+
+simpleTypeLengthModifier:
+ Short
+ | Long;
+
+simpleTypeSignednessModifier:
+ Unsigned
+ | Signed;
+
+simpleTypeSpecifier:
+ nestedNameSpecifier? theTypeName
+ | nestedNameSpecifier Template simpleTemplateId
+ | simpleTypeSignednessModifier
+ | simpleTypeSignednessModifier? simpleTypeLengthModifier+
+ | simpleTypeSignednessModifier? Char
+ | simpleTypeSignednessModifier? Char16
+ | simpleTypeSignednessModifier? Char32
+ | simpleTypeSignednessModifier? Wchar
+ | Bool
+ | simpleTypeSignednessModifier? simpleTypeLengthModifier* Int
+ | Float
+ | simpleTypeLengthModifier? Double
+ | Void
+ | Auto
+ | {specLevel>0}? valType
+ | decltypeSpecifier;
+
+theTypeName:
+ className
+ | enumName
+ | typedefName
+ | simpleTemplateId;
+
+decltypeSpecifier:
+ Decltype LeftParen (expression | Auto) RightParen;
+
+elaboratedTypeSpecifier:
+ classKey (
+ attributeSpecifierSeq? nestedNameSpecifier? clangppIdentifier
+ | simpleTemplateId
+ | nestedNameSpecifier Template? simpleTemplateId
+ )
+ | Enum nestedNameSpecifier? clangppIdentifier;
+
+enumName: clangppIdentifier;
+
+enumSpecifier:
+ enumHead LeftBrace (enumeratorList Comma?)? RightBrace;
+
+enumHead:
+ enumkey attributeSpecifierSeq? (
+ nestedNameSpecifier? clangppIdentifier
+ )? enumbase?;
+
+opaqueEnumDeclaration:
+ enumkey attributeSpecifierSeq? clangppIdentifier enumbase? Semi;
+
+enumkey: Enum (Class | Struct)?;
+
+enumbase: Colon typeSpecifierSeq;
+
+enumeratorList:
+ enumeratorDefinition (Comma enumeratorDefinition)*;
+
+enumeratorDefinition: enumerator (Assign constantExpression)?;
+
+enumerator: clangppIdentifier;
+
+namespaceName: originalNamespaceName | namespaceAlias;
+
+originalNamespaceName: clangppIdentifier;
+
+namespaceDefinition:
+ Inline? Namespace (clangppIdentifier | originalNamespaceName)? LeftBrace namespaceBody = declarationseq
+ ? RightBrace;
+
+namespaceAlias: clangppIdentifier;
+
+namespaceAliasDefinition:
+ Namespace clangppIdentifier Assign qualifiednamespacespecifier Semi;
+
+qualifiednamespacespecifier: nestedNameSpecifier? namespaceName;
+
+usingDeclaration:
+ Using ((Typename_? nestedNameSpecifier) | Doublecolon) unqualifiedId Semi;
+
+usingDirective:
+ attributeSpecifierSeq? Using Namespace nestedNameSpecifier? namespaceName Semi;
+
+asmDefinition: Asm LeftParen StringLiteral RightParen Semi;
+
+linkageSpecification:
+ Extern StringLiteral (
+ LeftBrace declarationseq? RightBrace
+ | declaration
+ );
+
+attributeSpecifierSeq: attributeSpecifier+;
+
+attributeSpecifier:
+ LeftBracket LeftBracket attributeList? RightBracket RightBracket
+ | alignmentspecifier;
+
+alignmentspecifier:
+ Alignas LeftParen (theTypeId | constantExpression) Ellipsis? RightParen;
+
+attributeList: attribute (Comma attribute)* Ellipsis?;
+
+attribute: (attributeNamespace Doublecolon)? clangppIdentifier attributeArgumentClause?;
+
+attributeNamespace: clangppIdentifier;
+
+attributeArgumentClause: LeftParen balancedTokenSeq? RightParen;
+
+balancedTokenSeq: balancedtoken+;
+
+balancedtoken:
+ LeftParen balancedTokenSeq RightParen
+ | LeftBracket balancedTokenSeq RightBracket
+ | LeftBrace balancedTokenSeq RightBrace
+ | ~(
+ LeftParen
+ | RightParen
+ | LeftBrace
+ | RightBrace
+ | LeftBracket
+ | RightBracket
+ )+;
+
+// Declarators
+initDeclaratorList:
+ initDeclarator
+ | initDeclaratorList Comma initDeclarator;
+
+initDeclarator: declarator initializer?;
+
+declarator:
+ pointerDeclarator
+ | noPointerDeclarator parametersAndQualifiers trailingReturnType;
+
+pointerDeclarator: pointerDeclaratorPrefix* noPointerDeclarator;
+
+pointerDeclaratorPrefix: pointerOperatorWithDoubleStar Const?;
+
+noPointerDeclarator:
+ declaratorid attributeSpecifierSeq?
+ | noPointerDeclarator parametersAndQualifiers
+ | noPointerDeclarator LeftBracket constantExpression? RightBracket attributeSpecifierSeq?
+ | LeftParen pointerDeclarator RightParen;
+
+parametersAndQualifiers:
+ LeftParen parameterDeclarationClause? RightParen cvqualifierseq? refqualifier?
+ exceptionSpecification? attributeSpecifierSeq?;
+
+trailingReturnType:
+ Arrow trailingTypeSpecifierSeq abstractDeclarator?;
+
+pointerOperator:
+ And attributeSpecifierSeq?
+ | AndAnd attributeSpecifierSeq?
+ | nestedNameSpecifier? Star attributeSpecifierSeq? cvqualifierseq?;
+
+// ** is tokenized separately as separating conjunction,
+// so add special case where ** can be used, which is when
+// multiple pointerOperators are allowed to be repeated after each other
+pointerOperatorWithDoubleStar:
+ pointerOperator
+ | nestedNameSpecifier? SEP_CONJ attributeSpecifierSeq? cvqualifierseq?;
+
+cvqualifierseq: cvQualifier+;
+
+cvQualifier: Const | Volatile;
+
+refqualifier: And | AndAnd;
+
+declaratorid: Ellipsis? idExpression;
+
+theTypeId: typeSpecifierSeq abstractDeclarator?;
+
+abstractDeclarator:
+ pointerAbstractDeclarator
+ | noPointerAbstractDeclarator? parametersAndQualifiers trailingReturnType
+ | abstractPackDeclarator;
+
+pointerAbstractDeclarator:
+ noPointerAbstractDeclarator
+ | pointerOperatorWithDoubleStar+ noPointerAbstractDeclarator?;
+
+noPointerAbstractDeclarator:
+ noPointerAbstractDeclarator (
+ parametersAndQualifiers
+ | noPointerAbstractDeclarator LeftBracket constantExpression? RightBracket
+ attributeSpecifierSeq?
+ )
+ | parametersAndQualifiers
+ | LeftBracket constantExpression? RightBracket attributeSpecifierSeq?
+ | LeftParen pointerAbstractDeclarator RightParen;
+
+abstractPackDeclarator:
+ pointerOperatorWithDoubleStar* noPointerAbstractPackDeclarator;
+
+noPointerAbstractPackDeclarator:
+ noPointerAbstractPackDeclarator (
+ parametersAndQualifiers
+ | LeftBracket constantExpression? RightBracket attributeSpecifierSeq?
+ )
+ | Ellipsis;
+
+parameterDeclarationClause:
+ parameterDeclarationList parameterDeclarationVarargs?;
+
+parameterDeclarationVarargs: Comma? Ellipsis;
+
+parameterDeclarationList:
+ parameterDeclaration (Comma parameterDeclaration)*;
+
+parameterDeclaration:
+ declSpecifierSeq declarator
+ | attributeSpecifierSeq? declSpecifierSeq (
+ (declarator | abstractDeclarator?) (
+ Assign initializerClause
+ )?
+ );
+
+functionDefinition:
+ valEmbedContract? attributeSpecifierSeq? declSpecifierSeq? declarator virtualSpecifierSeq? functionBody;
+
+functionBody:
+ constructorInitializer? compoundStatement
+ | functionTryBlock
+ | Assign (Default | Delete) Semi;
+
+initializer:
+ braceOrEqualInitializer
+ | LeftParen expressionList RightParen;
+
+braceOrEqualInitializer:
+ Assign initializerClause
+ | bracedInitList;
+
+// EW: Had to flip the two options to not get parsing errors
+initializerClause: bracedInitList | assignmentExpression;
+
+initializerList:
+ initializerClause Ellipsis?
+ | initializerList Comma initializerClause Ellipsis?;
+
+bracedInitList:
+ LeftBrace RightBrace
+ | LeftBrace initializerList RightBrace
+ | LeftBrace initializerList Comma RightBrace;
+
+// Classes
+className: clangppIdentifier | simpleTemplateId;
+
+classSpecifier:
+ classHead LeftBrace memberSpecification? RightBrace;
+
+classHead:
+ classKey attributeSpecifierSeq? (
+ classHeadName classVirtSpecifier?
+ )? baseClause?
+ | Union attributeSpecifierSeq? (
+ classHeadName classVirtSpecifier?
+ )?;
+
+classHeadName: nestedNameSpecifier? className;
+
+classVirtSpecifier: Final;
+
+classKey: Class | Struct;
+
+memberSpecification:
+ (memberdeclaration | accessSpecifier Colon)+;
+
+memberdeclaration:
+ attributeSpecifierSeq? declSpecifierSeq? memberDeclaratorList? Semi
+ | functionDefinition
+ | usingDeclaration
+ | staticAssertDeclaration
+ | templateDeclaration
+ | aliasDeclaration
+ | emptyDeclaration;
+
+memberDeclaratorList:
+ memberDeclarator (Comma memberDeclarator)*;
+
+memberDeclarator:
+ declarator (
+ virtualSpecifierSeq? pureSpecifier?
+ | braceOrEqualInitializer?
+ )
+ | clangppIdentifier? attributeSpecifierSeq? Colon constantExpression;
+
+virtualSpecifierSeq: virtualSpecifier+;
+
+virtualSpecifier: Override | Final;
+/*
+ purespecifier: Assign '0'//Conflicts with the lexer ;
+ */
+
+pureSpecifier:
+ Assign val = OctalLiteral {if($val.text.compareTo("0")!=0) throw new InputMismatchException(this);
+ };
+
+//Derived classes
+baseClause: Colon baseSpecifierList;
+
+baseSpecifierList:
+ baseSpecifier Ellipsis? (Comma baseSpecifier Ellipsis?)*;
+
+baseSpecifier:
+ attributeSpecifierSeq? (
+ baseTypeSpecifier
+ | Virtual accessSpecifier? baseTypeSpecifier
+ | accessSpecifier Virtual? baseTypeSpecifier
+ );
+
+classOrDeclType:
+ nestedNameSpecifier? className
+ | decltypeSpecifier;
+
+baseTypeSpecifier: classOrDeclType;
+
+accessSpecifier: Private | Protected | Public;
+
+// Special member functions
+conversionFunctionId: Operator conversionTypeId;
+
+conversionTypeId: typeSpecifierSeq conversionDeclarator?;
+
+conversionDeclarator: pointerOperator conversionDeclarator?;
+
+constructorInitializer: Colon memInitializerList;
+
+memInitializerList:
+ memInitializer Ellipsis? (Comma memInitializer Ellipsis?)*;
+
+memInitializer:
+ meminitializerid (
+ LeftParen expressionList? RightParen
+ | bracedInitList
+ );
+
+meminitializerid: classOrDeclType | clangppIdentifier;
+
+// Overloading
+operatorFunctionId: Operator theOperator;
+
+literalOperatorId:
+ Operator (
+ StringLiteral clangppIdentifier
+ | UserDefinedStringLiteral
+ );
+
+// Templates
+templateDeclaration:
+ Template Less templateparameterList Greater declaration;
+
+templateparameterList:
+ templateParameter (Comma templateParameter)*;
+
+templateParameter: typeParameter | parameterDeclaration;
+
+typeParameter:
+ (
+ (Template Less templateparameterList Greater)? Class
+ | Typename_
+ ) ((Ellipsis? clangppIdentifier?) | (clangppIdentifier? Assign theTypeId));
+
+simpleTemplateId:
+ templateName Less templateArgumentList? Greater;
+
+templateId:
+ simpleTemplateId
+ | (operatorFunctionId | literalOperatorId) Less templateArgumentList? Greater;
+
+templateName: clangppIdentifier;
+
+templateArgumentList:
+ templateArgument Ellipsis? (Comma templateArgument Ellipsis?)*;
+
+templateArgument: theTypeId | constantExpression | idExpression;
+
+typeNameSpecifier:
+ Typename_ nestedNameSpecifier (
+ clangppIdentifier
+ | Template? simpleTemplateId
+ );
+
+explicitInstantiation: Extern? Template declaration;
+
+explicitSpecialization: Template Less Greater declaration;
+
+// Exception handling
+tryBlock: Try compoundStatement handlerSeq;
+
+functionTryBlock:
+ Try constructorInitializer? compoundStatement handlerSeq;
+
+handlerSeq: handler+;
+
+handler:
+ Catch LeftParen exceptionDeclaration RightParen compoundStatement;
+
+exceptionDeclaration:
+ attributeSpecifierSeq? typeSpecifierSeq (
+ declarator
+ | abstractDeclarator
+ )?
+ | Ellipsis;
+
+throwExpression: Throw assignmentExpression?;
+
+exceptionSpecification:
+ dynamicExceptionSpecification
+ | noeExceptSpecification;
+
+dynamicExceptionSpecification:
+ Throw LeftParen typeIdList? RightParen;
+
+typeIdList: theTypeId Ellipsis? (Comma theTypeId Ellipsis?)*;
+
+noeExceptSpecification:
+ Noexcept LeftParen constantExpression RightParen
+ | Noexcept;
+
+// Preprocessing directives
+
+// Lexer
+theOperator:
+ New (LeftBracket RightBracket)?
+ | Delete (LeftBracket RightBracket)?
+ | Plus
+ | Minus
+ | Star
+ | Div
+ | Mod
+ | Caret
+ | And
+ | Or
+ | Tilde
+ | Not
+ | NotWord
+ | Assign
+ | Greater
+ | Less
+ | GreaterEqual
+ | PlusAssign
+ | MinusAssign
+ | StarAssign
+ | ModAssign
+ | XorAssign
+ | AndAssign
+ | OrAssign
+ | Less Less
+ | Greater Greater
+ | RightShiftAssign
+ | LeftShiftAssign
+ | Equal
+ | NotEqual
+ | LessEqual
+ | AndAnd
+ | OrOr
+ | PlusPlus
+ | MinusMinus
+ | Comma
+ | ArrowStar
+ | Arrow
+ | LeftParen RightParen
+ | LeftBracket RightBracket;
+
+literal:
+ IntegerLiteral
+ | CharacterLiteral
+ | FloatingLiteral
+ | StringLiteral
+ | BooleanLiteral
+ | PointerLiteral
+ | UserDefinedLiteral;
+
diff --git a/src/parsers/antlr4/LangJavaLexer.g4 b/src/parsers/antlr4/LangJavaLexer.g4
index 4e93b3eda8..d927f62ff9 100644
--- a/src/parsers/antlr4/LangJavaLexer.g4
+++ b/src/parsers/antlr4/LangJavaLexer.g4
@@ -17,6 +17,7 @@ VAL_ASSERT : EOF EOF;
VAL_TRUE : EOF EOF;
VAL_FALSE : EOF EOF;
VAL_SIZEOF : 'sizeof';
+CONS : '::';
// §3.9 Keywords
diff --git a/src/parsers/antlr4/SpecLexer.g4 b/src/parsers/antlr4/SpecLexer.g4
index 24cf7ab69b..83fac3a509 100644
--- a/src/parsers/antlr4/SpecLexer.g4
+++ b/src/parsers/antlr4/SpecLexer.g4
@@ -21,6 +21,7 @@ STAR: '*';
PIPE: '|';
PLUS: '+';
COLON: ':';
+CONS: '::';
VAL_INLINE: 'inline';
VAL_ASSERT: 'assert';
VAL_TRUE: 'true';
@@ -173,7 +174,6 @@ READ: 'read';
EMPTY: 'empty';
COALESCE: '?.';
-CONS: '::';
FRAC_DIV: '\\';
SEP_CONJ: '**';
IMPLIES: '==>';
diff --git a/src/parsers/vct/parsers/ColCPPParser.scala b/src/parsers/vct/parsers/ColCPPParser.scala
new file mode 100644
index 0000000000..05b79561ff
--- /dev/null
+++ b/src/parsers/vct/parsers/ColCPPParser.scala
@@ -0,0 +1,86 @@
+package vct.parsers
+
+import com.typesafe.scalalogging.LazyLogging
+import hre.io.{RWFile, Readable}
+import org.antlr.v4.runtime.CharStream
+import vct.parsers.CParser.PreprocessorError
+import vct.parsers.transform.{BlameProvider, InterpretedFileOriginProvider, OriginProvider}
+import vct.result.VerificationError.{Unreachable, UserError}
+
+import java.io._
+import java.nio.charset.StandardCharsets
+import java.nio.file.{Path, Paths}
+
+case object CPPParser {
+ case class PreprocessorError(fileName: String, errorCode: Int, error: String) extends UserError {
+ override def code: String = "preprocessorError"
+ override def text: String =
+ s"Preprocesing file $fileName failed with exit code $errorCode:\n$error"
+ }
+}
+
+case class ColCPPParser(override val originProvider: OriginProvider,
+ override val blameProvider: BlameProvider,
+ cc: Path,
+ systemInclude: Path,
+ otherIncludes: Seq[Path],
+ defines: Map[String, String]) extends Parser(originProvider, blameProvider) with LazyLogging {
+
+ def interpret(localInclude: Seq[Path], input: String, output: String): Process = {
+ var command = Seq(cc.toString, "-C", "-E")
+
+ command ++= Seq("-nostdinc")
+ command ++= Seq("-isystem", systemInclude.toAbsolutePath.toString)
+
+ command ++= localInclude.map("-I" + _.toAbsolutePath)
+ command ++= otherIncludes.map("-I" + _.toAbsolutePath.toString)
+ command ++= defines.map { case (k, v) => s"-D$k=$v" }
+ command ++= Seq("-o", output)
+ command :+= input
+
+ logger.debug(command.toString())
+
+ new ProcessBuilder(command:_*).start()
+ }
+
+ override def parse[G](stream: CharStream): ParseResult[G] = {
+ throw Unreachable("Should not parse C++ files from an ANTLR CharStream: they need to be interpreted first!")
+ }
+
+ override def parse[G](readable: Readable): ParseResult[G] =
+ try {
+ val interpreted = File.createTempFile("vercors-interpreted-", ".ipp")
+ interpreted.deleteOnExit()
+
+ val process = interpret(
+ localInclude=Option(Paths.get(readable.fileName).getParent).toSeq,
+ input="-",
+ output=interpreted.toString
+ )
+ new Thread(() => {
+ val writer = new OutputStreamWriter(process.getOutputStream, StandardCharsets.UTF_8)
+ try {
+ readable.read { reader =>
+ val written = reader.transferTo(writer)
+ logger.debug(s"Wrote $written bytes to clang++")
+ }
+ } finally {
+ writer.close()
+ }
+ }).start()
+ process.waitFor()
+
+ if(process.exitValue() != 0) {
+ val writer = new StringWriter()
+ new InputStreamReader(process.getInputStream).transferTo(writer)
+ new InputStreamReader(process.getErrorStream).transferTo(writer)
+ writer.close()
+ throw PreprocessorError(readable.fileName, process.exitValue(), writer.toString)
+ }
+
+ val result = ColIPPParser(InterpretedFileOriginProvider(originProvider, RWFile(interpreted)), blameProvider).parse[G](RWFile(interpreted))
+ result
+ } catch {
+ case _: FileNotFoundException => throw FileNotFound(readable.fileName)
+ }
+}
diff --git a/src/parsers/vct/parsers/ColIPPParser.scala b/src/parsers/vct/parsers/ColIPPParser.scala
new file mode 100644
index 0000000000..c73bb21f13
--- /dev/null
+++ b/src/parsers/vct/parsers/ColIPPParser.scala
@@ -0,0 +1,29 @@
+package vct.parsers
+
+import org.antlr.v4.runtime.{CharStream, CommonTokenStream}
+import vct.antlr4.generated.{CPPParser, LangCPPLexer}
+import vct.parsers.transform.{BlameProvider, CPPToCol, OriginProvider}
+
+case class ColIPPParser(override val originProvider: OriginProvider, override val blameProvider: BlameProvider) extends Parser(originProvider, blameProvider) {
+
+ override def parse[G](stream: CharStream): ParseResult[G] = {
+ try {
+ val lexer = new LangCPPLexer(stream)
+ val tokens = new CommonTokenStream(lexer)
+ originProvider.setTokenStream(tokens)
+ val parser = new CPPParser(tokens)
+
+ val (errors, tree) = noErrorsOrThrow(parser, lexer, originProvider) {
+ val errors = expectedErrors(tokens, LangCPPLexer.EXPECTED_ERROR_CHANNEL, LangCPPLexer.VAL_EXPECT_ERROR_OPEN, LangCPPLexer.VAL_EXPECT_ERROR_CLOSE)
+ val tree = parser.translationUnit()
+ (errors, tree)
+ }
+
+ val decls = CPPToCol[G](originProvider, blameProvider, errors).convert(tree)
+ ParseResult(decls, errors.map(_._3))
+ } catch {
+ case m: MatchError =>
+ throw ParseMatchError(m.getMessage())
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/parsers/vct/parsers/ColIParser.scala b/src/parsers/vct/parsers/ColIParser.scala
index 72bc794f40..86ab58c4bc 100644
--- a/src/parsers/vct/parsers/ColIParser.scala
+++ b/src/parsers/vct/parsers/ColIParser.scala
@@ -2,7 +2,6 @@ package vct.parsers
import org.antlr.v4.runtime.{CharStream, CommonTokenStream}
import vct.antlr4.generated.{CParser, LangCLexer}
-import vct.col.ast.GlobalDeclaration
import vct.parsers.transform.{BlameProvider, CToCol, OriginProvider}
case class ColIParser(override val originProvider: OriginProvider, override val blameProvider: BlameProvider) extends Parser(originProvider, blameProvider) {
diff --git a/src/parsers/vct/parsers/transform/CPPToCol.scala b/src/parsers/vct/parsers/transform/CPPToCol.scala
new file mode 100644
index 0000000000..77e17105af
--- /dev/null
+++ b/src/parsers/vct/parsers/transform/CPPToCol.scala
@@ -0,0 +1,1296 @@
+package vct.parsers.transform
+
+import org.antlr.v4.runtime.{ParserRuleContext, Token}
+import vct.antlr4.generated.CPPParser._
+import vct.antlr4.generated.CPPParserPatterns._
+import vct.col.ast._
+import vct.col.ast.`type`.TFloats
+import vct.col.origin._
+import vct.col.ref.{Ref, UnresolvedRef}
+import vct.col.util.AstBuildHelpers
+import vct.col.util.AstBuildHelpers._
+import vct.col.{ast => col}
+
+import scala.annotation.nowarn
+import scala.jdk.CollectionConverters._
+
+@nowarn("msg=match may not be exhaustive&msg=Some\\(")
+case class CPPToCol[G](override val originProvider: OriginProvider, override val blameProvider: BlameProvider, override val errors: Seq[(Token, Token, ExpectedError)])
+ extends ToCol(originProvider, blameProvider, errors) {
+
+ def convert(implicit unit: TranslationUnitContext): Seq[GlobalDeclaration[G]] = unit match {
+ case TranslationUnit0(maybeDeclSeq, _) => Seq(new CPPTranslationUnit(maybeDeclSeq.toSeq.flatMap(convert(_))))
+ }
+
+ def convert(implicit declSeq: DeclarationseqContext): Seq[GlobalDeclaration[G]] = declSeq match {
+ case Declarationseq0(decls) => decls.flatMap(convert(_))
+ }
+
+ // Only support block declarations, function declarations, empty declarations, and VerCors global declarations
+ def convert(implicit decl: DeclarationContext): Seq[GlobalDeclaration[G]] = decl match {
+ case Declaration0(blockDecl) => Seq(new CPPGlobalDeclaration(convert(blockDecl)))
+ case Declaration1(funcDecl) => Seq(convert(funcDecl))
+ case Declaration7(_) => Seq()
+ case Declaration9(globalSpecDecl) => convert(globalSpecDecl)
+ case x => ??(x)
+ }
+
+ // Not supporting attribute specifiers and virtual specifiers
+ def convert(implicit funcDef: FunctionDefinitionContext): CPPFunctionDefinition[G] = funcDef match {
+ case FunctionDefinition0(maybeContract, None, maybeDeclSpecs, declarator, None, body) =>
+ withContract(maybeContract, contract =>
+ new CPPFunctionDefinition(contract.consumeApplicableContract(blame(funcDef)), maybeDeclSpecs.toSeq.flatMap(convert(_)), convert(declarator), convert(body))(blame(funcDef))
+ )
+ case x => ??(x)
+ }
+
+ // Not supporting try blocks, '= default;', '= delete;', and constructor initializer ': name1, name2'
+ def convert(implicit funcBody: FunctionBodyContext): Statement[G] = funcBody match {
+ case FunctionBody0(None, compoundStmnt) => convert(compoundStmnt)
+ case x => ??(x)
+ }
+
+ def convert(implicit compoundStmnt: CompoundStatementContext): Statement[G] = compoundStmnt match {
+ case CompoundStatement0(_, None, _) => Scope(Nil, Block(Seq()))
+ case CompoundStatement0(_, Some(stmntSeq), _) => Scope(Nil, Block(convert(stmntSeq)))
+ }
+
+ def convert(implicit stmntSeq: StatementSeqContext): Seq[Statement[G]] = stmntSeq match {
+ case StatementSeq0(stmnts) => stmnts.map(convert(_))
+ }
+
+ // Do not support labeled statements and attribute specifiers before them
+ def convert(implicit stmnt: StatementContext): Statement[G] = stmnt match {
+ case Statement0(None, stmnt2) => convert(stmnt2)
+ case Statement2(blockDecl) => CPPDeclarationStatement(new CPPLocalDeclaration(convert(blockDecl)))
+ case x => ??(x)
+ }
+
+ // Do not support try blocks
+ def convert(implicit stmnt: StatementTwoContext): Statement[G] = stmnt match {
+ case StatementTwo0(exprStmnt) => convert(exprStmnt)
+ case StatementTwo1(compoundStmnt) => convert(compoundStmnt)
+ case StatementTwo2(selectionStmnt) => convert(selectionStmnt)
+ case StatementTwo3(iterStmnt) => convert(iterStmnt)
+ case StatementTwo4(jumpStmnt) => convert(jumpStmnt)
+ case StatementTwo6(embedStats) => convert(embedStats)
+ case StatementTwo7(embedStat) => convert(embedStat)
+ case x => ??(x)
+ }
+
+ // Do not support asm definitions, namespace alias definitions, using declarations and directives,
+ // static assert declarations, alias declarations, and opaque enum declarations
+ def convert(implicit blockDecl: BlockDeclarationContext): CPPDeclaration[G] = blockDecl match {
+ case BlockDeclaration0(simpleDecl) => convert(simpleDecl)
+ case x => ??(x)
+ }
+
+ // Not supporting attribute specifiers
+ def convert(implicit simpleDecl: SimpleDeclarationContext): CPPDeclaration[G] = simpleDecl match {
+ case SimpleDeclaration0(maybeContract, Some(declSpecs), maybeInits, _) =>
+ withContract(maybeContract, contract =>
+ new CPPDeclaration[G](contract.consumeApplicableContract(blame(simpleDecl)),
+ specs = convert(declSpecs), inits = maybeInits.map(convert(_)) getOrElse Nil)
+ )
+ case x => ??(x)
+ }
+
+ def convert(implicit exprStmnt: ExpressionStatementContext): Statement[G] = exprStmnt match {
+ case ExpressionStatement0(None, _) => Block(Nil)
+ case ExpressionStatement0(Some(expr), _) => Eval(convert(expr))
+ }
+
+ def convert(implicit expr: ExpressionContext): Expr[G] = expr match {
+ case Expression0(inner) => convert(inner)
+ case Expression1(first, _, result) => With(Eval(convert(first)), convert(result))
+ }
+
+ // Do not support switch statement
+ def convert(implicit selectionStmnt: SelectionStatementContext): Statement[G] = selectionStmnt match {
+ case SelectionStatement0(ifStmnt) => convert(ifStmnt)
+ case x => ??(x)
+ }
+
+ def convert(implicit ifStmnt: IfStatementContext): Statement[G] = ifStmnt match {
+ case IfStatement0(_, _, cond, _, whenTrue, _, whenFalse) => Branch(Seq((convert(cond), convert(whenTrue)), (tt, convert(whenFalse))))
+ case IfStatement1(_, _, cond, _, whenTrue) => Branch(Seq((convert(cond), convert(whenTrue))))
+ }
+
+ // Do not support do-while loops, 'for(item : list) {}' and expression instead of declaration in a for-loop
+ def convert(implicit iterStmnt: IterationStatementContext): Statement[G] = iterStmnt match {
+ case IterationStatement0(contract1, _, _, cond, _, contract2, body) => withContract(contract1, contract2, c => {
+ Scope(Nil, Loop[G](Block(Nil), convert(cond), Block(Nil), c.consumeLoopContract(iterStmnt), convert(body)))
+ })
+ case IterationStatement1(_, _, _, _, _, _, _) => ??(iterStmnt)
+ case IterationStatement2(contract1, _, _, ForInitStatement1(simpleDecl), cond, _, update, _, contract2, body) =>
+ withContract(contract1, contract2, c => {
+ Scope(Nil, Loop[G](CPPDeclarationStatement(new CPPLocalDeclaration(convert(simpleDecl))), cond.map(convert(_)).getOrElse(tt), evalOrNop(update), c.consumeLoopContract(iterStmnt), convert(body)))
+ })
+ case x => ??(x)
+ }
+
+ // Do not support goto or return of a bracedInitList
+ def convert(implicit jumpStmnt: JumpStatementContext): Statement[G] = jumpStmnt match {
+ case JumpStatement0(_, _) => col.Break(None)
+ case JumpStatement1(_, _) => col.Continue(None)
+ case JumpStatement2(_, expr, _) => col.Return(convert(expr))
+ case JumpStatement4(_, _) => col.Return(col.Void())
+ case x => ??(x)
+ }
+
+ // Do not support assignments in condition
+ def convert(implicit cond: ConditionContext): Expr[G] = cond match {
+ case Condition0(expr) => convert(expr)
+ case x => ??(x)
+ }
+
+ // Do not support throw expression
+ def convert(implicit expr: AssignmentExpressionContext): Expr[G] = expr match {
+ case AssignmentExpression0(pre, inner, post) =>
+ convertEmbedWith(pre, convertEmbedThen(post, convert(inner)))
+ case AssignmentExpression1(pre, targetNode, op, valueNode, post) =>
+ val e = convert(op, targetNode, valueNode, expr)
+ convertEmbedWith(pre, convertEmbedThen(post, e))
+ case x => ??(x)
+ }
+
+ // Do not support bit operators
+ def convert(op: AssignmentOperatorContext, targetNode: LogicalOrExpressionContext, valueNode: InitializerClauseContext, expr: AssignmentExpressionContext)(implicit o: Origin): Expr[G] = {
+ val target = convert(targetNode)
+ val value = convert(valueNode)
+ PreAssignExpression(target, op match {
+ case AssignmentOperator0(_) => value
+ case AssignmentOperator1(_) => AmbiguousMult(target, value)
+ case AssignmentOperator2(_) => FloorDiv(target, value)(blame(expr))
+ case AssignmentOperator3(_) => col.Mod(target, value)(blame(expr))
+ case AssignmentOperator4(_) => col.AmbiguousPlus(target, value)(blame(valueNode))
+ case AssignmentOperator5(_) => col.AmbiguousMinus(target, value)(blame(valueNode))
+ case _ => ??(op)
+ })(blame(expr))
+ }
+
+ def convert(implicit expr: ConditionalExpressionContext): Expr[G] = expr match {
+ case ConditionalExpression0(inner) => convert(inner)
+ case ConditionalExpression1(cond, _, whenTrue, _, whenFalse) =>
+ Select(convert(cond), convert(whenTrue), convert(whenFalse))
+ }
+
+ def convert(implicit expr: ImplicationExpressionContext): Expr[G] = expr match {
+ case ImplicationExpression0(inner) => convert(inner)
+ case ImplicationExpression1(left, op, right) => convert(op, convert(left), convert(right))
+ }
+
+ def convert(op: ImplicationOpContext, left: Expr[G], right: Expr[G])(implicit o: Origin): Expr[G] = op match {
+ case ImplicationOp0(ValImpOp0(_)) => Wand(left, right)
+ case ImplicationOp0(ValImpOp1(_)) => Implies(left, right)
+ }
+
+ def convert(implicit expr: LogicalOrExpressionContext): Expr[G] = expr match {
+ case LogicalOrExpression0(inner) => convert(inner)
+ case LogicalOrExpression1(left, _, right) => AmbiguousOr(convert(left), convert(right))
+ }
+
+ def convert(implicit expr: LogicalAndExpressionContext): Expr[G] = expr match {
+ case LogicalAndExpression0(inner) => convert(inner)
+ case LogicalAndExpression1(left, op, right) => op match {
+ case LogicalAndOp0(_) => col.And(convert(left), convert(right))
+ case LogicalAndOp1(valOp) => convert(expr, valOp, convert(left), convert(right))
+ }
+ }
+
+ def convert(implicit expr: InclusiveOrExpressionContext): Expr[G] = expr match {
+ case InclusiveOrExpression0(inner) => convert(inner)
+ case InclusiveOrExpression1(left, _, right) => BitOr(convert(left), convert(right))
+ }
+
+ def convert(implicit expr: ExclusiveOrExpressionContext): Expr[G] = expr match {
+ case ExclusiveOrExpression0(inner) => convert(inner)
+ case ExclusiveOrExpression1(left, _, right) => BitXor(convert(left), convert(right))
+ }
+
+ def convert(implicit expr: AndExpressionContext): Expr[G] = expr match {
+ case AndExpression0(inner) => convert(inner)
+ case AndExpression1(left, _, right) => BitAnd(convert(left), convert(right))
+ }
+
+ def convert(implicit expr: EqualityExpressionContext): Expr[G] = expr match {
+ case EqualityExpression0(inner) => convert(inner)
+ case EqualityExpression1(left, _, right) => Eq(convert(left), convert(right))
+ case EqualityExpression2(left, _, right) => Neq(convert(left), convert(right))
+ }
+
+ def convert(implicit expr: RelationalExpressionContext): Expr[G] = expr match {
+ case RelationalExpression0(inner) => convert(inner)
+ case RelationalExpression1(left, RelationalOp0(op), right) => op match {
+ case "<" => col.AmbiguousLess(convert(left), convert(right))
+ case ">" => col.AmbiguousGreater(convert(left), convert(right))
+ case "<=" => AmbiguousLessEq(convert(left), convert(right))
+ case ">=" => AmbiguousGreaterEq(convert(left), convert(right))
+ }
+ case RelationalExpression1(left, RelationalOp1(specOp), right) =>
+ convert(expr, specOp, convert(left), convert(right))
+ }
+
+ def convert(implicit expr: ShiftExpressionContext): Expr[G] = expr match {
+ case ShiftExpression0(inner) => convert(inner)
+ case ShiftExpression1(left, _, _, right) => BitShl(convert(left), convert(right))
+ case ShiftExpression2(left, _, _, right) => BitShr(convert(left), convert(right))
+ }
+
+ def convert(implicit expr: AdditiveExpressionContext): Expr[G] = expr match {
+ case AdditiveExpression0(inner) => convert(inner)
+ case AdditiveExpression1(left, _, right) => AmbiguousPlus(convert(left), convert(right))(blame(expr))
+ case AdditiveExpression2(left, _, right) => col.AmbiguousMinus(convert(left), convert(right))(blame(expr))
+ }
+
+ def convert(implicit expr: MultiplicativeExpressionContext): Expr[G] = expr match {
+ case MultiplicativeExpression0(inner) => convert(inner)
+ case MultiplicativeExpression1(left, op, right) => op match {
+ case MultiplicativeOp0(_) => AmbiguousMult(convert(left), convert(right))
+ case MultiplicativeOp1(_) => FloorDiv(convert(left), convert(right))(blame(expr))
+ case MultiplicativeOp2(_) => col.Mod(convert(left), convert(right))(blame(expr))
+ case MultiplicativeOp3(_) => col.Div(convert(left), convert(right))(blame(expr))
+ }
+ }
+
+ // Do not support operators .* and ->*
+ def convert(implicit expr: PointerMemberExpressionContext): Expr[G] = expr match {
+ case PointerMemberExpression0(inner) => convert(inner)
+ case x => ??(x)
+ }
+
+ def convert(implicit expr: PrependExpressionContext): Expr[G] = expr match {
+ case PrependExpression0(left, PrependOp0(specOp), right) => convert(expr, specOp, convert(left), convert(right))
+ case PrependExpression1(inner) => convert(inner)
+ }
+
+ // Do not support cast expressions
+ def convert(expr: CastExpressionContext): Expr[G] = expr match {
+ case CastExpression0(inner) => convert(inner)
+ case CastExpression1(_, typeName, _, expr) => ??(expr)
+ }
+
+ // Do not support bracedInitList
+ def convert(implicit initClause: InitializerClauseContext): Expr[G] = initClause match {
+ case InitializerClause0(expr) => ??(expr)
+ case InitializerClause1(expr) => convert(expr)
+ }
+
+ // Do not support '...'
+ def convert(implicit expr: InitializerListContext): Seq[Expr[G]] = expr match {
+ case InitializerList0(initClause, None) => Seq(convert(initClause))
+ case InitializerList1(initList, _, initClause, None) => convert(initList) :+ convert(initClause)
+ case x => ??(x)
+ }
+
+ // Do not support sizeof, alignof, noexcept, and delete expressions
+ def convert(implicit expr: UnaryExpressionContext): Expr[G] = expr match {
+ case UnaryExpression0(inner) => convert(inner)
+ case UnaryExpression1(_, arg) =>
+ val target = convert(arg)
+ PreAssignExpression(target, col.AmbiguousPlus(target, const(1))(blame(expr)))(blame(expr))
+ case UnaryExpression2(_, arg) =>
+ val target = convert(arg)
+ PreAssignExpression(target, col.AmbiguousMinus(target, const(1))(blame(expr)))(blame(expr))
+ case UnaryExpression3(UnaryOperator0(_), arg) => AddrOf(convert(arg))
+ case UnaryExpression3(UnaryOperator1(_), arg) => DerefPointer(convert(arg))(blame(expr))
+ case UnaryExpression3(UnaryOperator2(_), arg) => convert(arg)
+ case UnaryExpression3(UnaryOperator3(_), arg) => UMinus(convert(arg))
+ case UnaryExpression3(UnaryOperator5(_), arg) => col.Not(convert(arg))
+ case UnaryExpression3(UnaryOperator6(_), arg) => col.Not(convert(arg))
+ case UnaryExpression8(expr) => ??(expr)
+ case UnaryExpression10(SpecPrefix0(op), inner) => convert(expr, op, convert(inner))
+ case x => ??(x)
+ }
+
+ def convert(implicit decls: InitDeclaratorListContext): Seq[CPPInit[G]] = decls match {
+ case InitDeclaratorList0(decl) => Seq(convert(decl))
+ case InitDeclaratorList1(init, _, last) => convert(init) :+ convert(last)
+ }
+
+ def convert(implicit decl: InitDeclaratorContext): CPPInit[G] = decl match {
+ case InitDeclarator0(inner, None) => CPPInit(convert(inner), None)
+ case InitDeclarator0(inner, Some(init)) => CPPInit(convert(inner), Some(convert(init)))
+ }
+
+ def convert(implicit expr: InitializerContext): Expr[G] = expr match {
+ case Initializer0(expr) => convert(expr)
+ case Initializer1(_, _, _) => ??(expr)
+ }
+
+ // Do not support bracedInitList
+ def convert(implicit expr: BraceOrEqualInitializerContext): Expr[G] = expr match {
+ case BraceOrEqualInitializer0(_, expr) => convert(expr)
+ case BraceOrEqualInitializer1(expr) => ??(expr)
+ }
+
+ // Do not support templactes, typeNameSpecifiers, bracedInitLists,
+ def convert(implicit expr: PostfixExpressionContext): Expr[G] = expr match {
+ case PostfixExpression0(inner) => convert(inner)
+ case PostfixExpression1(arr, _, idx, _) => AmbiguousSubscript(convert(arr), convert(idx))(blame(expr))
+ case PostfixExpression3(target, _, args, _, given, yields) =>
+ CPPInvocation(convert(target), args.map(convert(_)) getOrElse Nil,
+ convertEmbedGiven(given), convertEmbedYields(yields))(blame(expr))
+ case PostfixExpression8(targetNode, _) =>
+ val target = convert(targetNode)
+ PostAssignExpression(target, col.AmbiguousPlus(target, const(1))(blame(expr)))(blame(expr))
+ case PostfixExpression9(targetNode, _) =>
+ val target = convert(targetNode)
+ PostAssignExpression(target, col.AmbiguousMinus(target, const(1))(blame(expr)))(blame(expr))
+ case PostfixExpression10(e, SpecPostfix0(postfix)) => convert(expr, postfix, convert(e))
+ case x => ??(x)
+ }
+
+ def convert(implicit exprList: ExpressionListContext): Seq[Expr[G]] = exprList match {
+ case ExpressionList0(initList) => convert(initList)
+ }
+
+ def convert(implicit expr: AnnotatedPrimaryExpressionContext): Expr[G] = expr match {
+ case AnnotatedPrimaryExpression0(pre, inner, post) =>
+ convertEmbedWith(pre, convertEmbedThen(post, convert(inner)))
+ }
+
+ // Dot not support lambdas, or more than 1 literal
+ def convert(implicit expr: PrimaryExpressionContext): Expr[G] = expr match {
+ case PrimaryExpression0(inner) => convert(inner)
+ case PrimaryExpression1(literals) if literals.length == 1 => convert(literals.head)
+ case PrimaryExpression2(_) => AmbiguousThis()
+ case PrimaryExpression3(_, inner, _) => convert(inner)
+ case PrimaryExpression4(inner) => local(expr, convert(inner).name)
+ case x => ??(x)
+ }
+
+ // Do not support extended chars and strings and user-defined literals
+ def convert(implicit literal: LiteralContext): Expr[G] = literal match {
+ case Literal0(intLit) => parseInt(intLit).getOrElse(??(literal))
+ case Literal1(charLit) => parseChar(charLit).getOrElse(??(literal))
+ case Literal2(floatLit) => parseFloat(floatLit).getOrElse(??(literal))
+ case Literal3(strLit) => parseString(strLit).getOrElse(??(literal))
+ case Literal4(value) => BooleanValue(value == "true")
+ case Literal5(_) => Null()
+ case Literal6(_) => ??(literal)
+ }
+
+ def convert(implicit idExpr: IdExpressionContext): CPPName[G] = idExpr match {
+ case IdExpression0(id) => convert(id)
+ case IdExpression1(id) => convert(id)
+ }
+
+ def parseFloat(numFlag: String)(implicit o: Origin): Option[Expr[G]] = {
+ try {
+ Some(numFlag.last match {
+ case 'f' | 'F' => FloatValue(BigDecimal(numFlag.init), TFloats.ieee754_32bit)
+ case 'l' | 'L' => FloatValue(BigDecimal(numFlag.init), TFloats.ieee754_64bit)
+ case _ => FloatValue(BigDecimal(numFlag), TFloats.ieee754_32bit)
+ })
+ } catch {
+ case _: NumberFormatException => None
+ }
+ }
+
+ def parseInt(i: String)(implicit o: Origin): Option[Expr[G]] =
+ try {
+ Some(IntegerValue(BigInt(i)))
+ } catch {
+ case _: NumberFormatException => None
+ }
+
+ private def parseChar(value: String)(implicit o: Origin): Option[Expr[G]] = {
+ val fixedValue = fixEscapeAndUnicodeChars(value)
+ val pattern = "^'(.|\n|\r)'$".r
+ fixedValue match {
+ case pattern(char, _*) => Some(CharValue(char.codePointAt(0)))
+ case _ => None
+ }
+ }
+
+ private def parseString(value: String)(implicit o: Origin): Option[Expr[G]] = {
+ val fixedValue = fixEscapeAndUnicodeChars(value)
+ val pattern = "^\"((.|\n|\r)*)\"$".r
+ fixedValue match {
+ case pattern(str, _*) => Some(StringValue(str))
+ case _ => None
+ }
+ }
+
+ // ANTLR separates escape sequences such into separate characters, so '\n' will be '\' and 'n'
+ // This function combines them back into 1 character
+ private def fixEscapeAndUnicodeChars(str: String): String = {
+ var result = str
+
+ val unicodePattern = "\\\\u([0-9a-fA-F]{4})".r
+ var patMatchOpt = unicodePattern.findFirstMatchIn(result)
+ while (patMatchOpt.isDefined) {
+ val patMatch = patMatchOpt.get
+ result = result.substring(0, patMatch.start) + new String(patMatch.group(1).sliding(2, 2).toArray.map(Integer.parseInt(_, 16).toByte), "UNICODE") + result.substring(patMatch.end)
+ patMatchOpt = unicodePattern.findFirstMatchIn(result)
+ }
+
+ val escapePattern = "\\\\(['\"\\\\nrt])".r
+ val escapeMap: Map[String, String] = Map("'" -> "'", "\"" -> "\"", "\\" -> "\\", "n" -> "\n", "r" -> "\r", "t" -> "\t")
+ patMatchOpt = escapePattern.findFirstMatchIn(result)
+ while (patMatchOpt.isDefined) {
+ val patMatch = patMatchOpt.get
+ result = result.substring(0, patMatch.start) + escapeMap(patMatch.group(1)) + result.substring(patMatch.end)
+ patMatchOpt = unicodePattern.findFirstMatchIn(result)
+ }
+
+ result
+ }
+
+ // Not supporting attribute specifiers
+ def convert(implicit declSpecSeq: DeclSpecifierSeqContext): Seq[CPPDeclarationSpecifier[G]] = declSpecSeq match {
+ case DeclSpecifierSeq0(declSpec, None) => declSpec.flatMap(convert(_))
+ case x => ??(x)
+ }
+
+ // Do not support storage specifiers, function specifiers, friends, typedefs, consts.
+ def convert(implicit declSpec: DeclSpecifierContext): Seq[CPPDeclarationSpecifier[G]] = declSpec match {
+ case DeclSpecifier1(typeSpec) => convert(typeSpec)
+ case DeclSpecifier6(valEmbedModifier) => withModifiers(valEmbedModifier, m => {
+ if (m.consume(m.pure))
+ Seq(new CPPPure[G]())
+ else if (m.consume(m.inline))
+ Seq(new CPPInline[G]())
+ else
+ fail(m.nodes.head, "This modifier cannot be attached to a declaration in C++")
+ })
+ case x => ??(x)
+ }
+
+ // Do not support enum or class declarations, such as 'class className { members }' as type specifiers
+ def convert(implicit typeSpec: TypeSpecifierContext): Seq[CPPTypeSpecifier[G]] = typeSpec match {
+ case TypeSpecifier0(trailingTypeSpec) => convert(trailingTypeSpec)
+ case x => ??(x)
+ }
+
+ // Do not support elaboratedTypeSpec, typeNameSpec, and cvQualifier
+ def convert(implicit typeSpec: TrailingTypeSpecifierContext): Seq[CPPTypeSpecifier[G]] = typeSpec match {
+ case TrailingTypeSpecifier0(simpleTypeSpec) => convert(simpleTypeSpec)
+ case x => ??(x)
+ }
+
+ // Do not support types: template, char16_t, char32_t, wchar_t, auto, decltype()
+ def convert(implicit typeSpec: SimpleTypeSpecifierContext): Seq[CPPTypeSpecifier[G]] = typeSpec match {
+ case SimpleTypeSpecifier0(Some(nestedNameSpec), typeName) => convert(nestedNameSpec) :+ convert(typeName)
+ case SimpleTypeSpecifier0(None, typeName) => Seq(convert(typeName))
+ case SimpleTypeSpecifier2(signedness) => Seq(convert(signedness))
+ case SimpleTypeSpecifier3(Some(signedness), typeLengthMods) => Seq(convert(signedness)) ++ typeLengthMods.map(convert(_))
+ case SimpleTypeSpecifier3(None, typeLengthMods) => typeLengthMods.map(convert(_))
+ case SimpleTypeSpecifier4(Some(signedness), _) => Seq(convert(signedness), new CPPChar[G]())
+ case SimpleTypeSpecifier4(None, _) => Seq(new CPPChar[G]())
+ case SimpleTypeSpecifier8(_) => Seq(new CPPBool[G]())
+ case SimpleTypeSpecifier9(Some(signedness), typeLengthMods, _) => Seq(convert(signedness)) ++ typeLengthMods.map(convert(_)) :+ new CPPInt[G]()
+ case SimpleTypeSpecifier9(None, typeLengthMods, _) => typeLengthMods.map(convert(_)) :+ new CPPInt[G]()
+ case SimpleTypeSpecifier10(_) => Seq(CPPSpecificationType(TFloats.ieee754_32bit))
+ case SimpleTypeSpecifier11(Some(typeLengthMod), _) => Seq(convert(typeLengthMod), CPPSpecificationType(TFloats.ieee754_64bit))
+ case SimpleTypeSpecifier11(None, _) => Seq(CPPSpecificationType(TFloats.ieee754_64bit))
+ case SimpleTypeSpecifier12(_) => Seq(new CPPVoid[G]())
+ case SimpleTypeSpecifier14(valType) => Seq(CPPSpecificationType(convert(valType)))
+ case x => ??(x)
+ }
+
+ def convert(implicit signedness: SimpleTypeSignednessModifierContext): CPPTypeSpecifier[G] = signedness match {
+ case SimpleTypeSignednessModifier0(_) => new CPPUnsigned[G]()
+ case SimpleTypeSignednessModifier1(_) => new CPPSigned[G]()
+ }
+
+ def convert(implicit simpleTypeLengthMod: SimpleTypeLengthModifierContext): CPPTypeSpecifier[G] = simpleTypeLengthMod match {
+ case SimpleTypeLengthModifier0(_) => new CPPShort[G]()
+ case SimpleTypeLengthModifier1(_) => new CPPLong[G]()
+ }
+
+ // Do not support template, namespaces or decltypes
+ def convert(implicit nestedNameSpec: NestedNameSpecifierContext): Seq[CPPTypeSpecifier[G]] = nestedNameSpec match {
+ case value: NestedNameSpecifier0Context =>
+ if (value.theTypeName() != null) {
+ Seq(convert(value.theTypeName()))
+ } else if (value.namespaceName() != null) {
+ ??(value.namespaceName())
+ } else if (value.decltypeSpecifier() != null) {
+ ??(value.decltypeSpecifier())
+ } else {
+ ??(value)
+ }
+ case value: NestedNameSpecifier1Context =>
+ if (value.simpleTemplateId() != null) {
+ ??(value.simpleTemplateId())
+ } else {
+ convert(value.nestedNameSpecifier()) :+ CPPTypedefName(convert(value.clangppIdentifier()))
+ }
+ }
+
+ // Do not support enum-names, typedef-names and template-names
+ def convert(implicit theTypeName: TheTypeNameContext): CPPTypeSpecifier[G] = theTypeName match {
+ case TheTypeName0(className) => convert(className)
+ case x => ??(x)
+ }
+
+ // Do not support template-names
+ def convert(implicit className: ClassNameContext): CPPTypeSpecifier[G] = className match {
+ case value: ClassName0Context => CPPTypedefName(convert(value.clangppIdentifier()))
+ case x => ??(x)
+ }
+
+ // Do not support trailing return types
+ def convert(implicit declarator: DeclaratorContext): CPPDeclarator[G] = declarator match {
+ case Declarator0(pointerDeclarator) => convert(pointerDeclarator)
+ case Declarator1(_, _, _) => ??(declarator)
+ }
+
+ def convert(implicit pointerDeclarator: PointerDeclaratorContext): CPPDeclarator[G] = pointerDeclarator match {
+ case PointerDeclarator0(pointerDeclaratorPrefix, noPointerDeclarator)
+ if pointerDeclaratorPrefix.isEmpty => convert(noPointerDeclarator)
+ case PointerDeclarator0(pointerDeclaratorPrefix, noPointerDeclarator)
+ if pointerDeclaratorPrefix.nonEmpty =>
+ val pointers = pointerDeclaratorPrefix.flatMap(convert(_))
+ CPPPointerDeclarator(pointers, convert(noPointerDeclarator))
+ }
+
+ // Do not support postfix 'const'
+ def convert(implicit pointer: PointerDeclaratorPrefixContext): Seq[CPPPointer[G]] = pointer match {
+ case PointerDeclaratorPrefix0(pointerOp, None) => convert(pointerOp)
+ case x => ??(x)
+ }
+
+ // Do not support nestedNameSpecifier, attributeSpeciefierSeq, and cvQualifierSeq
+ def convert(implicit pointerOp: PointerOperatorWithDoubleStarContext): Seq[CPPPointer[G]] = pointerOp match {
+ case PointerOperatorWithDoubleStar0(pointerOp) => convert(pointerOp)
+ case PointerOperatorWithDoubleStar1(None, _, None, None) => Seq(CPPPointer(), CPPPointer())
+ case x => ??(x)
+ }
+
+ // Do not support '&' and '&&' and nestedNameSpecifier, attributeSpeciefierSeq, and cvQualifierSeq
+ def convert(implicit pointerOp: PointerOperatorContext): Seq[CPPPointer[G]] = pointerOp match {
+ case PointerOperator2(None, _, None, None) => Seq(CPPPointer())
+ case x => ??(x)
+ }
+
+ // Do not support attributeSpeciefierSeq
+ def convert(noPointerDeclarator: NoPointerDeclaratorContext)(implicit o: Origin): CPPDeclarator[G] = noPointerDeclarator match {
+ case NoPointerDeclarator0(declaratorId, None) => convert(declaratorId)
+ case NoPointerDeclarator1(innerDeclarator, paramsAndQuals) =>
+ val (params, varargs) = convert(paramsAndQuals)
+ CPPTypedFunctionDeclarator[G](params, varargs, convert(innerDeclarator))
+ case NoPointerDeclarator2(innerDeclarator, _, None, _, None) =>
+ convert(innerDeclarator) match {
+ case CPPArrayDeclarator(_, _) => ??(noPointerDeclarator) // Do not support > 1 dimensions
+ case inner => CPPArrayDeclarator(inner, None)(blame(noPointerDeclarator))
+ }
+ case NoPointerDeclarator2(innerDeclarator, _, Some(constExpr), _, None) =>
+ convert(innerDeclarator) match {
+ case CPPArrayDeclarator(_, _) => ??(noPointerDeclarator) // Do not support > 1 dimensions
+ case inner => CPPArrayDeclarator(inner, Some(convert(constExpr)))(blame(noPointerDeclarator))
+ }
+ case NoPointerDeclarator3(_, pointerDecl, _) => ??(pointerDecl)
+ case x => ??(x)
+ }
+
+ def convert(implicit constExpr: ConstantExpressionContext): Expr[G] = constExpr match {
+ case ConstantExpression0(condExpr) => convert(condExpr)
+ }
+
+ // Do not support cvQualifier, refqualifier, exceptionSpec and attributeSpec
+ def convert(implicit paramsAndQuals: ParametersAndQualifiersContext): (Seq[CPPParam[G]], Boolean) = paramsAndQuals match {
+ case ParametersAndQualifiers0(_, None, _, None, None, None, None) => (Seq(), false)
+ case ParametersAndQualifiers0(_, Some(paramDeclClause), _, None, None, None, None) => convert(paramDeclClause)
+ }
+
+ def convert(implicit paramDeclClause: ParameterDeclarationClauseContext): (Seq[CPPParam[G]], Boolean) = paramDeclClause match {
+ case ParameterDeclarationClause0(paramDeclList, None) => (convert(paramDeclList), false)
+ case ParameterDeclarationClause0(paramDeclList, Some(_)) => (convert(paramDeclList), true)
+ }
+
+ def convert(implicit paramDeclList: ParameterDeclarationListContext): Seq[CPPParam[G]] = paramDeclList match {
+ case value: ParameterDeclarationList0Context => value.parameterDeclaration.asScala.toSeq.map(convert(_))
+ }
+
+ // only support params in form of 'declSpecifiers declarator'
+ def convert(implicit paramDecl: ParameterDeclarationContext): CPPParam[G] = paramDecl match {
+ case ParameterDeclaration0(declSpecs, declarator) => new CPPParam[G](convert(declSpecs), convert(declarator))
+ case x => ??(x)
+ }
+
+ // Do not support if spread operator '...' is used
+ def convert(implicit declaratorId: DeclaratoridContext): CPPDeclarator[G] = declaratorId match {
+ case Declaratorid0(None, idExpr) => convert(idExpr)
+ case x => ??(x)
+ }
+
+ // Do not support operatorFunctionId, conversionFunctionId, literalOperatorId, templateId, and things starting with a tilde
+ def convert(implicit unqualifiedId: UnqualifiedIdContext): CPPName[G] = unqualifiedId match {
+ case UnqualifiedId0(clangppId) => CPPName(convert(clangppId))
+ case x => ??(x)
+ }
+
+ // Do not support template or nestedNameSpecifier
+ def convert(implicit qualifiedId: QualifiedIdContext): CPPName[G] = qualifiedId match {
+ case QualifiedId0(nestedNameSpec, _, _) => ??(nestedNameSpec)
+ }
+
+ def convert(implicit id: ClangppIdentifierContext): String = id match {
+ case ClangppIdentifier0(text) => text
+ case ClangppIdentifier1(inner) => convert(inner)
+ }
+
+ def convert(expr: LangExprContext): Expr[G] = expr match {
+ case LangExpr0(expr) => convert(expr)
+ }
+
+ def convert(stat: LangStatementContext): Statement[G] = stat match {
+ case LangStatement0(stat) => convert(stat)
+ }
+
+ def convert(implicit t: LangTypeContext): Type[G] = t match {
+ case LangType0(typeSpec) => CPPPrimitiveType(convert(typeSpec))
+ }
+
+ def convert(id: LangIdContext): String = id match {
+ case LangId0(id) => convert(id)
+ }
+
+ def convert(implicit n: LangConstIntContext): BigInt = n match {
+ case LangConstInt0(Literal0(string)) => BigInt(string)
+ case LangConstInt0(Literal1(string)) => BigInt(string)
+ case LangConstInt0(Literal2(string)) => BigInt(string)
+ case x => ??(x)
+ }
+
+ def local(ctx: ParserRuleContext, name: String): Expr[G] =
+ CPPLocal(name)(blame(ctx))(origin(ctx))
+
+ def convert(decl: LangGlobalDeclContext): Seq[GlobalDeclaration[G]] = decl match {
+ case LangGlobalDecl0(decl) => convert(decl)
+ }
+
+ def convert(decl: LangClassDeclContext): Seq[ClassDeclaration[G]] = Nil
+
+ def withCollector[T](collector: ContractCollector[G], f: ContractCollector[G] => T): T = {
+ val result = f(collector)
+ collector.nodes.headOption match {
+ case Some(node) => fail(node, "This specification clause may not occur here")
+ case None => result
+ }
+ }
+
+ def withContract[T](node: Option[ValEmbedContractContext], f: ContractCollector[G] => T): T = {
+ val collector = new ContractCollector[G]()
+ node.foreach(convert(_, collector))
+ withCollector(collector, f)
+ }
+
+ def withContract[T](node1: Option[ValEmbedContractContext], node2: Option[ValEmbedContractContext], f: ContractCollector[G] => T): T = {
+ val collector = new ContractCollector[G]()
+ node1.foreach(convert(_, collector))
+ node2.foreach(convert(_, collector))
+ withCollector(collector, f)
+ }
+
+ def withContract[T](node: Seq[ValContractClauseContext], f: ContractCollector[G] => T): T = {
+ val collector = new ContractCollector[G]()
+ node.foreach(convert(_, collector))
+ withCollector(collector, f)
+ }
+
+ def withCollector[T](collector: ModifierCollector, f: ModifierCollector => T): T = {
+ val result = f(collector)
+ collector.nodes.headOption match {
+ case Some(node) => fail(node, "This modifier cannot be attached to this declaration")
+ case None => result
+ }
+ }
+
+ def withModifiers[T](node: Seq[ValModifierContext], f: ModifierCollector => T): T = {
+ val collector = new ModifierCollector()
+ node.foreach(convert(_, collector))
+ withCollector(collector, f)
+ }
+
+ def withModifiers[T](node: ValEmbedModifierContext, f: ModifierCollector => T): T = {
+ val collector = new ModifierCollector()
+ convert(node, collector)
+ withCollector(collector, f)
+ }
+
+ def convert(contract: ValEmbedContractContext, collector: ContractCollector[G]): Unit = contract match {
+ case ValEmbedContract0(blocks) => blocks.foreach(convert(_, collector))
+ }
+
+ def convert(contract: ValEmbedContractBlockContext, collector: ContractCollector[G]): Unit = contract match {
+ case ValEmbedContractBlock0(_, clauses, _) => clauses.foreach(convert(_, collector))
+ case ValEmbedContractBlock1(clauses) => clauses.foreach(convert(_, collector))
+ }
+
+ def convert(implicit contract: ValContractClauseContext, collector: ContractCollector[G]): Unit = contract match {
+ case ValContractClause0(_, ids, _) => collector.modifies ++= convert(ids).map((contract, _))
+ case ValContractClause1(_, ids, _) => collector.accessible ++= convert(ids).map((contract, _))
+ case ValContractClause2(_, exp, _) => collector.requires += ((contract, convert(exp)))
+ case ValContractClause3(_, exp, _) => collector.ensures += ((contract, convert(exp)))
+ case ValContractClause4(_, t, id, _) =>
+ val variable = new Variable(convert(t))(SourceNameOrigin(convert(id), origin(contract)))
+ collector.given += ((contract, variable))
+ case ValContractClause5(_, t, id, _) =>
+ val variable = new Variable(convert(t))(SourceNameOrigin(convert(id), origin(contract)))
+ collector.yields += ((contract, variable))
+ case ValContractClause6(_, exp, _) => collector.context_everywhere += ((contract, convert(exp)))
+ case ValContractClause7(_, exp, _) =>
+ collector.requires += ((contract, convert(exp)))
+ collector.ensures += ((contract, convert(exp)))
+ case ValContractClause8(_, exp, _) => collector.loop_invariant += ((contract, convert(exp)))
+ case ValContractClause9(_, exp, _) => collector.kernel_invariant += ((contract, convert(exp)))
+ case ValContractClause10(_, _, t, id, _, exp, _) =>
+ val variable = new Variable(convert(t))(SourceNameOrigin(convert(id), origin(contract)))
+ collector.signals += ((contract, SignalsClause(variable, convert(exp))(originProvider(contract))))
+ case ValContractClause11(_, invariant, _) => collector.lock_invariant += ((contract, convert(invariant)))
+ case ValContractClause12(_, None, _) => collector.decreases += ((contract, DecreasesClauseNoRecursion()))
+ case ValContractClause12(_, Some(clause), _) => collector.decreases += ((contract, convert(clause)))
+ }
+
+ def convert(implicit clause: ValDecreasesMeasureContext): DecreasesClause[G] = clause match {
+ case ValDecreasesMeasure0(_) => DecreasesClauseAssume()
+ case ValDecreasesMeasure1(exps) => DecreasesClauseTuple(convert(exps))
+ }
+
+ def convert(mod: ValEmbedModifierContext, collector: ModifierCollector): Unit = mod match {
+ case ValEmbedModifier0(_, mod, _) => convert(mod, collector)
+ case ValEmbedModifier1(mod) => convert(mod, collector)
+ }
+
+ def convert(mod: ValModifierContext, collector: ModifierCollector): Unit = mod match {
+ case ValModifier0(name) => name match {
+ case "pure" => collector.pure += mod
+ case "inline" => collector.inline += mod
+ case "thread_local" => collector.threadLocal += mod
+ }
+ case ValStatic(_) => collector.static += mod
+ }
+
+ def convertEmbedWith(implicit whiff: Option[ValEmbedWithContext], inner: Expr[G]): Expr[G] = whiff match {
+ case None => inner
+ case Some(ValEmbedWith0(_, whiff, _)) => convertWith(whiff, inner)
+ case Some(ValEmbedWith1(whiff)) => convertWith(Some(whiff), inner)
+ }
+
+ def convertWith(implicit whiff: Option[ValWithContext], inner: Expr[G]): Expr[G] = whiff match {
+ case None => inner
+ case Some(whiff@ValWith0(_, stat)) => With(convert(stat), inner)(origin(whiff))
+ }
+
+ def convertEmbedThen(implicit den: Option[ValEmbedThenContext], inner: Expr[G]): Expr[G] = den match {
+ case None => inner
+ case Some(ValEmbedThen0(_, den, _)) => convertThen(den, inner)
+ case Some(ValEmbedThen1(den)) => convertThen(Some(den), inner)
+ }
+
+ def convertThen(implicit den: Option[ValThenContext], inner: Expr[G]): Expr[G] = den match {
+ case None => inner
+ case Some(den@ValThen0(_, stat)) => Then(inner, convert(stat))(origin(den))
+ }
+
+ def convert(implicit whiff: ValEmbedWithContext): Statement[G] = whiff match {
+ case ValEmbedWith0(_, Some(whiff), _) => convert(whiff)
+ case ValEmbedWith0(_, None, _) => Block(Nil)
+ case ValEmbedWith1(whiff) => convert(whiff)
+ }
+
+ def convert(implicit whiff: ValWithContext): Statement[G] = whiff match {
+ case ValWith0(_, stat) => convert(stat)
+ }
+
+ def convert(implicit whiff: ValEmbedThenContext): Statement[G] = whiff match {
+ case ValEmbedThen0(_, Some(whiff), _) => convert(whiff)
+ case ValEmbedThen0(_, None, _) => Block(Nil)
+ case ValEmbedThen1(whiff) => convert(whiff)
+ }
+
+ def convert(implicit whiff: ValThenContext): Statement[G] = whiff match {
+ case ValThen0(_, stat) => convert(stat)
+ }
+
+ def convertEmbedGiven(implicit given: Option[ValEmbedGivenContext]): Seq[(Ref[G, Variable[G]], Expr[G])] = given match {
+ case None => Nil
+ case Some(ValEmbedGiven0(_, inner, _)) => convertGiven(inner)
+ case Some(ValEmbedGiven1(inner)) => convertGiven(Some(inner))
+ }
+
+ def convertGiven(implicit given: Option[ValGivenContext]): Seq[(Ref[G, Variable[G]], Expr[G])] = given match {
+ case None => Nil
+ case Some(ValGiven0(_, _, mappings, _)) => convert(mappings)
+ }
+
+ def convert(implicit mappings: ValGivenMappingsContext): Seq[(Ref[G, Variable[G]], Expr[G])] = mappings match {
+ case ValGivenMappings0(arg, _, v) => Seq((new UnresolvedRef[G, Variable[G]](convert(arg)), convert(v)))
+ case ValGivenMappings1(arg, _, v, _, more) => (new UnresolvedRef[G, Variable[G]](convert(arg)), convert(v)) +: convert(more)
+ }
+
+ def convertEmbedYields(implicit given: Option[ValEmbedYieldsContext]): Seq[(Expr[G], Ref[G, Variable[G]])] = given match {
+ case None => Nil
+ case Some(ValEmbedYields0(_, inner, _)) => convertYields(inner)
+ case Some(ValEmbedYields1(inner)) => convertYields(Some(inner))
+ }
+
+ def convertYields(implicit given: Option[ValYieldsContext]): Seq[(Expr[G], Ref[G, Variable[G]])] = given match {
+ case None => Nil
+ case Some(ValYields0(_, _, mappings, _)) => convert(mappings)
+ }
+
+ def convert(implicit mappings: ValYieldsMappingsContext): Seq[(Expr[G], Ref[G, Variable[G]])] = mappings match {
+ case ValYieldsMappings0(target, _, res) => Seq((local(target, convert(target)), new UnresolvedRef[G, Variable[G]](convert(res))))
+ case ValYieldsMappings1(target, _, res, _, more) => (local(target, convert(target)), new UnresolvedRef[G, Variable[G]](convert(res))) +: convert(more)
+ }
+
+ def convert(implicit exprs: ValExpressionListContext): Seq[Expr[G]] = exprs match {
+ case ValExpressionList0(expr) => Seq(convert(expr))
+ case ValExpressionList1(head, _, tail) => convert(head) +: convert(tail)
+ }
+
+ def convert(implicit ids: ValIdListContext): Seq[String] = ids match {
+ case ValIdList0(id) => Seq(convert(id))
+ case ValIdList1(id, _, ids) => convert(id) +: convert(ids)
+ }
+
+ def convert(implicit ts: ValTypeListContext): Seq[Type[G]] = ts match {
+ case ValTypeList0(t) => Seq(convert(t))
+ case ValTypeList1(t, _, ts) => convert(t) +: convert(ts)
+ }
+
+ def convert(implicit root: ParserRuleContext, impOp: ValImpOpContext, left: Expr[G], right: Expr[G]): Expr[G] = impOp match {
+ case ValImpOp0(_) => Wand(left, right)(origin(impOp))
+ case ValImpOp1(_) => Implies(left, right)(origin(impOp))
+ }
+
+ def convert(implicit root: ParserRuleContext, andOp: ValAndOpContext, left: Expr[G], right: Expr[G]): Expr[G] = andOp match {
+ case ValAndOp0(_) => col.Star(left, right)(origin(andOp))
+ }
+
+ def convert(implicit root: ParserRuleContext, inOp: ValInOpContext, left: Expr[G], right: Expr[G]): Expr[G] = inOp match {
+ case ValInOp0(_) => AmbiguousMember(left, right)
+ }
+
+ def convert(implicit root: ParserRuleContext, mulOp: ValMulOpContext, left: Expr[G], right: Expr[G]): Expr[G] = mulOp match {
+ case ValMulOp0(_) => col.Div(left, right)(blame(mulOp))
+ }
+
+ def convert(implicit root: ParserRuleContext, prependOp: ValPrependOpContext, left: Expr[G], right: Expr[G]): Expr[G] = prependOp match {
+ case ValPrependOp0(_) => Cons(left, right)
+ }
+
+ def convert(implicit root: ParserRuleContext, postfixOp: ValPostfixContext, xs: Expr[G]): Expr[G] = postfixOp match {
+ case ValPostfix0(_, _, to, _) => Take(xs, convert(to))
+ case ValPostfix1(_, from, _, None, _) => Drop(xs, convert(from))
+ case ValPostfix1(_, from, _, Some(to), _) => Slice(xs, convert(from), convert(to))
+ case ValPostfix2(_, idx, _, v, _) => SeqUpdate(xs, convert(idx), convert(v))
+ case ValPostfix3(_, name, _, args, _) => CoalesceInstancePredicateApply(xs, new UnresolvedRef[G, InstancePredicate[G]](convert(name)), args.map(convert(_)).getOrElse(Nil), WritePerm())
+ }
+
+ def convert(implicit root: ParserRuleContext, prefixOp: ValPrefixContext, xs: Expr[G]): Expr[G] = prefixOp match {
+ case ValScale(_, scale, _) => Scale(convert(scale), xs)(blame(prefixOp))
+ }
+
+ def convert(implicit block: ValEmbedStatementBlockContext): Statement[G] = block match {
+ case ValEmbedStatementBlock0(_, stats, _) => Block(stats.map(convert(_)))
+ case ValEmbedStatementBlock1(stats) => Block(stats.map(convert(_)))
+ case ValEmbedStatementBlock2(_, _, _, stat) => Extract(convert(stat))
+ case ValEmbedStatementBlock3(_, _, clauses, _, _, body, _, _, _) =>
+ withContract(clauses, contract => {
+ FramedProof(
+ AstBuildHelpers.foldStar(contract.consume(contract.requires)),
+ Block(body.map(convert(_))),
+ AstBuildHelpers.foldStar(contract.consume(contract.ensures)),
+ )(blame(block))
+ })
+ }
+
+ def convert(implicit stat: ValStatementContext): Statement[G] = stat match {
+ case ValPackage(_, expr, innerStat) => WandPackage(convert(expr), convert(innerStat))(blame(stat))
+ case ValApplyWand(_, wand, _) => WandApply(convert(wand))(blame(stat))
+ case ValFold(_, predicate, _) =>
+ Fold(convert(predicate))(blame(stat))
+ case ValUnfold(_, predicate, _) =>
+ Unfold(convert(predicate))(blame(stat))
+ case ValOpen(_, _, _) => ??(stat)
+ case ValClose(_, _, _) => ??(stat)
+ case ValAssert(_, assn, _) => Assert(convert(assn))(blame(stat))
+ case ValAssume(_, assn, _) => Assume(convert(assn))
+ case ValInhale(_, resource, _) => Inhale(convert(resource))
+ case ValExhale(_, resource, _) => Exhale(convert(resource))(blame(stat))
+ case ValLabel(_, label, _) =>
+ Label(new LabelDecl()(SourceNameOrigin(convert(label), origin(stat))), Block(Nil))
+ case ValRefute(_, assn, _) => Refute(convert(assn))(blame(stat))
+ case ValWitness(_, _, _) => ??(stat)
+ case ValGhost(_, stat) => convert(stat)
+ case ValSend(_, name, _, delta, _, resource, _) =>
+ Send(new SendDecl()(SourceNameOrigin(convert(name), origin(stat))), convert(delta), convert(resource))(blame(stat))
+ case ValRecv(_, name, _) =>
+ Recv(new UnresolvedRef[G, SendDecl[G]](convert(name)))
+ case ValTransfer(_, _, _) => ??(stat)
+ case ValCslSubject(_, _, _) => ??(stat) // FIXME PB: csl_subject seems to be used
+ case ValSpecIgnoreStart(_, _) => SpecIgnoreEnd()
+ case ValSpecIgnoreEnd(_, _) => SpecIgnoreStart()
+ case ValActionModel(_, _, model, _, perm, _, after, _, action, _, impl) =>
+ ModelDo(convert(model), convert(perm), convert(after), convert(action), impl match {
+ case ValActionImpl0(_) => Block(Nil)
+ case ValActionImpl1(inner) => convert(inner)
+ })
+ case ValAtomic(_, _, invariant, _, body) =>
+ ParAtomic(Seq(new UnresolvedRef[G, ParInvariantDecl[G]](convert(invariant))), convert(body))(blame(stat))
+ case ValCommit(_, obj, _) =>
+ Commit(convert(obj))(blame(stat))
+ case ValExtract(_, body) =>
+ Extract(convert(body))
+ case ValFrame(_, clauses, body) =>
+ withContract(clauses, contract => {
+ FramedProof(
+ AstBuildHelpers.foldStar(contract.consume(contract.requires)),
+ convert(body),
+ AstBuildHelpers.foldStar(contract.consume(contract.ensures)),
+ )(blame(stat))
+ })
+ }
+
+ def convert(implicit block: ValBlockContext): Seq[Statement[G]] = block match {
+ case ValBlock0(_, stats, _) => stats.map(convert(_))
+ }
+
+ def convert(implicit arg: ValArgContext): Variable[G] = arg match {
+ case ValArg0(t, id) => new Variable(convert(t))(SourceNameOrigin(convert(id), origin(arg)))
+ }
+
+ def convert(implicit args: ValArgListContext): Seq[Variable[G]] = args match {
+ case ValArgList0(arg) => Seq(convert(arg))
+ case ValArgList1(arg, _, args) => convert(arg) +: convert(args)
+ }
+
+ def convert(implicit decl: ValEmbedGlobalDeclarationBlockContext): Seq[GlobalDeclaration[G]] = decl match {
+ case ValEmbedGlobalDeclarationBlock0(_, globals, _) => globals.flatMap(convert(_))
+ case ValEmbedGlobalDeclarationBlock1(globals) => globals.flatMap(convert(_))
+ }
+
+ def convert(implicit decl: ValGlobalDeclarationContext): Seq[GlobalDeclaration[G]] = decl match {
+ case ValAxiom(_, name, _, axiom, _) =>
+ Seq(new SimplificationRule(convert(axiom))(SourceNameOrigin(convert(name), origin(decl))))
+ case ValPredicate(modifiers, _, name, _, args, _, definition) =>
+ withModifiers(modifiers, mods =>
+ Seq(new Predicate(args.map(convert(_)).getOrElse(Nil), convert(definition),
+ mods.consume(mods.threadLocal), mods.consume(mods.inline))
+ (SourceNameOrigin(convert(name), origin(decl)))))
+ case ValFunction(contract, modifiers, _, t, name, typeArgs, _, args, _, definition) =>
+ Seq(withContract(contract, c =>
+ withModifiers(modifiers, m => {
+ val namedOrigin = SourceNameOrigin(convert(name), origin(decl))
+ new Function(
+ convert(t),
+ args.map(convert(_)).getOrElse(Nil),
+ typeArgs.map(convert(_)).getOrElse(Nil),
+ convert(definition),
+ c.consumeApplicableContract(blame(decl)),
+ m.consume(m.inline))(blame(decl))(namedOrigin)
+ })
+ ))
+ case ValModel(_, name, _, decls, _) =>
+ Seq(new Model(decls.flatMap(convert(_)))(SourceNameOrigin(convert(name), origin(decl))))
+ case ValGhostDecl(_, inner) =>
+ convert(inner)
+ case ValAdtDecl(_, name, typeArgs, _, decls, _) =>
+ Seq(new AxiomaticDataType(decls.map(convert(_)), typeArgs.map(convert(_)).getOrElse(Nil))(
+ SourceNameOrigin(convert(name), origin(decl))))
+ }
+
+ def convert(implicit decl: ValEmbedClassDeclarationBlockContext): Seq[ClassDeclaration[G]] = decl match {
+ case ValEmbedClassDeclarationBlock0(_, decls, _) => decls.flatMap(convert(_, x => x))
+ case ValEmbedClassDeclarationBlock1(decls) => decls.flatMap(convert(_, x => x))
+ }
+
+ def convert[T](implicit decl: ValClassDeclarationContext, transform: ClassDeclaration[G] => T): Seq[T] = decl match {
+ case ValInstancePredicate(modifiers, _, name, _, args, _, definition) =>
+ Seq(withModifiers(modifiers, mods => {
+ transform(new InstancePredicate(args.map(convert(_)).getOrElse(Nil), convert(definition),
+ mods.consume(mods.threadLocal), mods.consume(mods.inline))(
+ SourceNameOrigin(convert(name), origin(decl))))
+ }))
+ case ValInstanceFunction(contract, modifiers, _, t, name, typeArgs, _, args, _, definition) =>
+ Seq(withContract(contract, c => {
+ withModifiers(modifiers, m => {
+ transform(new InstanceFunction(
+ convert(t),
+ args.map(convert(_)).getOrElse(Nil),
+ typeArgs.map(convert(_)).getOrElse(Nil),
+ convert(definition),
+ c.consumeApplicableContract(blame(decl)), m.consume(m.inline))(
+ blame(decl))(
+ SourceNameOrigin(convert(name), origin(decl))))
+ })
+ }))
+ case ValInstanceGhostDecl(_, decl) => convert(decl).map(transform)
+ }
+
+ def convert(implicit decl: ValModelDeclarationContext): Seq[ModelDeclaration[G]] = decl match {
+ case ValModelField(t, name, _) =>
+ convert(name).map(name => {
+ new ModelField(convert(t))(SourceNameOrigin(name, origin(decl)))
+ })
+ case ValModelProcess(contract, _, name, _, args, _, _, definition, _) =>
+ Seq(withContract(contract, c => {
+ new ModelProcess(args.map(convert(_)).getOrElse(Nil), convert(definition),
+ AstBuildHelpers.foldAnd(c.consume(c.requires)), AstBuildHelpers.foldAnd(c.consume(c.ensures)),
+ c.consume(c.modifies).map(new UnresolvedRef[G, ModelField[G]](_)), c.consume(c.accessible).map(new UnresolvedRef[G, ModelField[G]](_)))(
+ blame(decl))(SourceNameOrigin(convert(name), origin(decl)))
+ }))
+ case ValModelAction(contract, _, name, _, args, _, _) =>
+ Seq(withContract(contract, c => {
+ new ModelAction(args.map(convert(_)).getOrElse(Nil),
+ AstBuildHelpers.foldAnd(c.consume(c.requires)), AstBuildHelpers.foldAnd(c.consume(c.ensures)),
+ c.consume(c.modifies).map(new UnresolvedRef[G, ModelField[G]](_)), c.consume(c.accessible).map(new UnresolvedRef[G, ModelField[G]](_)))(
+ SourceNameOrigin(convert(name), origin(decl)))
+ }))
+ }
+
+ def convert(implicit ts: ValTypeVarsContext): Seq[Variable[G]] = ts match {
+ case ValTypeVars0(_, names, _) =>
+ convert(names).map(name => new Variable(TType(TAny()))(SourceNameOrigin(name, origin(ts))))
+ }
+
+ def convert(implicit decl: ValAdtDeclarationContext): ADTDeclaration[G] = decl match {
+ case ValAdtAxiom(_, ax, _) => new ADTAxiom(convert(ax))
+ case ValAdtFunction(_, returnType, name, _, args, _, _) =>
+ new ADTFunction(args.map(convert(_)).getOrElse(Nil), convert(returnType))(
+ SourceNameOrigin(convert(name), origin(decl)))
+ }
+
+ def convert(implicit definition: ValPureDefContext): Option[Expr[G]] = definition match {
+ case ValPureAbstractBody(_) => None
+ case ValPureBody(_, expr, _) => Some(convert(expr))
+ }
+
+ def convert(implicit definition: ValImpureDefContext): Option[Statement[G]] = definition match {
+ case ValImpureAbstractBody(_) => None
+ case ValImpureBody(statement) => Some(convert(statement))
+ }
+
+ def convert(implicit t: ValTypeContext): Type[G] = t match {
+ case ValPrimaryType(name) => name match {
+ case "resource" => TResource()
+ case "process" => TProcess()
+ case "frac" => TFraction()
+ case "zfrac" => TZFraction()
+ case "rational" => TRational()
+ case "bool" => TBool()
+ case "ref" => TRef()
+ case "any" => TAny()
+ case "nothing" => TNothing()
+ }
+ case ValSeqType(_, _, element, _) => TSeq(convert(element))
+ case ValSetType(_, _, element, _) => TSet(convert(element))
+ case ValBagType(_, _, element, _) => TBag(convert(element))
+ case ValOptionType(_, _, element, _) => TOption(convert(element))
+ case ValMapType(_, _, key, _, value, _) => TMap(convert(key), convert(value))
+ case ValTupleType(_, _, t1, _, t2, _) => TTuple(Seq(convert(t1), convert(t2)))
+ case ValPointerType(_, _, element, _) => TPointer(convert(element))
+ case ValTypeType(_, _, element, _) => TType(convert(element))
+ case ValEitherType(_, _, left, _, right, _) => TEither(convert(left), convert(right))
+ }
+
+ def convert(implicit e: ValPrimarySeqContext): Expr[G] = e match {
+ case ValCardinality(_, xs, _) => Size(convert(xs))
+ case ValArrayValues(_, _, a, _, from, _, to, _) => Values(convert(a), convert(from), convert(to))(blame(e))
+ }
+
+ def convert(implicit e: ValPrimaryOptionContext): Expr[G] = e match {
+ case ValSome(_, _, v, _) => OptSome(convert(v))
+ }
+
+ def convert(implicit e: ValPrimaryEitherContext): Expr[G] = e match {
+ case ValLeft(_, _, inner, _) => EitherLeft(convert(inner))
+ case ValRight(_, _, inner, _) => EitherRight(convert(inner))
+ }
+
+ // valsetcompselectors
+ def convert(implicit exprs: ValMapPairsContext): Seq[(Expr[G], Expr[G])] = exprs match {
+ case ValMapPairs0(k, _, v) => Seq((convert(k), convert(v)))
+ case ValMapPairs1(k, _, v, _, tail) => (convert(k), convert(v)) +: convert(tail)
+ }
+
+ def convert(implicit e: ValPrimaryCollectionConstructorContext): Expr[G] = e match {
+ case ValTypedLiteralSeq(_, _, t, _, _, exprs, _) => LiteralSeq(convert(t), exprs.map(convert(_)).getOrElse(Nil))
+ case ValTypedLiteralSet(_, _, t, _, _, exprs, _) => LiteralSet(convert(t), exprs.map(convert(_)).getOrElse(Nil))
+ case ValSetComprehension(_, _, t, _, _, value, _, selectors, _, something, _) => ??(e)
+ case ValTypedLiteralBag(_, _, t, _, _, exprs, _) => LiteralBag(convert(t), exprs.map(convert(_)).getOrElse(Nil))
+ case ValTypedLiteralMap(_, _, key, _, value, _, _, pairs, _) => LiteralMap(convert(key), convert(value), pairs.map(convert(_)).getOrElse(Nil))
+ case ValTypedTuple(_, _, t1, _, t2, _, _, v1, _, v2, _) =>
+ LiteralTuple(Seq(convert(t1), convert(t2)), Seq(convert(v1), convert(v2)))
+ case ValLiteralSeq(_, exprs, _) => UntypedLiteralSeq(convert(exprs))
+ case ValLiteralSet(_, exprs, _) => UntypedLiteralSet(convert(exprs))
+ case ValLiteralBag(_, exprs, _) => UntypedLiteralBag(convert(exprs))
+ case ValEmptySeq(_, t, _) => LiteralSeq(convert(t), Nil)
+ case ValEmptySet(_, t, _) => LiteralSet(convert(t), Nil)
+ case ValEmptyBag(_, t, _) => LiteralBag(convert(t), Nil)
+ case ValRange(_, from, _, to, _) => Range(convert(from), convert(to))
+ }
+
+ def convert(implicit e: ValPrimaryPermissionContext): Expr[G] = e match {
+ case ValCurPerm(_, _, loc, _) => CurPerm(AmbiguousLocation(convert(loc))(blame(e)))
+ case ValPerm(_, _, loc, _, perm, _) => Perm(AmbiguousLocation(convert(loc))(blame(e)), convert(perm))
+ case ValValue(_, _, loc, _) => Value(AmbiguousLocation(convert(loc))(blame(e)))
+ case ValPointsTo(_, _, loc, _, perm, _, v, _) => PointsTo(AmbiguousLocation(convert(loc))(blame(e)), convert(perm), convert(v))
+ case ValHPerm(_, _, loc, _, perm, _) => ModelPerm(convert(loc), convert(perm))
+ case ValAPerm(_, _, loc, _, perm, _) => ActionPerm(convert(loc), convert(perm))
+ case ValArrayPerm(_, _, arr, _, i, _, step, _, count, _, perm, _) => ??(e)
+ case ValMatrix(_, _, m, _, dim1, _, dim2, _) => ValidMatrix(convert(m), convert(dim1), convert(dim2))
+ case ValArray(_, _, arr, _, dim, _) => ValidArray(convert(arr), convert(dim))
+ case ValPointer(_, _, ptr, _, n, _, perm, _) => PermPointer(convert(ptr), convert(n), convert(perm))
+ case ValPointerIndex(_, _, ptr, _, idx, _, perm, _) => PermPointerIndex(convert(ptr), convert(idx), convert(perm))
+ case ValPointerBlockLength(_, _, ptr, _) => PointerBlockLength(convert(ptr))(blame(e))
+ case ValPointerBlockOffset(_, _, ptr, _) => PointerBlockOffset(convert(ptr))(blame(e))
+ case ValPointerLength(_, _, ptr, _) => PointerLength(convert(ptr))(blame(e))
+ case ValPolarityDependent(_, _, onInhale, _, onExhale, _) => PolarityDependent(convert(onInhale), convert(onExhale))
+ }
+
+ def convert(implicit v: ValBindingContext): (Variable[G], Seq[Expr[G]]) = v match {
+ case ValRangeBinding(t, id, _, from, _, to) =>
+ val variable = new Variable[G](convert(t))(SourceNameOrigin(convert(id), origin(id)))
+ val cond = SeqMember[G](Local(variable.ref), Range(convert(from), convert(to)))
+ (variable, Seq(cond))
+ case ValNormalBinding(arg) =>
+ (convert(arg), Nil)
+ }
+
+ def convert(implicit vs: ValBindingsContext): (Seq[Variable[G]], Seq[Expr[G]]) = vs match {
+ case ValBindings0(binding) =>
+ val (v, cs) = convert(binding)
+ (Seq(v), cs)
+ case ValBindings1(binding, _, bindings) =>
+ val (v, cs) = convert(binding)
+ val (vs, ds) = convert(bindings)
+ (v +: vs, cs ++ ds)
+ }
+
+ def convert(implicit e: ValPrimaryBinderContext): Expr[G] = e match {
+ case ValQuantifier(_, symbol, bindings, _, bodyOrCond, maybeBody, _) =>
+ val (variables, bindingConds) = convert(bindings)
+ val (bodyConds, body) = maybeBody match {
+ case Some(ValBinderCont0(_, body)) => (Seq(convert(bodyOrCond)), convert(body))
+ case None => (Nil, convert(bodyOrCond))
+ }
+ val conds = bindingConds ++ bodyConds
+ symbol match {
+ case ValForallSymb(_) => Forall(variables, Nil, implies(conds, body))
+ case ValStarallSymb(_) => Starall(variables, Nil, implies(conds, body))(blame(e))
+ case ValExistsSymb(_) => Exists(variables, Nil, foldAnd(conds :+ body))
+ }
+ case ValLet(_, _, t, id, _, v, _, body, _) =>
+ Let(new Variable(convert(t))(SourceNameOrigin(convert(id), origin(id))), convert(v), convert(body))
+ case ValForPerm(_, _, bindings, _, loc, _, body, _) =>
+ ForPerm(convert(bindings), AmbiguousLocation(convert(loc))(blame(loc))(origin(loc)), convert(body))
+ }
+
+ def convert(implicit e: ValPrimaryVectorContext): Expr[G] = e match {
+ case ValSum(_, _, t, id, _, cond, _, body, _) =>
+ val binding = new Variable(convert(t))(SourceNameOrigin(convert(id), origin(id)))
+ Sum(Seq(binding), convert(cond), convert(body))
+ case ValVectorSum(_, _, rng, _, vec, _) => VectorSum(convert(rng), convert(vec))
+ case ValVectorCmp(_, _, left, _, right, _) => VectorCompare(convert(left), convert(right))
+ case ValVectorRep(_, _, inner, _) => VectorRepeat(convert(inner))
+ case ValMatrixSum(_, _, rng, _, mat, _) => MatrixSum(convert(rng), convert(mat))
+ case ValMatrixCmp(_, _, left, _, right, _) => MatrixCompare(convert(left), convert(right))
+ case ValMatrixRep(_, _, inner, _) => MatrixRepeat(convert(inner))
+ }
+
+ def convert(implicit e: ValPrimaryReducibleContext): Expr[G] = ??(e)
+
+ def convert(implicit e: ValPrimaryThreadContext): Expr[G] = e match {
+ case ValIdle(_, _, thread, _) => IdleToken(convert(thread))
+ case ValRunning(_, _, thread, _) => JoinToken(convert(thread))
+ }
+
+ def convert(implicit e: ValPrimaryContextContext): Expr[G] = e match {
+ case ValPrimaryContext0("\\result") => AmbiguousResult()
+ case ValPrimaryContext1("\\current_thread") => CurrentThreadId()
+ case ValPrimaryContext2("\\ltid") => LocalThreadId()
+ case ValPrimaryContext3("\\gtid") => GlobalThreadId()
+ }
+
+ def convert(implicit e: ValPrimaryContext): Expr[G] = e match {
+ case ValPrimary0(inner) => convert(inner)
+ case ValPrimary1(inner) => convert(inner)
+ case ValPrimary2(inner) => convert(inner)
+ case ValPrimary3(inner) => convert(inner)
+ case ValPrimary4(inner) => convert(inner)
+ case ValPrimary5(inner) => convert(inner)
+ case ValPrimary6(inner) => convert(inner)
+ case ValPrimary7(inner) => convert(inner)
+ case ValPrimary8(inner) => convert(inner)
+ case ValPrimary9(inner) => convert(inner)
+ case ValAny(_) => Any()(blame(e))
+ case ValFunctionOf(_, inner, _, names, _) => FunctionOf(new UnresolvedRef[G, Variable[G]](convert(inner)), convert(names).map(new UnresolvedRef[G, Variable[G]](_)))
+ case ValInlinePattern(open, pattern, _) =>
+ val groupText = open.filter(_.isDigit)
+ InlinePattern(convert(pattern), open.count(_ == '<'), if (groupText.isEmpty) 0 else groupText.toInt)
+ case ValUnfolding(_, predExpr, _, body) => Unfolding(convert(predExpr), convert(body))(blame(e))
+ case ValOld(_, _, expr, _) => Old(convert(expr), at = None)(blame(e))
+ case ValOldLabeled(_, _, label, _, _, expr, _) => Old(convert(expr), at = Some(new UnresolvedRef[G, LabelDecl[G]](convert(label))))(blame(e))
+ case ValTypeof(_, _, expr, _) => TypeOf(convert(expr))
+ case ValTypeValue(_, _, t, _) => TypeValue(convert(t))
+ case ValHeld(_, _, obj, _) => Held(convert(obj))
+ case ValCommitted(_, _, obj, _) => Committed(convert(obj))(blame(e))
+ case ValIdEscape(text) => local(e, text.substring(1, text.length - 1))
+ case ValSharedMemSize(_, _, ptr, _) => SharedMemSize(convert(ptr))
+ case ValNdIndex(_, _, firstIndex, _, firstDim, parsePairs, _) =>
+ val pairs = parsePairs.map(convert(_))
+ val indices = convert(firstIndex) +: pairs.map(_._1)
+ val dims = convert(firstDim) +: pairs.map(_._2)
+ NdIndex(indices, dims)
+ case ValNdLIndex(_, _, indices, _, dims, _) =>
+ val allIndices = convert(indices)
+ NdPartialIndex(allIndices.init, allIndices.last, convert(dims))
+ case ValNdLength(_, _, dims, _) => NdLength(convert(dims))
+ }
+
+ def convert(implicit e: ValExprPairContext): (Expr[G], Expr[G]) = e match {
+ case ValExprPair0(_, e1, _, e2) => (convert(e1), convert(e2))
+ }
+
+ def convert(implicit e: ValExprContext): Expr[G] = e match {
+ case ValExpr0(inner) => convert(inner)
+ case ValExpr1(inner) => convert(inner)
+ }
+
+ def convert(implicit id: ValIdentifierContext): String = id match {
+ case ValIdentifier0(inner) => convertText(inner)
+ case ValIdentifier1(ValKeywordNonExpr0(text)) => text
+ case ValIdentifier2(text) => text.substring(1, text.length - 1)
+ }
+
+ def convertText(implicit res: ValKeywordExprContext): String = res match {
+ case ValNonePerm(_) => "none"
+ case ValWrite(_) => "write"
+ case ValRead(_) => "read"
+ case ValNoneOption(_) => "None"
+ case ValEmpty(_) => "empty"
+ case ValTrue(_) => "true"
+ case ValFalse(_) => "false"
+ }
+
+ def convert(implicit res: ValKeywordExprContext): Expr[G] = res match {
+ case ValNonePerm(_) => NoPerm()
+ case ValWrite(_) => WritePerm()
+ case ValRead(_) => ReadPerm()
+ case ValNoneOption(_) => OptNone()
+ case ValEmpty(_) => EmptyProcess()
+ case ValTrue(_) => tt
+ case ValFalse(_) => ff
+ }
+
+ def convert(implicit inv: ValGenericAdtInvocationContext): Expr[G] = inv match {
+ case ValGenericAdtInvocation0(adt, _, typeArgs, _, _, func, _, args, _) =>
+ ADTFunctionInvocation(Some((new UnresolvedRef[G, AxiomaticDataType[G]](convert(adt)), convert(typeArgs))),
+ new UnresolvedRef[G, ADTFunction[G]](convert(func)), args.map(convert(_)).getOrElse(Nil))
+ }
+
+ def evalOrNop(implicit expr: Option[ExpressionContext]): Statement[G] = expr match {
+ case Some(expr) => Eval(convert(expr))(origin(expr))
+ case None =>
+ // PB: strictly speaking it would be nice if we can point to the empty range that indicates the absence of a statement here.
+ Block(Nil)(DiagnosticOrigin)
+ }
+
+}
\ No newline at end of file
diff --git a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
new file mode 100644
index 0000000000..d3edd98400
--- /dev/null
+++ b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
@@ -0,0 +1,254 @@
+package vct.col.rewrite.lang
+
+import com.typesafe.scalalogging.LazyLogging
+import hre.util.ScopedStack
+import vct.col.ast._
+import vct.col.origin._
+import vct.col.ref.Ref
+import vct.col.resolve.ctx._
+import vct.col.resolve.lang.CPP
+import vct.col.rewrite.lang.LangSpecificToCol.NotAValue
+import vct.col.rewrite.{Generation, Rewritten}
+import vct.col.util.AstBuildHelpers._
+import vct.col.util.SuccessionMap
+import vct.result.VerificationError.UserError
+
+case object LangCPPToCol {
+ case class CPPGlobalStateNotSupported(example: CPPInit[_]) extends UserError {
+ override def code: String = "notSupported"
+
+ override def text: String =
+ example.o.messageInContext("Global variables in C++ are not supported.")
+ }
+
+ case class WrongCPPType(decl: CPPLocalDeclaration[_]) extends UserError {
+ override def code: String = "wrongCPPType"
+
+ override def text: String =
+ decl.o.messageInContext(s"This declaration has a type that is not supported.")
+ }
+
+ case class CPPDoubleContracted(decl: CPPGlobalDeclaration[_], defn: CPPFunctionDefinition[_]) extends UserError {
+ override def code: String = "multipleContracts"
+
+ override def text: String =
+ Origin.messagesInContext(Seq(
+ defn.o -> "This method has a non-empty contract at its definition, ...",
+ decl.o -> "... but its forward declaration also has a contract.",
+ ))
+ }
+}
+
+case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends LazyLogging {
+ import LangCPPToCol._
+ type Post = Rewritten[Pre]
+ implicit val implicitRewriter: AbstractRewriter[Pre, Post] = rw
+
+ val cppFunctionSuccessor: SuccessionMap[CPPFunctionDefinition[Pre], Procedure[Post]] = SuccessionMap()
+ val cppFunctionDeclSuccessor: SuccessionMap[(CPPGlobalDeclaration[Pre], Int), Procedure[Post]] = SuccessionMap()
+ val cppNameSuccessor: SuccessionMap[CPPNameTarget[Pre], Variable[Post]] = SuccessionMap()
+ val cppCurrentDefinitionParamSubstitutions: ScopedStack[Map[CPPParam[Pre], CPPParam[Pre]]] = ScopedStack()
+
+ def rewriteUnit(cppUnit: CPPTranslationUnit[Pre]): Unit = {
+ cppUnit.declarations.foreach(rw.dispatch)
+ }
+
+ def rewriteParam(cppParam: CPPParam[Pre]): Unit = {
+ cppParam.drop()
+ val varO = InterpretedOriginVariable(CPP.getDeclaratorInfo(cppParam.declarator).name, cppParam.o)
+
+ val v = new Variable[Post](cppParam.specifiers.collectFirst
+ { case t: CPPSpecificationType[Pre] => rw.dispatch(t.t) }.get)(varO)
+ cppNameSuccessor(RefCPPParam(cppParam)) = v
+ rw.variables.declare(v)
+ }
+
+ def rewriteFunctionDef(func: CPPFunctionDefinition[Pre]): Unit = {
+ func.drop()
+ val info = CPP.getDeclaratorInfo(func.declarator)
+ val returnType = func.specs.collectFirst { case t: CPPSpecificationType[Pre] => rw.dispatch(t.t) }.get
+
+ val (contract, subs: Map[CPPParam[Pre], CPPParam[Pre]]) = func.ref match {
+ case Some(RefCPPGlobalDeclaration(decl, idx)) if decl.decl.contract.nonEmpty =>
+ if (func.contract.nonEmpty) throw CPPDoubleContracted(decl, func)
+
+ val declParams = CPP.getDeclaratorInfo(decl.decl.inits(idx).decl).params.get
+ val defnParams = info.params.get
+
+ (decl.decl.contract, declParams.zip(defnParams).toMap)
+ case _ =>
+ (func.contract, Map.empty)
+ }
+
+ val namedO = InterpretedOriginVariable(CPP.getDeclaratorInfo(func.declarator).name, func.o)
+ val proc =
+ cppCurrentDefinitionParamSubstitutions.having(subs) {
+ rw.globalDeclarations.declare(
+ {
+ val params = rw.variables.collect {
+ info.params.get.foreach(rw.dispatch)
+ }._1
+ rw.labelDecls.scope {
+ new Procedure[Post](
+ returnType = returnType,
+ args = params,
+ outArgs = Nil,
+ typeArgs = Nil,
+ body = Some(rw.dispatch(func.body)),
+ contract = rw.dispatch(contract),
+ )(func.blame)(namedO)
+ }
+ }
+ )
+ }
+
+ cppFunctionSuccessor(func) = proc
+
+ func.ref match {
+ case Some(RefCPPGlobalDeclaration(decl, idx)) =>
+ cppFunctionDeclSuccessor((decl, idx)) = proc
+ case None => // ok
+ }
+ }
+
+ def rewriteGlobalDecl(decl: CPPGlobalDeclaration[Pre]): Unit = {
+ val t = decl.decl.specs.collectFirst { case t: CPPSpecificationType[Pre] => rw.dispatch(t.t) }.get
+ for ((init, idx) <- decl.decl.inits.zipWithIndex if init.ref.isEmpty) {
+ // If the reference is empty, skip the declaration: the definition is used instead.
+ val info = CPP.getDeclaratorInfo(init.decl)
+ info.params match {
+ case Some(params) =>
+ cppFunctionDeclSuccessor((decl, idx)) = rw.globalDeclarations.declare(
+ new Procedure[Post](
+ returnType = t,
+ args = rw.variables.collect {
+ params.foreach(rw.dispatch)
+ }._1,
+ outArgs = Nil,
+ typeArgs = Nil,
+ body = None,
+ contract = rw.dispatch(decl.decl.contract),
+ )(AbstractApplicable)(init.o)
+ )
+ case None =>
+ throw CPPGlobalStateNotSupported(init)
+ }
+ }
+ }
+
+ def rewriteLocal(decl: CPPLocalDeclaration[Pre]): Statement[Post] = {
+ decl.drop()
+ val t = decl.decl.specs.collectFirst { case t: CPPSpecificationType[Pre] => rw.dispatch(t.t) }.get
+ decl.decl.specs.foreach {
+ case _: CPPSpecificationType[Pre] =>
+ case _ => throw WrongCPPType(decl)
+ }
+
+ // LangTypesToCol makes it so that each declaration only has one init
+ val init = decl.decl.inits.head
+
+ val info = CPP.getDeclaratorInfo(init.decl)
+ val varO: Origin = InterpretedOriginVariable(info.name, init.o)
+ t match {
+ case cta @ CPPTArray(Some(size), t) =>
+ if (init.init.isDefined) throw WrongCPPType(decl)
+ implicit val o: Origin = init.o
+ val v = new Variable[Post](TArray(t))(varO)
+ cppNameSuccessor(RefCPPLocalDeclaration(decl, 0)) = v
+ val newArr = NewArray[Post](t, Seq(size), 0)(cta.blame)
+ Block(Seq(LocalDecl(v), assignLocal(v.get, newArr)))
+ case _ =>
+ val v = new Variable[Post](t)(varO)
+ cppNameSuccessor(RefCPPLocalDeclaration(decl, 0)) = v
+ implicit val o: Origin = init.o
+ init.init
+ .map(value => Block(Seq(LocalDecl(v), assignLocal(v.get, rw.dispatch(value)))))
+ .getOrElse(LocalDecl(v))
+ }
+ }
+
+ def result(ref: RefCPPFunctionDefinition[Pre])(implicit o: Origin): Expr[Post] =
+ Result[Post](cppFunctionSuccessor.ref(ref.decl))
+
+ def result(ref: RefCPPGlobalDeclaration[Pre])(implicit o: Origin): Expr[Post] = {
+ val maybeDefinition = ref.decls.decl.inits(ref.initIdx).ref
+ maybeDefinition match {
+ case Some(defn) => Result[Post](cppFunctionSuccessor.ref(defn.decl))
+ case None => Result[Post](cppFunctionDeclSuccessor.ref((ref.decls, ref.initIdx)))
+ }
+ }
+
+ def local(local: CPPLocal[Pre]): Expr[Post] = {
+ implicit val o: Origin = local.o
+ local.ref.get match {
+ case RefAxiomaticDataType(_) => throw NotAValue(local)
+ case RefVariable(decl) => Local(rw.succ(decl))
+ case RefModelField(decl) => ModelDeref[Post](rw.currentThis.top, rw.succ(decl))(local.blame)
+ case ref: RefCPPParam[Pre] =>
+ if (cppCurrentDefinitionParamSubstitutions.nonEmpty)
+ Local(cppNameSuccessor.ref(RefCPPParam(cppCurrentDefinitionParamSubstitutions.top.getOrElse(ref.decl, ref.decl))))
+ else
+ Local(cppNameSuccessor.ref(ref))
+ case RefCPPFunctionDefinition(_) => throw NotAValue(local)
+ case RefCPPGlobalDeclaration(_, _) => throw NotAValue(local)
+ case ref: RefCPPLocalDeclaration[Pre] => Local(cppNameSuccessor.ref(ref))
+ }
+ }
+
+ def invocation(inv: CPPInvocation[Pre]): Expr[Post] = {
+ val CPPInvocation(applicable, args, givenMap, yields) = inv
+ implicit val o: Origin = inv.o
+ inv.ref.get match {
+ case RefFunction(decl) =>0
+ FunctionInvocation[Post](rw.succ(decl), args.map(rw.dispatch), Nil,
+ givenMap.map { case (Ref(v), e) => (rw.succ(v), rw.dispatch(e)) },
+ yields.map { case (e, Ref(v)) => (rw.dispatch(e), rw.succ(v)) })(inv.blame)
+ case RefProcedure(decl) =>
+ ProcedureInvocation[Post](rw.succ(decl), args.map(rw.dispatch), Nil, Nil,
+ givenMap.map { case (Ref(v), e) => (rw.succ(v), rw.dispatch(e)) },
+ yields.map { case (e, Ref(v)) => (rw.dispatch(e), rw.succ(v)) })(inv.blame)
+ case RefPredicate(decl) =>
+ PredicateApply[Post](rw.succ(decl), args.map(rw.dispatch), WritePerm())
+ case RefInstanceFunction(decl) => ???
+ case RefInstanceMethod(decl) => ???
+ case RefInstancePredicate(decl) => ???
+ case RefADTFunction(decl) =>
+ ADTFunctionInvocation[Post](None, rw.succ(decl), args.map(rw.dispatch))
+ case RefModelProcess(decl) =>
+ ProcessApply[Post](rw.succ(decl), args.map(rw.dispatch))
+ case RefModelAction(decl) =>
+ ActionApply[Post](rw.succ(decl), args.map(rw.dispatch))
+ case BuiltinInstanceMethod(f) => ???
+ case ref: RefCPPFunctionDefinition[Pre] =>
+ ProcedureInvocation[Post](cppFunctionSuccessor.ref(ref.decl), args.map(rw.dispatch), Nil, Nil,
+ givenMap.map { case (Ref(v), e) => (rw.succ(v), rw.dispatch(e)) },
+ yields.map { case (e, Ref(v)) => (rw.dispatch(e), rw.succ(v)) })(inv.blame)
+ case e: RefCPPGlobalDeclaration[Pre] => globalInvocation(e, inv)
+ case RefProverFunction(decl) => ProverFunctionInvocation(rw.succ(decl), args.map(rw.dispatch))
+ }
+ }
+
+ def globalInvocation(e: RefCPPGlobalDeclaration[Pre], inv: CPPInvocation[Pre]): Expr[Post] = {
+ val CPPInvocation(_, args, givenMap, yields) = inv
+ val RefCPPGlobalDeclaration(decls, initIdx) = e
+ implicit val o: Origin = inv.o
+
+ val arg = if (args.size == 1) {
+ args.head match {
+ case IntegerValue(i) if i >= 0 && i < 3 => Some(i.toInt)
+ case _ => None
+ }
+ } else None
+ (e.name, arg) match {
+ case _ => ProcedureInvocation[Post](cppFunctionDeclSuccessor.ref((decls, initIdx)), args.map(rw.dispatch), Nil, Nil,
+ givenMap.map { case (Ref(v), e) => (rw.succ(v), rw.dispatch(e)) },
+ yields.map { case (e, Ref(v)) => (rw.dispatch(e), rw.succ(v)) })(inv.blame)
+ }
+ }
+
+ def arrayType(t: CPPTArray[Pre]): Type[Post] = {
+ // TODO: we should not use pointer here
+ TPointer(rw.dispatch(t.innerType))
+ }
+
+}
\ No newline at end of file
diff --git a/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala b/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala
index 46dd3e1fb7..413e073f92 100644
--- a/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala
+++ b/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala
@@ -9,10 +9,7 @@ import vct.col.origin._
import vct.col.resolve.ctx._
import vct.col.resolve.lang.Java
import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder}
-import vct.col.resolve._
-import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder, RewriterBuilderArg}
import vct.result.VerificationError.UserError
-import vct.col.util.SuccessionMap
case object LangSpecificToCol extends RewriterBuilder {
override def key: String = "langSpecific"
@@ -35,6 +32,7 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
val java: LangJavaToCol[Pre] = LangJavaToCol(this)
val bip: LangBipToCol[Pre] = LangBipToCol(this)
val c: LangCToCol[Pre] = LangCToCol(this)
+ val cpp: LangCPPToCol[Pre] = LangCPPToCol(this)
val pvl: LangPVLToCol[Pre] = LangPVLToCol(this)
val silver: LangSilverToCol[Pre] = LangSilverToCol(this)
val llvm: LangLLVMToCol[Pre] = LangLLVMToCol(this)
@@ -67,6 +65,13 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
case func: CFunctionDefinition[Pre] => c.rewriteFunctionDef(func)
case decl: CGlobalDeclaration[Pre] => c.rewriteGlobalDecl(decl)
case decl: CLocalDeclaration[Pre] => ???
+
+ case unit: CPPTranslationUnit[Pre] => cpp.rewriteUnit(unit)
+ case cppParam: CPPParam[Pre] => cpp.rewriteParam(cppParam)
+ case func: CPPFunctionDefinition[Pre] => cpp.rewriteFunctionDef(func)
+ case decl: CPPGlobalDeclaration[Pre] => cpp.rewriteGlobalDecl(decl)
+ case decl: CPPLocalDeclaration[Pre] => ???
+
case func: LlvmFunctionDefinition[Pre] => llvm.rewriteFunctionDef(func)
case cls: Class[Pre] =>
@@ -103,6 +108,7 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
case JavaLocalDeclarationStatement(locals: JavaLocalDeclaration[Pre]) => java.initLocal(locals)
case CDeclarationStatement(decl) => c.rewriteLocal(decl)
+ case CPPDeclarationStatement(decl) => cpp.rewriteLocal(decl)
case goto: CGoto[Pre] => c.rewriteGoto(goto)
case barrier: GpgpuBarrier[Pre] => c.gpuBarrier(barrier)
@@ -115,6 +121,8 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
result.ref.get match {
case ref: RefCFunctionDefinition[Pre] => c.result(ref)
case ref: RefCGlobalDeclaration[Pre] => c.result(ref)
+ case ref: RefCPPFunctionDefinition[Pre] => cpp.result(ref)
+ case ref: RefCPPGlobalDeclaration[Pre] => cpp.result(ref)
case RefFunction(decl) => Result[Post](anySucc(decl))
case RefProcedure(decl) => Result[Post](anySucc(decl))
case RefJavaMethod(decl) => Result[Post](java.javaMethod.ref(decl))
@@ -154,6 +162,9 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
case global: GlobalThreadId[Pre] => c.cudaGlobalThreadId(global)
case cast: CCast[Pre] => c.cast(cast)
+ case local: CPPLocal[Pre] => cpp.local(local)
+ case inv: CPPInvocation[Pre] => cpp.invocation(inv)
+
case inv: SilverPartialADTFunctionInvocation[Pre] => silver.adtInvocation(inv)
case map: SilverUntypedNonemptyLiteralMap[Pre] => silver.nonemptyMap(map)
@@ -164,6 +175,7 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
case t: JavaTClass[Pre] => java.classType(t)
case t: CTPointer[Pre] => c.pointerType(t)
case t: CTArray[Pre] => c.arrayType(t)
+ case t: CPPTArray[Pre] => cpp.arrayType(t)
case other => rewriteDefault(other)
}
}
diff --git a/src/rewrite/vct/rewrite/lang/LangTypesToCol.scala b/src/rewrite/vct/rewrite/lang/LangTypesToCol.scala
index ae5ffe4588..2c9f5e6da6 100644
--- a/src/rewrite/vct/rewrite/lang/LangTypesToCol.scala
+++ b/src/rewrite/vct/rewrite/lang/LangTypesToCol.scala
@@ -1,13 +1,13 @@
package vct.col.rewrite.lang
+import vct.col.ast.RewriteHelpers._
import vct.col.ast._
import vct.col.origin.Origin
-import vct.col.resolve.ctx.{RefAxiomaticDataType, RefClass, RefEnum, RefJavaClass, RefModel, RefVariable, SpecTypeNameTarget, RefProverType}
-import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder, Rewritten}
-import vct.col.ast.RewriteHelpers._
-import vct.col.rewrite.lang.LangTypesToCol.IncompleteTypeArgs
import vct.col.ref.{Ref, UnresolvedRef}
-import vct.col.resolve.lang.C
+import vct.col.resolve.ctx._
+import vct.col.resolve.lang.{C, CPP}
+import vct.col.rewrite.lang.LangTypesToCol.IncompleteTypeArgs
+import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder, Rewritten}
import vct.result.VerificationError.UserError
import scala.reflect.ClassTag
@@ -62,6 +62,8 @@ case class LangTypesToCol[Pre <: Generation]() extends Rewriter[Pre] {
}
case t @ CPrimitiveType(specs) =>
dispatch(C.getPrimitiveType(specs, context = Some(t)))
+ case t@CPPPrimitiveType(specs) =>
+ dispatch(CPP.getPrimitiveType(specs, context = Some(t)))
case t @ SilverPartialTAxiomatic(Ref(adt), partialTypeArgs) =>
if(partialTypeArgs.map(_._1.decl).toSet != adt.typeArgs.toSet)
throw IncompleteTypeArgs(t)
@@ -94,6 +96,29 @@ case class LangTypesToCol[Pre <: Generation]() extends Rewriter[Pre] {
(newSpecifiers, newDeclarator)
}
+ def normalizeCPPDeclaration(specifiers: Seq[CPPDeclarationSpecifier[Pre]],
+ declarator: CPPDeclarator[Pre],
+ context: Option[Node[Pre]] = None)
+ (implicit o: Origin): (Seq[CPPDeclarationSpecifier[Post]], CPPDeclarator[Post]) = {
+ val info = CPP.getDeclaratorInfo(declarator)
+ val baseType = CPP.getPrimitiveType(specifiers, context)
+ val otherSpecifiers = specifiers.filter(!_.isInstanceOf[CPPTypeSpecifier[Pre]]).map(dispatch)
+ val newSpecifiers = CPPSpecificationType[Post](dispatch(info.typeOrReturnType(baseType))) +: otherSpecifiers
+ val newDeclarator = info.params match {
+ case Some(params) =>
+ // PB TODO: varargs is discarded here.
+ CPPTypedFunctionDeclarator[Post](
+ cPPParams.dispatch(params),
+ varargs = false,
+ CPPName(info.name)
+ )
+ case None =>
+ CPPName[Post](info.name)
+ }
+
+ (newSpecifiers, newDeclarator)
+ }
+
override def dispatch(decl: Declaration[Pre]): Unit = decl match {
case param: CParam[Pre] =>
val (specs, decl) = normalizeCDeclaration(param.specifiers, param.declarator, context = Some(param))(param.o)
@@ -128,6 +153,39 @@ case class LangTypesToCol[Pre <: Generation]() extends Rewriter[Pre] {
implicit val o: Origin = declaration.o
val (specs, decl) = normalizeCDeclaration(declaration.specs, declaration.declarator, context = Some(declaration))
globalDeclarations.declare(declaration.rewrite(specs = specs, declarator = decl))
+ case param: CPPParam[Pre] =>
+ val (specs, decl) = normalizeCPPDeclaration(param.specifiers, param.declarator, context = Some(param))(param.o)
+ cPPParams.declare(new CPPParam(specs, decl)(param.o))
+ case declaration: CPPLocalDeclaration[Pre] =>
+ declaration.decl.inits.foreach(init => {
+ implicit val o: Origin = init.o
+ val (specs, decl) = normalizeCPPDeclaration(declaration.decl.specs, init.decl, context = Some(declaration))
+ cPPLocalDeclarations.declare(declaration.rewrite(
+ decl = declaration.decl.rewrite(
+ specs = specs,
+ inits = Seq(
+ CPPInit(decl, init.init.map(dispatch)),
+ ),
+ ),
+ ))
+ })
+ case declaration: CPPGlobalDeclaration[Pre] =>
+ declaration.decl.inits.foreach(init => {
+ implicit val o: Origin = init.o
+ val (specs, decl) = normalizeCPPDeclaration(declaration.decl.specs, init.decl, context = Some(declaration))
+ globalDeclarations.declare(declaration.rewrite(
+ decl = declaration.decl.rewrite(
+ specs = specs,
+ inits = Seq(
+ CPPInit(decl, init.init.map(dispatch)),
+ ),
+ ),
+ ))
+ })
+ case declaration: CPPFunctionDefinition[Pre] =>
+ implicit val o: Origin = declaration.o
+ val (specs, decl) = normalizeCPPDeclaration(declaration.specs, declaration.declarator, context = Some(declaration))
+ globalDeclarations.declare(declaration.rewrite(specs = specs, declarator = decl))
case cls: JavaClass[Pre] =>
rewriteDefault(cls)
case other => rewriteDefault(other)
@@ -137,6 +195,9 @@ case class LangTypesToCol[Pre <: Generation]() extends Rewriter[Pre] {
case CDeclarationStatement(local) =>
val (locals, _) = cLocalDeclarations.collect { dispatch(local) }
Block(locals.map(CDeclarationStatement(_)(stat.o)))(stat.o)
+ case CPPDeclarationStatement(local) =>
+ val (locals, _) = cPPLocalDeclarations.collect { dispatch(local) }
+ Block(locals.map(CPPDeclarationStatement(_)(stat.o)))(stat.o)
case other => rewriteDefault(other)
}
diff --git a/test/main/vct/test/integration/examples/CPPSpec.scala b/test/main/vct/test/integration/examples/CPPSpec.scala
new file mode 100644
index 0000000000..562240568d
--- /dev/null
+++ b/test/main/vct/test/integration/examples/CPPSpec.scala
@@ -0,0 +1,23 @@
+package vct.test.integration.examples
+
+import vct.test.integration.helper.VercorsSpec
+
+class CPPSpec extends VercorsSpec {
+ vercors should verify using silicon example("concepts/cpp/Arrays.cpp")
+ vercors should verify using silicon example("concepts/cpp/Conditionals.cpp")
+ vercors should verify using silicon example("concepts/cpp/Loops.cpp")
+ vercors should verify using silicon example("concepts/cpp/Operators.cpp")
+ vercors should verify using silicon examples("concepts/cpp/Pointers.cpp")
+ vercors should verify using silicon examples("concepts/cpp/Scoping.cpp")
+ vercors should verify using silicon examples("concepts/cpp/Types.cpp")
+
+ vercors should verify using silicon examples("concepts/cpp/methods/AbstractMethod.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/ContextAndContextEverywhere.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/Decreases.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/GhostMethodsAndVariables.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/GhostParamsAndResults.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/InlineFunction.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/Permissions.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/Predicates.cpp")
+ vercors should verify using silicon examples("concepts/cpp/methods/PureGhostMethod.cpp")
+}
\ No newline at end of file
From a7f1ff8107aa466d1bf55fd33fc1890a95fcb7e5 Mon Sep 17 00:00:00 2001
From: Pieter Bos
Date: Fri, 30 Jun 2023 14:31:21 +0200
Subject: [PATCH 04/11] do not depend on compilation for
buildTarget/scalacOptions and/or bspCompileClasspath
---
project/common.sc | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/project/common.sc b/project/common.sc
index b42e0b57bf..afa693e928 100644
--- a/project/common.sc
+++ b/project/common.sc
@@ -83,6 +83,17 @@ trait JavaModule extends BaseJavaModule {
}
T.dest
}
+
+ def bspTransitiveCompileClasspath: T[Agg[UnresolvedPath]] = T {
+ T.traverse(
+ (moduleDeps ++ compileModuleDeps).flatMap(_.transitiveModuleDeps).distinct
+ )(m =>
+ T.task {
+ m.bspCompileClasspath() ++ Agg(m.bspCompileClassesPath())
+ }
+ )()
+ .flatten
+ }
}
trait ScalaModule extends BaseScalaModule with JavaModule {
From c7d4d7bb4cc04d5289480b7835395328da1a4262 Mon Sep 17 00:00:00 2001
From: Pieter Bos
Date: Fri, 30 Jun 2023 14:45:06 +0200
Subject: [PATCH 05/11] no more ammonite
---
.github/workflows/scalatest.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/scalatest.yml b/.github/workflows/scalatest.yml
index 020e632a83..37d4c588a7 100644
--- a/.github/workflows/scalatest.yml
+++ b/.github/workflows/scalatest.yml
@@ -33,7 +33,7 @@ jobs:
!**/upstreamAssembly.json
key: vercors-ci-ubuntu
- name: Compile
- run: ./mill --no-default-predef -j 0 allTests.assembly
+ run: ./mill -j 0 allTests.assembly
- name: Upload
uses: actions/upload-artifact@v3
with:
From 897b0398f9792512b55bf6d654a8acefee4a119f Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Fri, 30 Jun 2023 16:06:22 +0200
Subject: [PATCH 06/11] added global variable support
---
src/col/vct/col/resolve/Resolve.scala | 13 +++++++++----
src/main/vct/main/stages/Resolution.scala | 16 ----------------
src/rewrite/vct/rewrite/lang/LangCPPToCol.scala | 16 ++++++++--------
3 files changed, 17 insertions(+), 28 deletions(-)
diff --git a/src/col/vct/col/resolve/Resolve.scala b/src/col/vct/col/resolve/Resolve.scala
index 254724b04e..6259d23f50 100644
--- a/src/col/vct/col/resolve/Resolve.scala
+++ b/src/col/vct/col/resolve/Resolve.scala
@@ -323,10 +323,15 @@ case object ResolveReferences extends LazyLogging {
if (func.decl.contract.nonEmpty && func.decl.inits.size > 1) {
throw MultipleForwardDeclarationContractError(func)
}
- ctx
- .declare(CPP.paramsFromDeclarator(func.decl.inits.head.decl) ++ func.decl.contract.givenArgs ++ func.decl.contract.yieldsArgs)
- .copy(currentResult = CPP.getDeclaratorInfo(func.decl.inits.head.decl)
- .params.map(_ => RefCPPGlobalDeclaration(func, initIdx = 0)))
+ func.decl.inits.zipWithIndex.foldLeft(
+ ctx.declare(func.decl.contract.givenArgs ++ func.decl.contract.yieldsArgs)
+ ) {
+ case (ctx, (init, idx)) =>
+ val info = CPP.getDeclaratorInfo(init.decl)
+ ctx
+ .declare(info.params.getOrElse(Nil))
+ .copy(currentResult = info.params.map(_ => RefCPPGlobalDeclaration(func, idx)))
+ }
case func: LlvmFunctionDefinition[G] => ctx
.copy(currentResult = Some(RefLlvmFunctionDefinition(func)))
case par: ParStatement[G] => ctx
diff --git a/src/main/vct/main/stages/Resolution.scala b/src/main/vct/main/stages/Resolution.scala
index cdbc5b35fa..f1504cf014 100644
--- a/src/main/vct/main/stages/Resolution.scala
+++ b/src/main/vct/main/stages/Resolution.scala
@@ -6,13 +6,11 @@ import org.antlr.v4.runtime.CharStreams
import vct.col.ast._
import vct.col.check.CheckError
import vct.col.origin.{FileSpanningOrigin, LLVMOrigin, Origin}
-import vct.col.resolve.lang.{C, CPP}
import vct.col.resolve.{Resolve, ResolveReferences, ResolveTypes}
import vct.col.rewrite.Generation
import vct.col.rewrite.bip.IsolateBipGlue
import vct.col.rewrite.lang.{LangSpecificToCol, LangTypesToCol}
import vct.importer.JavaLibraryLoader
-import vct.main.Main.TemporarilyUnsupported
import vct.main.stages.Resolution.InputResolutionError
import vct.options.Options
import vct.options.types.ClassPathEntry
@@ -96,20 +94,6 @@ case class Resolution[G <: Generation]
override def progressWeight: Int = 1
override def run(in: ParseResult[G]): Verification[_ <: Generation] = {
- in.decls.foreach(_.transSubnodes.foreach {
- case decl: CGlobalDeclaration[_] => decl.decl.inits.foreach(init => {
- if(C.getDeclaratorInfo(init.decl).params.isEmpty) {
- throw TemporarilyUnsupported("GlobalCVariable", Seq(decl))
- }
- })
- case decl: CPPGlobalDeclaration[_] => decl.decl.inits.foreach(init => {
- if (CPP.getDeclaratorInfo(init.decl).params.isEmpty) {
- throw TemporarilyUnsupported("GlobalCPPVariable", Seq(decl))
- }
- })
- case _ =>
- })
-
implicit val o: Origin = FileSpanningOrigin
val parsedProgram = Program(in.decls)(blameProvider())
diff --git a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
index d3edd98400..54103a7d16 100644
--- a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
+++ b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
@@ -14,12 +14,6 @@ import vct.col.util.SuccessionMap
import vct.result.VerificationError.UserError
case object LangCPPToCol {
- case class CPPGlobalStateNotSupported(example: CPPInit[_]) extends UserError {
- override def code: String = "notSupported"
-
- override def text: String =
- example.o.messageInContext("Global variables in C++ are not supported.")
- }
case class WrongCPPType(decl: CPPLocalDeclaration[_]) extends UserError {
override def code: String = "wrongCPPType"
@@ -47,6 +41,7 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
val cppFunctionSuccessor: SuccessionMap[CPPFunctionDefinition[Pre], Procedure[Post]] = SuccessionMap()
val cppFunctionDeclSuccessor: SuccessionMap[(CPPGlobalDeclaration[Pre], Int), Procedure[Post]] = SuccessionMap()
val cppNameSuccessor: SuccessionMap[CPPNameTarget[Pre], Variable[Post]] = SuccessionMap()
+ val cppGlobalNameSuccessor: SuccessionMap[CPPNameTarget[Pre], HeapVariable[Post]] = SuccessionMap()
val cppCurrentDefinitionParamSubstitutions: ScopedStack[Map[CPPParam[Pre], CPPParam[Pre]]] = ScopedStack()
def rewriteUnit(cppUnit: CPPTranslationUnit[Pre]): Unit = {
@@ -131,7 +126,8 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
)(AbstractApplicable)(init.o)
)
case None =>
- throw CPPGlobalStateNotSupported(init)
+ cppGlobalNameSuccessor(RefCPPGlobalDeclaration(decl, idx)) =
+ rw.globalDeclarations.declare(new HeapVariable(t)(init.o))
}
}
}
@@ -190,7 +186,11 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
else
Local(cppNameSuccessor.ref(ref))
case RefCPPFunctionDefinition(_) => throw NotAValue(local)
- case RefCPPGlobalDeclaration(_, _) => throw NotAValue(local)
+ case ref @ RefCPPGlobalDeclaration(decl, initIdx) =>
+ CPP.getDeclaratorInfo(decl.decl.inits(initIdx).decl).params match {
+ case None => DerefHeapVariable[Post](cppGlobalNameSuccessor.ref(ref))(local.blame)
+ case Some(_) => throw NotAValue(local)
+ }
case ref: RefCPPLocalDeclaration[Pre] => Local(cppNameSuccessor.ref(ref))
}
}
From 62146100581184595f9b1c960ae6d6a14f8be1e2 Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Mon, 3 Jul 2023 14:41:01 +0200
Subject: [PATCH 07/11] added namespace declaration and usage support
---
examples/concepts/cpp/Namespaces.cpp | 48 ++++++++++++
...espacesDoNotFindWithoutNamespacePrefix.cpp | 15 ++++
src/col/vct/col/ast/Node.scala | 5 +-
src/col/vct/col/ast/lang/CPPLocalImpl.scala | 2 +-
.../ast/lang/CPPNamespaceDefinitionImpl.scala | 13 ++++
.../vct/col/ast/lang/CPPTypedefNameImpl.scala | 2 +-
src/col/vct/col/feature/FeatureRainbow.scala | 1 +
src/col/vct/col/resolve/Resolve.scala | 9 ++-
src/col/vct/col/resolve/ctx/Referrable.scala | 3 +
src/col/vct/col/resolve/lang/CPP.scala | 45 +++++++++--
.../vct/col/typerules/CoercingRewriter.scala | 10 ++-
src/parsers/antlr4/LangCPPParser.g4 | 26 ++++---
.../vct/parsers/transform/CPPToCol.scala | 78 +++++++++++--------
.../vct/rewrite/lang/LangCPPToCol.scala | 11 ++-
.../vct/rewrite/lang/LangSpecificToCol.scala | 4 +-
.../test/integration/examples/CPPSpec.scala | 34 ++++----
16 files changed, 222 insertions(+), 84 deletions(-)
create mode 100644 examples/concepts/cpp/Namespaces.cpp
create mode 100644 examples/concepts/cpp/NamespacesDoNotFindWithoutNamespacePrefix.cpp
create mode 100644 src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala
diff --git a/examples/concepts/cpp/Namespaces.cpp b/examples/concepts/cpp/Namespaces.cpp
new file mode 100644
index 0000000000..f732fd0107
--- /dev/null
+++ b/examples/concepts/cpp/Namespaces.cpp
@@ -0,0 +1,48 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases Namespaces
+//:: tools silicon
+//:: verdict Pass
+
+int x;
+
+namespace spaceA {
+ int x;
+
+ //@ context Perm(x, write);
+ //@ ensures x == 90;
+ //@ ensures \result == \old(x) + 1;
+ int incr() {
+ int newX = x + 1;
+ x = 90;
+ return newX;
+ }
+
+ namespace spaceB {
+ //@ context Perm(x, 0.5);
+ //@ ensures \result == x + 2;
+ int incr() {
+ return x + 2;
+ }
+
+ void doNothing() {};
+ }
+}
+
+//@ context Perm(spaceA::x, write);
+//@ context Perm(x, write);
+int main() {
+ x = 99;
+ spaceA::x = 5;
+ //@ assert spaceA::x == 5;
+ int varA = spaceA::incr();
+ //@ assert varA == 6;
+ //@ assert spaceA::x == 90;
+ int varB = spaceA::spaceB::incr();
+ //@ assert varB == 92;
+ spaceA::spaceB::doNothing();
+ int varX = spaceA::x;
+ //@ assert varX == 90;
+
+ //@ assert x == 99;
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/concepts/cpp/NamespacesDoNotFindWithoutNamespacePrefix.cpp b/examples/concepts/cpp/NamespacesDoNotFindWithoutNamespacePrefix.cpp
new file mode 100644
index 0000000000..d9e7ff8f04
--- /dev/null
+++ b/examples/concepts/cpp/NamespacesDoNotFindWithoutNamespacePrefix.cpp
@@ -0,0 +1,15 @@
+// -*- tab-width:2 ; indent-tabs-mode:nil -*-
+//:: cases NamespacesDoNotFindWithoutNamespacePrefix
+//:: tools silicon
+//:: verdict Fail
+
+namespace spaceA {
+
+ namespace spaceB {
+ int b = 10;
+ }
+
+ int getB() {
+ return b;
+ }
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/Node.scala b/src/col/vct/col/ast/Node.scala
index e8a760cc38..8266d5e830 100644
--- a/src/col/vct/col/ast/Node.scala
+++ b/src/col/vct/col/ast/Node.scala
@@ -970,7 +970,7 @@ final case class CPPLong[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G
final case class CPPSigned[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPSignedImpl[G]
final case class CPPUnsigned[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPUnsignedImpl[G]
final case class CPPBool[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPBoolImpl[G]
-final case class CPPTypedefName[G](name: String)(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPTypedefNameImpl[G] {
+final case class CPPTypedefName[G](nestedName: Seq[String])(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPTypedefNameImpl[G] {
var ref: Option[CPPTypeNameTarget[G]] = None
}
@@ -1001,12 +1001,13 @@ final class CPPLocalDeclaration[G](val decl: CPPDeclaration[G])(implicit val o:
final class CPPFunctionDefinition[G](val contract: ApplicableContract[G], val specs: Seq[CPPDeclarationSpecifier[G]], val declarator: CPPDeclarator[G], val body: Statement[G])(val blame: Blame[CallableFailure])(implicit val o: Origin) extends GlobalDeclaration[G] with CPPFunctionDefinitionImpl[G] {
var ref: Option[RefCPPGlobalDeclaration[G]] = None
}
+final class CPPNamespaceDefinition[G](val name: String, val declarations: Seq[GlobalDeclaration[G]])(implicit val o: Origin) extends GlobalDeclaration[G] with CPPNamespaceDefinitionImpl[G]
sealed trait CPPStatement[G] extends Statement[G] with CPPStatementImpl[G]
final case class CPPDeclarationStatement[G](decl: CPPLocalDeclaration[G])(implicit val o: Origin) extends CPPStatement[G] with CPPDeclarationStatementImpl[G]
sealed trait CPPExpr[G] extends Expr[G] with CPPExprImpl[G]
-final case class CPPLocal[G](name: String)(val blame: Blame[DerefInsufficientPermission])(implicit val o: Origin) extends CPPExpr[G] with CPPLocalImpl[G] {
+final case class CPPLocal[G](name: Seq[String])(val blame: Blame[DerefInsufficientPermission])(implicit val o: Origin) extends CPPExpr[G] with CPPLocalImpl[G] {
var ref: Option[CPPNameTarget[G]] = None
}
final case class CPPInvocation[G](applicable: Expr[G], args: Seq[Expr[G]], givenArgs: Seq[(Ref[G, Variable[G]], Expr[G])], yields: Seq[(Expr[G], Ref[G, Variable[G]])])(val blame: Blame[FrontendInvocationError])(implicit val o: Origin) extends CPPExpr[G] with CPPInvocationImpl[G] {
diff --git a/src/col/vct/col/ast/lang/CPPLocalImpl.scala b/src/col/vct/col/ast/lang/CPPLocalImpl.scala
index 5246f352dd..cbb11f208c 100644
--- a/src/col/vct/col/ast/lang/CPPLocalImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPLocalImpl.scala
@@ -28,5 +28,5 @@ trait CPPLocalImpl[G] { this: CPPLocal[G] =>
case target: SpecInvocationTarget[G] => Types.notAValue(target)
}
- override def layout(implicit ctx: Ctx): Doc = Text(name)
+ override def layout(implicit ctx: Ctx): Doc = Text(name.mkString("::"))
}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala b/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala
new file mode 100644
index 0000000000..e9403c772c
--- /dev/null
+++ b/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala
@@ -0,0 +1,13 @@
+package vct.col.ast.lang
+
+import vct.col.ast.CPPNamespaceDefinition
+import vct.col.print._
+
+trait CPPNamespaceDefinitionImpl[G] { this: CPPNamespaceDefinition[G] =>
+
+ override def layout(implicit ctx: Ctx): Doc =
+ Doc.stack(Seq(
+ Text("namespace") <+> Text(name),
+ Doc.stack(declarations),
+ ))
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala b/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
index b2e42cbe4b..f504f0459b 100644
--- a/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
@@ -4,5 +4,5 @@ import vct.col.ast.CPPTypedefName
import vct.col.print.{Ctx, Doc, Text}
trait CPPTypedefNameImpl[G] { this: CPPTypedefName[G] =>
- override def layout(implicit ctx: Ctx): Doc = Text(name)
+ override def layout(implicit ctx: Ctx): Doc = Text(nestedName.mkString("::"))
}
\ No newline at end of file
diff --git a/src/col/vct/col/feature/FeatureRainbow.scala b/src/col/vct/col/feature/FeatureRainbow.scala
index 889a8891a1..44326fc9cf 100644
--- a/src/col/vct/col/feature/FeatureRainbow.scala
+++ b/src/col/vct/col/feature/FeatureRainbow.scala
@@ -223,6 +223,7 @@ class FeatureRainbow[G] {
case node: CPPLocalDeclaration[G] => CPPSpecific
case node: CPPLong[G] => CPPSpecific
case node: CPPName[G] => CPPSpecific
+ case node: CPPNamespaceDefinition[G] => CPPSpecific
case node: CPPParam[G] => CPPSpecific
case node: CPPPrimitiveType[G] => CPPSpecific
case node: CPPPure[G] => CPPSpecific
diff --git a/src/col/vct/col/resolve/Resolve.scala b/src/col/vct/col/resolve/Resolve.scala
index 6259d23f50..593146ae9d 100644
--- a/src/col/vct/col/resolve/Resolve.scala
+++ b/src/col/vct/col/resolve/Resolve.scala
@@ -127,9 +127,9 @@ case object ResolveTypes {
t.ref = Some(C.findCTypeName(name, ctx).getOrElse(
throw NoSuchNameError("struct", name, t)
))
- case t@CPPTypedefName(name) =>
- t.ref = Some(CPP.findCPPTypeName(name, ctx).getOrElse(
- throw NoSuchNameError("class or struct", name, t)
+ case t@CPPTypedefName(nestedName) =>
+ t.ref = Some(CPP.findCPPTypeName(nestedName, ctx).getOrElse(
+ throw NoSuchNameError("class, struct, or namespace", nestedName.mkString("::"), t)
))
case t @ PVLNamedType(name, typeArgs) =>
t.ref = Some(PVL.findTypeName(name, ctx).getOrElse(
@@ -319,6 +319,7 @@ case object ResolveReferences extends LazyLogging {
ctx
.copy(currentResult = Some(RefCPPFunctionDefinition(func)))
.declare(CPP.paramsFromDeclarator(func.declarator) ++ scanLabels(func.body) ++ func.contract.givenArgs ++ func.contract.yieldsArgs)
+ case ns: CPPNamespaceDefinition[G] => ctx.declare(ns.declarations)
case func: CPPGlobalDeclaration[G] =>
if (func.decl.contract.nonEmpty && func.decl.inits.size > 1) {
throw MultipleForwardDeclarationContractError(func)
@@ -349,7 +350,7 @@ case object ResolveReferences extends LazyLogging {
case local@CLocal(name) =>
local.ref = Some(C.findCName(name, ctx).getOrElse(throw NoSuchNameError("local", name, local)))
case local@CPPLocal(name) =>
- local.ref = Some(CPP.findCPPName(name, ctx).getOrElse(throw NoSuchNameError("local", name, local)))
+ local.ref = Some(CPP.findCPPName(name, ctx).getOrElse(throw NoSuchNameError("local", name.mkString("::"), local)))
case local @ JavaLocal(name) =>
val start: Option[JavaNameTarget[G]] = if (ctx.javaBipGuardsEnabled) {
Java.findJavaBipGuard(ctx, name).map(RefJavaBipGuard(_))
diff --git a/src/col/vct/col/resolve/ctx/Referrable.scala b/src/col/vct/col/resolve/ctx/Referrable.scala
index c73992f167..9f48b5aa07 100644
--- a/src/col/vct/col/resolve/ctx/Referrable.scala
+++ b/src/col/vct/col/resolve/ctx/Referrable.scala
@@ -22,6 +22,7 @@ sealed trait Referrable[G] {
case RefCPPTranslationUnit(_) => ""
case RefCPPParam(decl) => CPP.nameFromDeclarator(decl.declarator)
case RefCPPFunctionDefinition(decl) => CPP.nameFromDeclarator(decl.declarator)
+ case RefCPPNamespaceDefinition(_) => ""
case RefCPPGlobalDeclaration(decls, initIdx) => CPP.nameFromDeclarator(decls.decl.inits(initIdx).decl)
case RefCPPLocalDeclaration(decls, initIdx) => CPP.nameFromDeclarator(decls.decl.inits(initIdx).decl)
case RefJavaNamespace(_) => ""
@@ -92,6 +93,7 @@ case object Referrable {
case decl: CPPTranslationUnit[G] => RefCPPTranslationUnit(decl)
case decl: CPPParam[G] => RefCPPParam(decl)
case decl: CPPFunctionDefinition[G] => RefCPPFunctionDefinition(decl)
+ case decl: CPPNamespaceDefinition[G] => RefCPPNamespaceDefinition(decl)
case decl: CPPGlobalDeclaration[G] => return decl.decl.inits.indices.map(RefCPPGlobalDeclaration(decl, _))
case decl: JavaNamespace[G] => RefJavaNamespace(decl)
case decl: JavaClass[G] => RefJavaClass(decl)
@@ -206,6 +208,7 @@ case class RefCLocalDeclaration[G](decls: CLocalDeclaration[G], initIdx: Int) ex
case class RefCPPTranslationUnit[G](decl: CPPTranslationUnit[G]) extends Referrable[G]
case class RefCPPParam[G](decl: CPPParam[G]) extends Referrable[G] with CPPNameTarget[G]
case class RefCPPFunctionDefinition[G](decl: CPPFunctionDefinition[G]) extends Referrable[G] with CPPNameTarget[G] with CPPInvocationTarget[G] with ResultTarget[G]
+case class RefCPPNamespaceDefinition[G](decl: CPPNamespaceDefinition[G]) extends Referrable[G]
case class RefCPPGlobalDeclaration[G](decls: CPPGlobalDeclaration[G], initIdx: Int) extends Referrable[G] with CPPNameTarget[G] with CPPInvocationTarget[G] with ResultTarget[G]
case class RefCPPLocalDeclaration[G](decls: CPPLocalDeclaration[G], initIdx: Int) extends Referrable[G] with CPPNameTarget[G]
case class RefJavaNamespace[G](decl: JavaNamespace[G]) extends Referrable[G]
diff --git a/src/col/vct/col/resolve/lang/CPP.scala b/src/col/vct/col/resolve/lang/CPP.scala
index ab82452c54..0952ca664f 100644
--- a/src/col/vct/col/resolve/lang/CPP.scala
+++ b/src/col/vct/col/resolve/lang/CPP.scala
@@ -80,17 +80,50 @@ case object CPP {
def paramsFromDeclarator[G](declarator: CPPDeclarator[G]): Seq[CPPParam[G]] =
getDeclaratorInfo(declarator).params.get
- def findCPPTypeName[G](name: String, ctx: TypeResolutionContext[G]): Option[CPPTypeNameTarget[G]] =
+ def findCPPTypeName[G](names: Seq[String], ctx: TypeResolutionContext[G]): Option[CPPTypeNameTarget[G]] =
ctx.stack.flatten.collectFirst {
- case target: CPPTypeNameTarget[G] if target.name == name => target
+ case target: CPPTypeNameTarget[G] if target.name == names.mkString("::") => target
}
- def findCPPName[G](name: String, ctx: ReferenceResolutionContext[G]): Option[CPPNameTarget[G]] =
- name match {
- case _ => ctx.stack.flatten.collectFirst {
- case target: CPPNameTarget[G] if target.name == name => target
+ def findCPPName[G](name: Seq[String], ctx: ReferenceResolutionContext[G]): Option[CPPNameTarget[G]] = {
+ if (name.length == 1) {
+ ctx.stack.flatten.collectFirst {
+ case target: CPPNameTarget[G] if target.name == name.head => target
+ }
+ } else {
+ val ctxTarget: Option[RefCPPNamespaceDefinition[G]] = ctx.stack.flatten.collectFirst {
+ case namespace: RefCPPNamespaceDefinition[G] if namespace.decl.name == name.head => namespace
+ }
+
+ ctxTarget match {
+ case Some(ref) =>
+ var curNameSeq = name.drop(1);
+ var foundNamespace: Option[CPPNamespaceDefinition[G]] = Some(ref.decl);
+ var returnVal: Option[CPPNameTarget[G]] = None;
+ while (curNameSeq.nonEmpty) {
+ if (foundNamespace.isEmpty) {
+ return None
+ }
+
+ if (curNameSeq.length > 1) {
+ // Look for nested namespaces
+ foundNamespace = foundNamespace.get.declarations.collectFirst {
+ case namespace: CPPNamespaceDefinition[G] if namespace.name == curNameSeq.head => namespace
+ }
+ } else {
+ // Look for final nameTarget
+ returnVal = foundNamespace.get.declarations.collectFirst {
+ case funcDef: CPPFunctionDefinition[G] if getDeclaratorInfo(funcDef.declarator).name == curNameSeq.head => RefCPPFunctionDefinition(funcDef)
+ case globalDecl: CPPGlobalDeclaration[G] if getDeclaratorInfo(globalDecl.decl.inits.head.decl).name == curNameSeq.head => RefCPPGlobalDeclaration(globalDecl, 0)
+ }
+ }
+ curNameSeq = curNameSeq.drop(1)
+ }
+ returnVal
+ case None => None
}
}
+ }
def findForwardDeclaration[G](declarator: CPPDeclarator[G], ctx: ReferenceResolutionContext[G]): Option[RefCPPGlobalDeclaration[G]] =
ctx.stack.flatten.collectFirst {
diff --git a/src/col/vct/col/typerules/CoercingRewriter.scala b/src/col/vct/col/typerules/CoercingRewriter.scala
index 7c5d496f1f..769ec1347d 100644
--- a/src/col/vct/col/typerules/CoercingRewriter.scala
+++ b/src/col/vct/col/typerules/CoercingRewriter.scala
@@ -351,6 +351,10 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
def postCoerce(node: CDeclaration[Pre]): CDeclaration[Post] = rewriteDefault(node)
override final def dispatch(node: CDeclaration[Pre]): CDeclaration[Post] = postCoerce(coerce(preCoerce(node)))
+ def preCoerce(node: GpuMemoryFence[Pre]): GpuMemoryFence[Pre] = node
+ def postCoerce(node: GpuMemoryFence[Pre]): GpuMemoryFence[Post] = rewriteDefault(node)
+ override final def dispatch(node: GpuMemoryFence[Pre]): GpuMemoryFence[Post] = postCoerce(coerce(preCoerce(node)))
+
def preCoerce(node: CPPDeclarator[Pre]): CPPDeclarator[Pre] = node
def postCoerce(node: CPPDeclarator[Pre]): CPPDeclarator[Post] = rewriteDefault(node)
override final def dispatch(node: CPPDeclarator[Pre]): CPPDeclarator[Post] = postCoerce(coerce(preCoerce(node)))
@@ -371,10 +375,6 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
def postCoerce(node: CPPInit[Pre]): CPPInit[Post] = rewriteDefault(node)
override final def dispatch(node: CPPInit[Pre]): CPPInit[Post] = postCoerce(coerce(preCoerce(node)))
- def preCoerce(node: GpuMemoryFence[Pre]): GpuMemoryFence[Pre] = node
- def postCoerce(node: GpuMemoryFence[Pre]): GpuMemoryFence[Post] = rewriteDefault(node)
- override final def dispatch(node: GpuMemoryFence[Pre]): GpuMemoryFence[Post] = postCoerce(coerce(preCoerce(node)))
-
def preCoerce(node: JavaName[Pre]): JavaName[Pre] = node
def postCoerce(node: JavaName[Pre]): JavaName[Post] = rewriteDefault(node)
override final def dispatch(node: JavaName[Pre]): JavaName[Post] = postCoerce(coerce(preCoerce(node)))
@@ -1660,6 +1660,8 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
declaration
case definition: CPPFunctionDefinition[Pre] =>
definition
+ case namespace: CPPNamespaceDefinition[Pre] =>
+ namespace
case declaration: CPPGlobalDeclaration[Pre] =>
declaration
case namespace: JavaNamespace[Pre] =>
diff --git a/src/parsers/antlr4/LangCPPParser.g4 b/src/parsers/antlr4/LangCPPParser.g4
index b38176f9b8..5ee6065939 100644
--- a/src/parsers/antlr4/LangCPPParser.g4
+++ b/src/parsers/antlr4/LangCPPParser.g4
@@ -55,11 +55,12 @@ unqualifiedId:
qualifiedId: nestedNameSpecifier Template? unqualifiedId;
nestedNameSpecifier:
- (theTypeName | namespaceName | decltypeSpecifier)? Doublecolon
- | nestedNameSpecifier (
- clangppIdentifier
- | Template? simpleTemplateId
- ) Doublecolon;
+ theTypeName Doublecolon
+ | namespaceName Doublecolon
+ | decltypeSpecifier Doublecolon
+ | Doublecolon
+ | nestedNameSpecifier clangppIdentifier Doublecolon
+ | nestedNameSpecifier Template? simpleTemplateId Doublecolon;
lambdaExpression:
lambdaIntroducer lambdaDeclarator? compoundStatement;
@@ -181,8 +182,8 @@ pointerMemberExpression:
| pointerMemberExpression ArrowStar prependExpression;
prependExpression:
- castExpression prependOp prependExpression
- | castExpression;
+ castExpression
+ | castExpression prependOp prependExpression;
prependOp: {specLevel>0}? valPrependOp;
@@ -345,11 +346,13 @@ jumpStatement:
| Goto clangppIdentifier Semi;
// Declarations
-declarationseq: declaration+;
+declarationseq:
+ declaration Semi*
+ | declarationseq declaration Semi*;
declaration:
- blockDeclaration
- | functionDefinition
+ functionDefinition
+ | blockDeclaration
| templateDeclaration
| explicitInstantiation
| explicitSpecialization
@@ -493,8 +496,7 @@ namespaceName: originalNamespaceName | namespaceAlias;
originalNamespaceName: clangppIdentifier;
namespaceDefinition:
- Inline? Namespace (clangppIdentifier | originalNamespaceName)? LeftBrace namespaceBody = declarationseq
- ? RightBrace;
+ Inline? Namespace clangppIdentifier? LeftBrace declarationseq? RightBrace;
namespaceAlias: clangppIdentifier;
diff --git a/src/parsers/vct/parsers/transform/CPPToCol.scala b/src/parsers/vct/parsers/transform/CPPToCol.scala
index 77e17105af..4ac67fb39d 100644
--- a/src/parsers/vct/parsers/transform/CPPToCol.scala
+++ b/src/parsers/vct/parsers/transform/CPPToCol.scala
@@ -23,18 +23,26 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
}
def convert(implicit declSeq: DeclarationseqContext): Seq[GlobalDeclaration[G]] = declSeq match {
- case Declarationseq0(decls) => decls.flatMap(convert(_))
+ case Declarationseq0(decl, _) => convert(decl)
+ case Declarationseq1(declSeq, decl, _) => convert(declSeq) ++ convert(decl)
}
- // Only support block declarations, function declarations, empty declarations, and VerCors global declarations
+ // Only support block declarations, function declarations, namespace declarations, empty declarations, and VerCors global declarations
def convert(implicit decl: DeclarationContext): Seq[GlobalDeclaration[G]] = decl match {
- case Declaration0(blockDecl) => Seq(new CPPGlobalDeclaration(convert(blockDecl)))
- case Declaration1(funcDecl) => Seq(convert(funcDecl))
+ case Declaration0(funcDecl) => Seq(convert(funcDecl))
+ case Declaration1(blockDecl) => Seq(new CPPGlobalDeclaration(convert(blockDecl)))
+ case Declaration6(namespaceDecl) => Seq(convert(namespaceDecl))
case Declaration7(_) => Seq()
case Declaration9(globalSpecDecl) => convert(globalSpecDecl)
case x => ??(x)
}
+ // Do not support inline and unnamed namespaces
+ def convert(implicit nsDef: NamespaceDefinitionContext): CPPNamespaceDefinition[G] = nsDef match {
+ case NamespaceDefinition0(None, _, Some(name), _, maybeBody, _) => new CPPNamespaceDefinition(convert(name), maybeBody.toSeq.flatMap(convert(_)))
+ case x => ??(x)
+ }
+
// Not supporting attribute specifiers and virtual specifiers
def convert(implicit funcDef: FunctionDefinitionContext): CPPFunctionDefinition[G] = funcDef match {
case FunctionDefinition0(maybeContract, None, maybeDeclSpecs, declarator, None, body) =>
@@ -260,8 +268,8 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
}
def convert(implicit expr: PrependExpressionContext): Expr[G] = expr match {
- case PrependExpression0(left, PrependOp0(specOp), right) => convert(expr, specOp, convert(left), convert(right))
- case PrependExpression1(inner) => convert(inner)
+ case PrependExpression0(inner) => convert(inner)
+ case PrependExpression1(left, PrependOp0(specOp), right) => convert(expr, specOp, convert(left), convert(right))
}
// Do not support cast expressions
@@ -356,7 +364,7 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
case PrimaryExpression1(literals) if literals.length == 1 => convert(literals.head)
case PrimaryExpression2(_) => AmbiguousThis()
case PrimaryExpression3(_, inner, _) => convert(inner)
- case PrimaryExpression4(inner) => local(expr, convert(inner).name)
+ case PrimaryExpression4(inner) => CPPLocal(convert(inner).nestedName)(blame(expr))(origin(expr))
case x => ??(x)
}
@@ -371,7 +379,7 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
case Literal6(_) => ??(literal)
}
- def convert(implicit idExpr: IdExpressionContext): CPPName[G] = idExpr match {
+ def convert(implicit idExpr: IdExpressionContext): CPPTypedefName[G] = idExpr match {
case IdExpression0(id) => convert(id)
case IdExpression1(id) => convert(id)
}
@@ -470,9 +478,8 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
case x => ??(x)
}
- // Do not support types: template, char16_t, char32_t, wchar_t, auto, decltype()
+ // Do not support types: template, char16_t, char32_t, wchar_t, auto, decltype(), and combination of namespace and typename
def convert(implicit typeSpec: SimpleTypeSpecifierContext): Seq[CPPTypeSpecifier[G]] = typeSpec match {
- case SimpleTypeSpecifier0(Some(nestedNameSpec), typeName) => convert(nestedNameSpec) :+ convert(typeName)
case SimpleTypeSpecifier0(None, typeName) => Seq(convert(typeName))
case SimpleTypeSpecifier2(signedness) => Seq(convert(signedness))
case SimpleTypeSpecifier3(Some(signedness), typeLengthMods) => Seq(convert(signedness)) ++ typeLengthMods.map(convert(_))
@@ -500,24 +507,26 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
case SimpleTypeLengthModifier1(_) => new CPPLong[G]()
}
- // Do not support template, namespaces or decltypes
- def convert(implicit nestedNameSpec: NestedNameSpecifierContext): Seq[CPPTypeSpecifier[G]] = nestedNameSpec match {
- case value: NestedNameSpecifier0Context =>
- if (value.theTypeName() != null) {
- Seq(convert(value.theTypeName()))
- } else if (value.namespaceName() != null) {
- ??(value.namespaceName())
- } else if (value.decltypeSpecifier() != null) {
- ??(value.decltypeSpecifier())
- } else {
- ??(value)
+ // Do not support template or decltypes, or a typename as identifier in the nestedname
+ def convert(implicit nestedNameSpec: NestedNameSpecifierContext): CPPTypedefName[G] = nestedNameSpec match {
+ case NestedNameSpecifier0(theTypeName, _) =>
+ convert(theTypeName) match {
+ case name@CPPTypedefName(_) => name
+ case x => ??(theTypeName)
}
- case value: NestedNameSpecifier1Context =>
- if (value.simpleTemplateId() != null) {
- ??(value.simpleTemplateId())
- } else {
- convert(value.nestedNameSpecifier()) :+ CPPTypedefName(convert(value.clangppIdentifier()))
+ case NestedNameSpecifier1(namespaceName, _) => convert(namespaceName)
+ case NestedNameSpecifier3(_) => CPPTypedefName(Seq())
+ case NestedNameSpecifier4(inner, id, _) =>
+ convert(inner) match {
+ case CPPTypedefName(nestedName) => CPPTypedefName(nestedName :+ convert(id))
+ case _ => ??(inner)
}
+ case x => ??(x)
+ }
+
+ def convert(implicit namespaceName: NamespaceNameContext): CPPTypedefName[G] = namespaceName match {
+ case NamespaceName0(OriginalNamespaceName0(id)) => CPPTypedefName(Seq(convert(id)))
+ case NamespaceName1(NamespaceAlias0(id)) => CPPTypedefName(Seq(convert(id)))
}
// Do not support enum-names, typedef-names and template-names
@@ -528,7 +537,7 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
// Do not support template-names
def convert(implicit className: ClassNameContext): CPPTypeSpecifier[G] = className match {
- case value: ClassName0Context => CPPTypedefName(convert(value.clangppIdentifier()))
+ case ClassName0(name) => CPPTypedefName(Seq(convert(name)))
case x => ??(x)
}
@@ -613,19 +622,20 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
// Do not support if spread operator '...' is used
def convert(implicit declaratorId: DeclaratoridContext): CPPDeclarator[G] = declaratorId match {
- case Declaratorid0(None, idExpr) => convert(idExpr)
+ case Declaratorid0(None, idExpr) => CPPName(convert(idExpr).nestedName.mkString("::"))
case x => ??(x)
}
// Do not support operatorFunctionId, conversionFunctionId, literalOperatorId, templateId, and things starting with a tilde
- def convert(implicit unqualifiedId: UnqualifiedIdContext): CPPName[G] = unqualifiedId match {
- case UnqualifiedId0(clangppId) => CPPName(convert(clangppId))
+ def convert(implicit unqualifiedId: UnqualifiedIdContext): CPPTypedefName[G] = unqualifiedId match {
+ case UnqualifiedId0(clangppId) => CPPTypedefName(Seq(convert(clangppId)))
case x => ??(x)
}
- // Do not support template or nestedNameSpecifier
- def convert(implicit qualifiedId: QualifiedIdContext): CPPName[G] = qualifiedId match {
- case QualifiedId0(nestedNameSpec, _, _) => ??(nestedNameSpec)
+ // Do not support template
+ def convert(implicit qualifiedId: QualifiedIdContext): CPPTypedefName[G] = qualifiedId match {
+ case QualifiedId0(nestedNameSpec, None, id) => CPPTypedefName(convert(nestedNameSpec).nestedName ++ convert(id).nestedName)
+ case x => ??(x)
}
def convert(implicit id: ClangppIdentifierContext): String = id match {
@@ -657,7 +667,7 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
}
def local(ctx: ParserRuleContext, name: String): Expr[G] =
- CPPLocal(name)(blame(ctx))(origin(ctx))
+ CPPLocal(Seq(name))(blame(ctx))(origin(ctx))
def convert(decl: LangGlobalDeclContext): Seq[GlobalDeclaration[G]] = decl match {
case LangGlobalDecl0(decl) => convert(decl)
diff --git a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
index 54103a7d16..f00e6b16d3 100644
--- a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
+++ b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
@@ -38,6 +38,7 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
type Post = Rewritten[Pre]
implicit val implicitRewriter: AbstractRewriter[Pre, Post] = rw
+ val namespace: ScopedStack[CPPNamespaceDefinition[Pre]] = ScopedStack()
val cppFunctionSuccessor: SuccessionMap[CPPFunctionDefinition[Pre], Procedure[Post]] = SuccessionMap()
val cppFunctionDeclSuccessor: SuccessionMap[(CPPGlobalDeclaration[Pre], Int), Procedure[Post]] = SuccessionMap()
val cppNameSuccessor: SuccessionMap[CPPNameTarget[Pre], Variable[Post]] = SuccessionMap()
@@ -163,6 +164,14 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
}
}
+ def rewriteNamespaceDef(ns: CPPNamespaceDefinition[Pre]): Unit = {
+ ns.drop()
+ namespace.having(ns) {
+ // Do not enter a scope, so classes of the namespace are declared to the program.
+ ns.declarations.foreach(rw.dispatch)
+ }
+ }
+
def result(ref: RefCPPFunctionDefinition[Pre])(implicit o: Origin): Expr[Post] =
Result[Post](cppFunctionSuccessor.ref(ref.decl))
@@ -199,7 +208,7 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
val CPPInvocation(applicable, args, givenMap, yields) = inv
implicit val o: Origin = inv.o
inv.ref.get match {
- case RefFunction(decl) =>0
+ case RefFunction(decl) =>
FunctionInvocation[Post](rw.succ(decl), args.map(rw.dispatch), Nil,
givenMap.map { case (Ref(v), e) => (rw.succ(v), rw.dispatch(e)) },
yields.map { case (e, Ref(v)) => (rw.dispatch(e), rw.succ(v)) })(inv.blame)
diff --git a/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala b/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala
index 309708b9c3..396fcb6e15 100644
--- a/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala
+++ b/src/rewrite/vct/rewrite/lang/LangSpecificToCol.scala
@@ -9,10 +9,7 @@ import vct.col.origin._
import vct.col.resolve.ctx._
import vct.col.resolve.lang.Java
import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder}
-import vct.col.resolve._
-import vct.col.rewrite.{Generation, Rewriter, RewriterBuilder, RewriterBuilderArg}
import vct.result.VerificationError.UserError
-import vct.col.util.SuccessionMap
case object LangSpecificToCol extends RewriterBuilder {
override def key: String = "langSpecific"
@@ -72,6 +69,7 @@ case class LangSpecificToCol[Pre <: Generation]() extends Rewriter[Pre] with Laz
case unit: CPPTranslationUnit[Pre] => cpp.rewriteUnit(unit)
case cppParam: CPPParam[Pre] => cpp.rewriteParam(cppParam)
case func: CPPFunctionDefinition[Pre] => cpp.rewriteFunctionDef(func)
+ case ns: CPPNamespaceDefinition[Pre] => cpp.rewriteNamespaceDef(ns)
case decl: CPPGlobalDeclaration[Pre] => cpp.rewriteGlobalDecl(decl)
case decl: CPPLocalDeclaration[Pre] => ???
diff --git a/test/main/vct/test/integration/examples/CPPSpec.scala b/test/main/vct/test/integration/examples/CPPSpec.scala
index 562240568d..c51275bf4a 100644
--- a/test/main/vct/test/integration/examples/CPPSpec.scala
+++ b/test/main/vct/test/integration/examples/CPPSpec.scala
@@ -3,21 +3,23 @@ package vct.test.integration.examples
import vct.test.integration.helper.VercorsSpec
class CPPSpec extends VercorsSpec {
- vercors should verify using silicon example("concepts/cpp/Arrays.cpp")
- vercors should verify using silicon example("concepts/cpp/Conditionals.cpp")
- vercors should verify using silicon example("concepts/cpp/Loops.cpp")
- vercors should verify using silicon example("concepts/cpp/Operators.cpp")
- vercors should verify using silicon examples("concepts/cpp/Pointers.cpp")
- vercors should verify using silicon examples("concepts/cpp/Scoping.cpp")
- vercors should verify using silicon examples("concepts/cpp/Types.cpp")
+ vercors should verify using silicon example "concepts/cpp/Arrays.cpp"
+ vercors should verify using silicon example "concepts/cpp/Conditionals.cpp"
+ vercors should verify using silicon example "concepts/cpp/Loops.cpp"
+ vercors should verify using silicon example "concepts/cpp/Namespaces.cpp"
+ vercors should error withCode "noSuchName" example "concepts/cpp/NamespacesDoNotFindWithoutNamespacePrefix.cpp"
+ vercors should verify using silicon example "concepts/cpp/Operators.cpp"
+ vercors should verify using silicon example "concepts/cpp/Pointers.cpp"
+ vercors should verify using silicon example "concepts/cpp/Scoping.cpp"
+ vercors should verify using silicon example "concepts/cpp/Types.cpp"
- vercors should verify using silicon examples("concepts/cpp/methods/AbstractMethod.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/ContextAndContextEverywhere.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/Decreases.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/GhostMethodsAndVariables.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/GhostParamsAndResults.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/InlineFunction.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/Permissions.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/Predicates.cpp")
- vercors should verify using silicon examples("concepts/cpp/methods/PureGhostMethod.cpp")
+ vercors should verify using silicon example "concepts/cpp/methods/AbstractMethod.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/ContextAndContextEverywhere.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/Decreases.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/GhostMethodsAndVariables.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/GhostParamsAndResults.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/InlineFunction.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/Permissions.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/Predicates.cpp"
+ vercors should verify using silicon example "concepts/cpp/methods/PureGhostMethod.cpp"
}
\ No newline at end of file
From f629d6f124887a785ed3702002bef8ce147afc08 Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Thu, 6 Jul 2023 09:51:11 +0200
Subject: [PATCH 08/11] Minor bugfixes and added support for using methods from
certain sycl classes
---
examples/concepts/cpp/Arrays.cpp | 9 ---
examples/concepts/cpp/Loops.cpp | 17 +-----
examples/concepts/cpp/Scoping.cpp | 2 +-
.../cpp/methods/GhostMethodsAndVariables.cpp | 1 +
.../cpp/methods/GhostParamsAndResults.cpp | 7 ++-
examples/concepts/sycl/MethodResolving.cpp | 8 +++
res/universal/res/cpp/stdbool.h | 2 +-
res/universal/res/cpp/sycl/sycl.hpp | 8 +++
src/col/vct/col/ast/Node.scala | 6 +-
.../declaration/global/HeapVariableImpl.scala | 2 +-
.../declaration/global/ProcedureImpl.scala | 2 +-
.../ast/family/coercion/CoercionImpl.scala | 4 +-
.../vct/col/ast/lang/CPPInvocationImpl.scala | 3 +
.../ast/lang/CPPLocalDeclarationImpl.scala | 2 +-
src/col/vct/col/ast/lang/CPPLocalImpl.scala | 2 +-
.../ast/lang/CPPNamespaceDefinitionImpl.scala | 4 +-
.../vct/col/ast/lang/CPPTypedefNameImpl.scala | 7 ++-
src/col/vct/col/ast/lang/SYCLQueueImpl.scala | 8 +++
.../ast/statement/terminal/LabelImpl.scala | 4 +-
src/col/vct/col/ast/type/TBoolImpl.scala | 4 +-
src/col/vct/col/ast/type/TSYCLQueueImpl.scala | 8 +++
src/col/vct/col/resolve/Resolve.scala | 4 +-
src/col/vct/col/resolve/lang/CPP.scala | 55 ++++++++++++++-----
.../vct/col/typerules/CoercingRewriter.scala | 3 +
src/parsers/antlr4/LangCPPLexer.g4 | 3 +
src/parsers/antlr4/LangCPPParser.g4 | 1 +
.../vct/parsers/transform/CPPToCol.scala | 32 ++++++-----
.../ResolveExpressionSideEffects.scala | 1 +
src/rewrite/vct/rewrite/adt/ImportADT.scala | 3 +-
.../vct/rewrite/lang/LangCPPToCol.scala | 2 +-
.../viper/api/transform/ColToSilver.scala | 3 +-
.../test/integration/examples/SYCLSpec.scala | 7 +++
32 files changed, 150 insertions(+), 74 deletions(-)
create mode 100644 examples/concepts/sycl/MethodResolving.cpp
create mode 100644 res/universal/res/cpp/sycl/sycl.hpp
create mode 100644 src/col/vct/col/ast/lang/SYCLQueueImpl.scala
create mode 100644 src/col/vct/col/ast/type/TSYCLQueueImpl.scala
create mode 100644 test/main/vct/test/integration/examples/SYCLSpec.scala
diff --git a/examples/concepts/cpp/Arrays.cpp b/examples/concepts/cpp/Arrays.cpp
index a5c3696b16..2ae61a1f12 100644
--- a/examples/concepts/cpp/Arrays.cpp
+++ b/examples/concepts/cpp/Arrays.cpp
@@ -3,15 +3,6 @@
//:: tools silicon
//:: verdict Pass
-void test() {
- // Not supported atm
-// int arr[10];
- // assert \array(arr, 10);
- // assert \pointer(arr, 10, write);
-// arr[5] = 8;
- // assert arr[5] == 8;
-}
-
//@ requires a != nullptr && size > 0;
//@ context \pointer(a, size, read);
//@ requires (\forall int i = 0 .. size; {: a[i] :} == 0);
diff --git a/examples/concepts/cpp/Loops.cpp b/examples/concepts/cpp/Loops.cpp
index 21470b7192..f8de6bae5b 100644
--- a/examples/concepts/cpp/Loops.cpp
+++ b/examples/concepts/cpp/Loops.cpp
@@ -13,25 +13,14 @@ void whileLoop() {
}
}
-// context_everywhere \pointer(arr, size + 1, read); -- does work for the foralll statement
+//@ context_everywhere size >= 0;
//@ context_everywhere \pointer(arr, size, read);
void forArrayLoop(bool arr[], int size) {
bool sum = true;
+
//@ loop_invariant i >= 0 && i <= size;
- //@ loop_invariant sum == (\forall int j; j >= 0 && j < i; arr[i]);
+ //@ loop_invariant sum == (\forall int j; j >= 0 && j < i; arr[j]);
for(int i = 0; i < size; i++) {
sum = sum && arr[i];
}
}
-
-void forLoop() {
- int numLoops = 10;
- int sum = 0;
- //@ loop_invariant i >= 0 && i <= numLoops;
- //@ decreases numLoops;
- //@ loop_invariant sum == i * (i+1) / 2;
- for(int i = 0; i < numLoops; i++) {
- numLoops--;
- sum += (i + 1);
- }
-}
diff --git a/examples/concepts/cpp/Scoping.cpp b/examples/concepts/cpp/Scoping.cpp
index 93a0bc3e8e..00afe14a01 100644
--- a/examples/concepts/cpp/Scoping.cpp
+++ b/examples/concepts/cpp/Scoping.cpp
@@ -6,7 +6,7 @@ void test() {
int a = 10;
int b = 10;
- { // CompoundStatement { statements }
+ {
a = 20;
int b = 20;
//@ assert a == 20;
diff --git a/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp b/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp
index d248c2e7a0..8bf939a6e8 100644
--- a/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp
+++ b/examples/concepts/cpp/methods/GhostMethodsAndVariables.cpp
@@ -10,6 +10,7 @@
}
*/
+//@ context_everywhere size >= 0;
//@ context_everywhere \pointer(a, size, read);
int sum(int a[], int size) {
//@ ghost bool positive = true;
diff --git a/examples/concepts/cpp/methods/GhostParamsAndResults.cpp b/examples/concepts/cpp/methods/GhostParamsAndResults.cpp
index 89c7456435..b68ef70b7a 100644
--- a/examples/concepts/cpp/methods/GhostParamsAndResults.cpp
+++ b/examples/concepts/cpp/methods/GhostParamsAndResults.cpp
@@ -7,15 +7,16 @@
given int min;
yields bool all_ge_min;
requires min >= 0;
- ensures all_ge_min ==> \result >= min * 2;
+ ensures all_ge_min == (a >= min && b >= min);
*/
int add(int a, int b) {
//@ ghost all_ge_min = a >= min && b >= min;
return a + b;
}
-int caller(int a, int b) {
+int caller() {
//@ ghost bool items_ge_5;
- int result = add(a, b) /*@ given { min = 5 } */ /*@ yields { items_ge_5 = all_ge_min } */ ;
+ int result = add(10, 12) /*@ given { min = 5 } */ /*@ yields { items_ge_5 = all_ge_min } */ ;
+ //@ assert items_ge_5;
return result;
}
diff --git a/examples/concepts/sycl/MethodResolving.cpp b/examples/concepts/sycl/MethodResolving.cpp
new file mode 100644
index 0000000000..7d50f3c942
--- /dev/null
+++ b/examples/concepts/sycl/MethodResolving.cpp
@@ -0,0 +1,8 @@
+#include
+
+void test2() {
+ sycl::queue queue;
+ queue.submit(5);
+ queue.submit(33);
+ int x = queue.test2();
+}
\ No newline at end of file
diff --git a/res/universal/res/cpp/stdbool.h b/res/universal/res/cpp/stdbool.h
index c82a3f85b6..930ddeb7c6 100644
--- a/res/universal/res/cpp/stdbool.h
+++ b/res/universal/res/cpp/stdbool.h
@@ -1,3 +1,3 @@
#define bool _Bool
#define true 1
-#define false 0
+#define false 0
\ No newline at end of file
diff --git a/res/universal/res/cpp/sycl/sycl.hpp b/res/universal/res/cpp/sycl/sycl.hpp
new file mode 100644
index 0000000000..68365606b3
--- /dev/null
+++ b/res/universal/res/cpp/sycl/sycl.hpp
@@ -0,0 +1,8 @@
+namespace VERCORS {
+ namespace sycl {
+ namespace queue {
+ int VERCORS__submit(int kernel);
+ int VERCORS__test2();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/Node.scala b/src/col/vct/col/ast/Node.scala
index 8266d5e830..65e41d8450 100644
--- a/src/col/vct/col/ast/Node.scala
+++ b/src/col/vct/col/ast/Node.scala
@@ -970,9 +970,11 @@ final case class CPPLong[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G
final case class CPPSigned[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPSignedImpl[G]
final case class CPPUnsigned[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPUnsignedImpl[G]
final case class CPPBool[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPBoolImpl[G]
-final case class CPPTypedefName[G](nestedName: Seq[String])(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPTypedefNameImpl[G] {
+final case class CPPTypedefName[G](var nestedName: String)(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPTypedefNameImpl[G] {
var ref: Option[CPPTypeNameTarget[G]] = None
}
+final case class SYCLQueue[G]()(implicit val o: Origin) extends CPPTypeSpecifier[G] with SYCLQueueImpl[G]
+final case class TSYCLQueue[G]()(implicit val o: Origin) extends Type[G] with TSYCLQueueImpl[G]
final case class CPPSpecificationType[G](t: Type[G])(implicit val o: Origin) extends CPPTypeSpecifier[G] with CPPSpecificationTypeImpl[G]
@@ -1007,7 +1009,7 @@ sealed trait CPPStatement[G] extends Statement[G] with CPPStatementImpl[G]
final case class CPPDeclarationStatement[G](decl: CPPLocalDeclaration[G])(implicit val o: Origin) extends CPPStatement[G] with CPPDeclarationStatementImpl[G]
sealed trait CPPExpr[G] extends Expr[G] with CPPExprImpl[G]
-final case class CPPLocal[G](name: Seq[String])(val blame: Blame[DerefInsufficientPermission])(implicit val o: Origin) extends CPPExpr[G] with CPPLocalImpl[G] {
+final case class CPPLocal[G](name: String)(val blame: Blame[DerefInsufficientPermission])(implicit val o: Origin) extends CPPExpr[G] with CPPLocalImpl[G] {
var ref: Option[CPPNameTarget[G]] = None
}
final case class CPPInvocation[G](applicable: Expr[G], args: Seq[Expr[G]], givenArgs: Seq[(Ref[G, Variable[G]], Expr[G])], yields: Seq[(Expr[G], Ref[G, Variable[G]])])(val blame: Blame[FrontendInvocationError])(implicit val o: Origin) extends CPPExpr[G] with CPPInvocationImpl[G] {
diff --git a/src/col/vct/col/ast/declaration/global/HeapVariableImpl.scala b/src/col/vct/col/ast/declaration/global/HeapVariableImpl.scala
index f0170e5b7a..d203665195 100644
--- a/src/col/vct/col/ast/declaration/global/HeapVariableImpl.scala
+++ b/src/col/vct/col/ast/declaration/global/HeapVariableImpl.scala
@@ -5,7 +5,7 @@ import vct.col.print._
trait HeapVariableImpl[G] { this: HeapVariable[G] =>
override def layout(implicit ctx: Ctx): Doc = ctx.syntax match {
- case Ctx.C | Ctx.Cuda | Ctx.OpenCL =>
+ case Ctx.C | Ctx.Cuda | Ctx.OpenCL | Ctx.CPP =>
val (spec, decl) = t.layoutSplitDeclarator
spec <+> decl <> ctx.name(this) <> ";"
case _ =>
diff --git a/src/col/vct/col/ast/declaration/global/ProcedureImpl.scala b/src/col/vct/col/ast/declaration/global/ProcedureImpl.scala
index 4e45e31aeb..f6cc4e3f51 100644
--- a/src/col/vct/col/ast/declaration/global/ProcedureImpl.scala
+++ b/src/col/vct/col/ast/declaration/global/ProcedureImpl.scala
@@ -35,7 +35,7 @@ trait ProcedureImpl[G] { this: Procedure[G] =>
override def layout(implicit ctx: Ctx): Doc = ctx.syntax match {
case Ctx.Silver => layoutSilver
- case Ctx.C | Ctx.Cuda | Ctx.OpenCL => layoutC
+ case Ctx.C | Ctx.Cuda | Ctx.OpenCL | Ctx.CPP => layoutC
case Ctx.PVL | Ctx.Java => Doc.spec(Show.lazily(layoutSpec(_)))
}
}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/family/coercion/CoercionImpl.scala b/src/col/vct/col/ast/family/coercion/CoercionImpl.scala
index c811820f2c..a12fa7ec67 100644
--- a/src/col/vct/col/ast/family/coercion/CoercionImpl.scala
+++ b/src/col/vct/col/ast/family/coercion/CoercionImpl.scala
@@ -1,6 +1,6 @@
package vct.col.ast.family.coercion
-import vct.col.ast.{CoerceBoolResource, CoerceBoundIntFrac, CoerceBoundIntZFrac, CoerceCPrimitiveToCol, CoerceClassAnyClass, CoerceColToCPrimitive, CoerceFloatRat, CoerceFracZFrac, CoerceIdentity, CoerceIncreasePrecision, CoerceIntRat, CoerceJavaClassAnyClass, CoerceJavaSupports, CoerceJoinUnion, CoerceMapBag, CoerceMapEither, CoerceMapMap, CoerceMapMatrix, CoerceMapOption, CoerceMapSeq, CoerceMapSet, CoerceMapTuple, CoerceMapType, CoerceNothingSomething, CoerceNullAnyClass, CoerceNullArray, CoerceNullClass, CoerceNullJavaClass, CoerceNullPointer, CoerceNullRef, CoerceRatZFrac, CoerceSelectUnion, CoerceSomethingAny, CoerceSupports, CoerceUnboundInt, CoerceWidenBound, CoerceZFracFrac, CoerceZFracRat, Coercion, CoercionSequence, Type}
+import vct.col.ast.{CoerceBoolResource, CoerceBoundIntFrac, CoerceBoundIntZFrac, CoerceCPrimitiveToCol, CoerceCPPPrimitiveToCol, CoerceClassAnyClass, CoerceColToCPrimitive, CoerceColToCPPPrimitive, CoerceFloatRat, CoerceFracZFrac, CoerceIdentity, CoerceIncreasePrecision, CoerceIntRat, CoerceJavaClassAnyClass, CoerceJavaSupports, CoerceJoinUnion, CoerceMapBag, CoerceMapEither, CoerceMapMap, CoerceMapMatrix, CoerceMapOption, CoerceMapSeq, CoerceMapSet, CoerceMapTuple, CoerceMapType, CoerceNothingSomething, CoerceNullAnyClass, CoerceNullArray, CoerceNullClass, CoerceNullJavaClass, CoerceNullPointer, CoerceNullRef, CoerceRatZFrac, CoerceSelectUnion, CoerceSomethingAny, CoerceSupports, CoerceUnboundInt, CoerceWidenBound, CoerceZFracFrac, CoerceZFracRat, Coercion, CoercionSequence, Type}
trait CoercionImpl[G] { this: Coercion[G] =>
def target: Type[G]
@@ -34,6 +34,8 @@ trait CoercionImpl[G] { this: Coercion[G] =>
case CoerceJavaClassAnyClass(_) => true
case CoerceCPrimitiveToCol(_, _) => true
case CoerceColToCPrimitive(_, _) => true
+ case CoerceCPPPrimitiveToCol(_, _) => true
+ case CoerceColToCPPPrimitive(_, _) => true
case CoerceMapOption(inner, _, _) => inner.isPromoting
case CoerceMapTuple(inner, _, _) => inner.forall(_.isPromoting)
case CoerceMapEither(inner, _, _) => inner._1.isPromoting && inner._2.isPromoting
diff --git a/src/col/vct/col/ast/lang/CPPInvocationImpl.scala b/src/col/vct/col/ast/lang/CPPInvocationImpl.scala
index e08c12b319..28938ba191 100644
--- a/src/col/vct/col/ast/lang/CPPInvocationImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPInvocationImpl.scala
@@ -19,6 +19,9 @@ trait CPPInvocationImpl[G] { this: CPPInvocation[G] =>
case RefInstanceMethod(decl) => decl.returnType
case RefInstanceFunction(decl) => decl.returnType
case RefInstancePredicate(decl) => decl.returnType
+ case BuiltinInstanceMethod(f) => applicable match {
+ case _ => throw Unreachable("BuiltinInstanceMethod resolution of CPPInvocation cannot invoke anything.")
+ }
}
override def precedence: Int = Precedence.POSTFIX
diff --git a/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala b/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala
index 30860d3502..66a52cbf5f 100644
--- a/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPLocalDeclarationImpl.scala
@@ -4,5 +4,5 @@ import vct.col.ast.CPPLocalDeclaration
import vct.col.print.{Ctx, Doc}
trait CPPLocalDeclarationImpl[G] { this: CPPLocalDeclaration[G] =>
- override def layout(implicit ctx: Ctx): Doc = decl.show <> ";"
+ override def layout(implicit ctx: Ctx): Doc = decl.show
}
diff --git a/src/col/vct/col/ast/lang/CPPLocalImpl.scala b/src/col/vct/col/ast/lang/CPPLocalImpl.scala
index cbb11f208c..5246f352dd 100644
--- a/src/col/vct/col/ast/lang/CPPLocalImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPLocalImpl.scala
@@ -28,5 +28,5 @@ trait CPPLocalImpl[G] { this: CPPLocal[G] =>
case target: SpecInvocationTarget[G] => Types.notAValue(target)
}
- override def layout(implicit ctx: Ctx): Doc = Text(name.mkString("::"))
+ override def layout(implicit ctx: Ctx): Doc = Text(name)
}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala b/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala
index e9403c772c..afb2ebf8df 100644
--- a/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPNamespaceDefinitionImpl.scala
@@ -7,7 +7,7 @@ trait CPPNamespaceDefinitionImpl[G] { this: CPPNamespaceDefinition[G] =>
override def layout(implicit ctx: Ctx): Doc =
Doc.stack(Seq(
- Text("namespace") <+> Text(name),
- Doc.stack(declarations),
+ Text("namespace") <+> Text(name) <+>
+ "{" <>> Doc.stack(declarations) <+/> "}"
))
}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala b/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
index f504f0459b..d800538716 100644
--- a/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
+++ b/src/col/vct/col/ast/lang/CPPTypedefNameImpl.scala
@@ -4,5 +4,10 @@ import vct.col.ast.CPPTypedefName
import vct.col.print.{Ctx, Doc, Text}
trait CPPTypedefNameImpl[G] { this: CPPTypedefName[G] =>
- override def layout(implicit ctx: Ctx): Doc = Text(nestedName.mkString("::"))
+ override def layout(implicit ctx: Ctx): Doc = Text(nestedName)
+
+ def appendName(postfix: String): CPPTypedefName[G] = {
+ nestedName ++= postfix
+ this
+ }
}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/lang/SYCLQueueImpl.scala b/src/col/vct/col/ast/lang/SYCLQueueImpl.scala
new file mode 100644
index 0000000000..edd7f3044a
--- /dev/null
+++ b/src/col/vct/col/ast/lang/SYCLQueueImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.lang
+
+import vct.col.ast.SYCLQueue
+import vct.col.print.{Ctx, Doc, Text}
+
+trait SYCLQueueImpl[G] { this: SYCLQueue[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("sycl::queue")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/statement/terminal/LabelImpl.scala b/src/col/vct/col/ast/statement/terminal/LabelImpl.scala
index 2450239e19..2bb7699518 100644
--- a/src/col/vct/col/ast/statement/terminal/LabelImpl.scala
+++ b/src/col/vct/col/ast/statement/terminal/LabelImpl.scala
@@ -8,14 +8,14 @@ trait LabelImpl[G] { this: Label[G] =>
case Ctx.PVL => Seq(layoutLabel) ++ stat.blockElementsForLayout
case Ctx.Silver => Seq(layoutLabel) ++ stat.blockElementsForLayout
case Ctx.Java => Seq(this)
- case Ctx.C | Ctx.Cuda | Ctx.OpenCL => Seq(layoutLabel) ++ stat.blockElementsForLayout
+ case Ctx.C | Ctx.Cuda | Ctx.OpenCL | Ctx.CPP => Seq(layoutLabel) ++ stat.blockElementsForLayout
}
def layoutLabel(implicit ctx: Ctx): Doc = ctx.syntax match {
case Ctx.PVL => Text("label") <+> ctx.name(decl) <> ";"
case Ctx.Silver => Text("label") <+> ctx.name(decl)
case Ctx.Java => Text(ctx.name(decl)) <> ":"
- case Ctx.C | Ctx.Cuda | Ctx.OpenCL => Text(ctx.name(decl)) <> ":"
+ case Ctx.C | Ctx.Cuda | Ctx.OpenCL | Ctx.CPP => Text(ctx.name(decl)) <> ":"
}
override def layout(implicit ctx: Ctx): Doc =
diff --git a/src/col/vct/col/ast/type/TBoolImpl.scala b/src/col/vct/col/ast/type/TBoolImpl.scala
index 38b24f8a1d..3b44c268a2 100644
--- a/src/col/vct/col/ast/type/TBoolImpl.scala
+++ b/src/col/vct/col/ast/type/TBoolImpl.scala
@@ -1,13 +1,13 @@
package vct.col.ast.`type`
import vct.col.ast.TBool
-import vct.col.print.{Ctx, Doc, Group, Text}
+import vct.col.print.{Ctx, Doc, Text}
trait TBoolImpl[G] { this: TBool[G] =>
override def layout(implicit ctx: Ctx): Doc = ctx.syntax match {
case Ctx.PVL => Text("boolean")
case Ctx.Silver => Text("Bool")
case Ctx.Java => Text("boolean")
- case Ctx.C | Ctx.Cuda | Ctx.OpenCL => Text("bool")
+ case Ctx.C | Ctx.Cuda | Ctx.OpenCL | Ctx.CPP => Text("bool")
}
}
\ No newline at end of file
diff --git a/src/col/vct/col/ast/type/TSYCLQueueImpl.scala b/src/col/vct/col/ast/type/TSYCLQueueImpl.scala
new file mode 100644
index 0000000000..db3a3467c6
--- /dev/null
+++ b/src/col/vct/col/ast/type/TSYCLQueueImpl.scala
@@ -0,0 +1,8 @@
+package vct.col.ast.`type`
+
+import vct.col.ast.TSYCLQueue
+import vct.col.print.{Ctx, Doc, Text}
+
+trait TSYCLQueueImpl[G] { this: TSYCLQueue[G] =>
+ override def layout(implicit ctx: Ctx): Doc = Text("sycl::queue")
+}
\ No newline at end of file
diff --git a/src/col/vct/col/resolve/Resolve.scala b/src/col/vct/col/resolve/Resolve.scala
index 593146ae9d..4c3d528245 100644
--- a/src/col/vct/col/resolve/Resolve.scala
+++ b/src/col/vct/col/resolve/Resolve.scala
@@ -129,7 +129,7 @@ case object ResolveTypes {
))
case t@CPPTypedefName(nestedName) =>
t.ref = Some(CPP.findCPPTypeName(nestedName, ctx).getOrElse(
- throw NoSuchNameError("class, struct, or namespace", nestedName.mkString("::"), t)
+ throw NoSuchNameError("class, struct, or namespace", nestedName, t)
))
case t @ PVLNamedType(name, typeArgs) =>
t.ref = Some(PVL.findTypeName(name, ctx).getOrElse(
@@ -350,7 +350,7 @@ case object ResolveReferences extends LazyLogging {
case local@CLocal(name) =>
local.ref = Some(C.findCName(name, ctx).getOrElse(throw NoSuchNameError("local", name, local)))
case local@CPPLocal(name) =>
- local.ref = Some(CPP.findCPPName(name, ctx).getOrElse(throw NoSuchNameError("local", name.mkString("::"), local)))
+ local.ref = Some(CPP.findCPPName(name, ctx).getOrElse(throw NoSuchNameError("local", name, local)))
case local @ JavaLocal(name) =>
val start: Option[JavaNameTarget[G]] = if (ctx.javaBipGuardsEnabled) {
Java.findJavaBipGuard(ctx, name).map(RefJavaBipGuard(_))
diff --git a/src/col/vct/col/resolve/lang/CPP.scala b/src/col/vct/col/resolve/lang/CPP.scala
index 0952ca664f..e121108f6c 100644
--- a/src/col/vct/col/resolve/lang/CPP.scala
+++ b/src/col/vct/col/resolve/lang/CPP.scala
@@ -65,6 +65,7 @@ case object CPP {
case t if CPP.NUMBER_LIKE_SPECIFIERS.contains(t) => TInt()
case Seq(CPPSpecificationType(t@TFloat(_, _))) => t
case Seq(CPPBool()) => TBool()
+ case Seq(SYCLQueue()) => TSYCLQueue()
case Seq(defn@CPPTypedefName(_)) => Types.notAValue(defn.ref.get)
case Seq(CPPSpecificationType(typ)) => typ
case spec +: _ => throw CPPTypeNotSupported(context.orElse(Some(spec)))
@@ -80,44 +81,70 @@ case object CPP {
def paramsFromDeclarator[G](declarator: CPPDeclarator[G]): Seq[CPPParam[G]] =
getDeclaratorInfo(declarator).params.get
- def findCPPTypeName[G](names: Seq[String], ctx: TypeResolutionContext[G]): Option[CPPTypeNameTarget[G]] =
+ def findCPPTypeName[G](name: String, ctx: TypeResolutionContext[G]): Option[CPPTypeNameTarget[G]] =
ctx.stack.flatten.collectFirst {
- case target: CPPTypeNameTarget[G] if target.name == names.mkString("::") => target
+ case target: CPPTypeNameTarget[G] if target.name == name => target
}
- def findCPPName[G](name: Seq[String], ctx: ReferenceResolutionContext[G]): Option[CPPNameTarget[G]] = {
- if (name.length == 1) {
+ def replacePotentialSYCLClassInstance[G](name: String, ctx: ReferenceResolutionContext[G]): String = {
+ if (name.contains('.') && name.count(x => x == '.') == 1) {
+ // Class method, replace with SYCL equivalent
+ val classVarName = name.split('.').head
+ val methodName = name.split('.').last
+
+ // Get type (so class) of variable (instance)
+ val classTarget = ctx.stack.flatten.collectFirst {
+ case target: CPPNameTarget[G] if target.name == classVarName => target
+ }
+ val className = classTarget match {
+ case Some(RefCPPLocalDeclaration(decl, _)) => Some(getPrimitiveType(decl.decl.specs))
+ case Some(RefCPPGlobalDeclaration(decl, _)) => Some(getPrimitiveType(decl.decl.specs))
+ case _ => None
+ }
+ // Replace class reference name to a namespace name
+ if (className.isDefined) {
+ return name.replace(classVarName + ".", "VERCORS::" + className.get.toString + "::VERCORS__")
+ }
+ }
+ name
+ }
+
+ def findCPPName[G](name: String, ctx: ReferenceResolutionContext[G]): Option[CPPNameTarget[G]] = {
+ val targetName: String = replacePotentialSYCLClassInstance(name, ctx)
+
+ var nameSeq = targetName.split("::")
+ if (nameSeq.length == 1) {
ctx.stack.flatten.collectFirst {
- case target: CPPNameTarget[G] if target.name == name.head => target
+ case target: CPPNameTarget[G] if target.name == targetName => target
}
} else {
val ctxTarget: Option[RefCPPNamespaceDefinition[G]] = ctx.stack.flatten.collectFirst {
- case namespace: RefCPPNamespaceDefinition[G] if namespace.decl.name == name.head => namespace
+ case namespace: RefCPPNamespaceDefinition[G] if namespace.decl.name == nameSeq.head => namespace
}
ctxTarget match {
case Some(ref) =>
- var curNameSeq = name.drop(1);
- var foundNamespace: Option[CPPNamespaceDefinition[G]] = Some(ref.decl);
+ nameSeq = nameSeq.drop(1);
+ var foundNamespace: Option[CPPNamespaceDefinition[G]] = Some(ref.decl)
var returnVal: Option[CPPNameTarget[G]] = None;
- while (curNameSeq.nonEmpty) {
+ while (nameSeq.nonEmpty) {
if (foundNamespace.isEmpty) {
return None
}
- if (curNameSeq.length > 1) {
+ if (nameSeq.length > 1) {
// Look for nested namespaces
foundNamespace = foundNamespace.get.declarations.collectFirst {
- case namespace: CPPNamespaceDefinition[G] if namespace.name == curNameSeq.head => namespace
+ case namespace: CPPNamespaceDefinition[G] if namespace.name == nameSeq.head => namespace
}
} else {
// Look for final nameTarget
returnVal = foundNamespace.get.declarations.collectFirst {
- case funcDef: CPPFunctionDefinition[G] if getDeclaratorInfo(funcDef.declarator).name == curNameSeq.head => RefCPPFunctionDefinition(funcDef)
- case globalDecl: CPPGlobalDeclaration[G] if getDeclaratorInfo(globalDecl.decl.inits.head.decl).name == curNameSeq.head => RefCPPGlobalDeclaration(globalDecl, 0)
+ case funcDef: CPPFunctionDefinition[G] if getDeclaratorInfo(funcDef.declarator).name == nameSeq.head => RefCPPFunctionDefinition(funcDef)
+ case globalDecl: CPPGlobalDeclaration[G] if getDeclaratorInfo(globalDecl.decl.inits.head.decl).name == nameSeq.head => RefCPPGlobalDeclaration(globalDecl, 0)
}
}
- curNameSeq = curNameSeq.drop(1)
+ nameSeq = nameSeq.drop(1)
}
returnVal
case None => None
diff --git a/src/col/vct/col/typerules/CoercingRewriter.scala b/src/col/vct/col/typerules/CoercingRewriter.scala
index 769ec1347d..446d1bcadb 100644
--- a/src/col/vct/col/typerules/CoercingRewriter.scala
+++ b/src/col/vct/col/typerules/CoercingRewriter.scala
@@ -177,6 +177,8 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
case CoerceJavaClassAnyClass(_) => e
case CoerceCPrimitiveToCol(_, _) => e
case CoerceColToCPrimitive(_, _) => e
+ case CoerceCPPPrimitiveToCol(_, _) => e
+ case CoerceColToCPPPrimitive(_, _) => e
case CoerceNullRef() => e
case CoerceNullArray(_) => e
case CoerceNullClass(_) => e
@@ -1998,6 +2000,7 @@ abstract class CoercingRewriter[Pre <: Generation]() extends AbstractRewriter[Pr
case CPPBool() => CPPBool()
case CPPTypedefName(name) => CPPTypedefName(name)
case CPPSpecificationType(t) => CPPSpecificationType(t)
+ case SYCLQueue() => SYCLQueue()
}
}
diff --git a/src/parsers/antlr4/LangCPPLexer.g4 b/src/parsers/antlr4/LangCPPLexer.g4
index 43f217c708..a0cece3c57 100644
--- a/src/parsers/antlr4/LangCPPLexer.g4
+++ b/src/parsers/antlr4/LangCPPLexer.g4
@@ -39,6 +39,9 @@ BooleanLiteral: False | True;
PointerLiteral: Nullptr;
+// EW: Will be moved to own SYCL lexer later
+SYCLQueue: 'sycl::queue';
+
UserDefinedLiteral:
UserDefinedIntegerLiteral
| UserDefinedFloatingLiteral
diff --git a/src/parsers/antlr4/LangCPPParser.g4 b/src/parsers/antlr4/LangCPPParser.g4
index 5ee6065939..b6a2ab4328 100644
--- a/src/parsers/antlr4/LangCPPParser.g4
+++ b/src/parsers/antlr4/LangCPPParser.g4
@@ -446,6 +446,7 @@ simpleTypeSpecifier:
| Float
| simpleTypeLengthModifier? Double
| Void
+ | SYCLQueue // EW: Will be moved to own SYCL Parser later
| Auto
| {specLevel>0}? valType
| decltypeSpecifier;
diff --git a/src/parsers/vct/parsers/transform/CPPToCol.scala b/src/parsers/vct/parsers/transform/CPPToCol.scala
index 4ac67fb39d..ab1769b90b 100644
--- a/src/parsers/vct/parsers/transform/CPPToCol.scala
+++ b/src/parsers/vct/parsers/transform/CPPToCol.scala
@@ -339,6 +339,11 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
case PostfixExpression3(target, _, args, _, given, yields) =>
CPPInvocation(convert(target), args.map(convert(_)) getOrElse Nil,
convertEmbedGiven(given), convertEmbedYields(yields))(blame(expr))
+ case PostfixExpression4(classVar, _, None, idExpr) =>
+ convert(classVar) match {
+ case CPPLocal(className) => CPPLocal(className + "." + convert(idExpr).nestedName)(blame(expr))
+ case _ => ??(expr)
+ }
case PostfixExpression8(targetNode, _) =>
val target = convert(targetNode)
PostAssignExpression(target, col.AmbiguousPlus(target, const(1))(blame(expr)))(blame(expr))
@@ -493,7 +498,8 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
case SimpleTypeSpecifier11(Some(typeLengthMod), _) => Seq(convert(typeLengthMod), CPPSpecificationType(TFloats.ieee754_64bit))
case SimpleTypeSpecifier11(None, _) => Seq(CPPSpecificationType(TFloats.ieee754_64bit))
case SimpleTypeSpecifier12(_) => Seq(new CPPVoid[G]())
- case SimpleTypeSpecifier14(valType) => Seq(CPPSpecificationType(convert(valType)))
+ case SimpleTypeSpecifier13(_) => Seq(new SYCLQueue[G]())
+ case SimpleTypeSpecifier15(valType) => Seq(CPPSpecificationType(convert(valType)))
case x => ??(x)
}
@@ -509,24 +515,24 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
// Do not support template or decltypes, or a typename as identifier in the nestedname
def convert(implicit nestedNameSpec: NestedNameSpecifierContext): CPPTypedefName[G] = nestedNameSpec match {
- case NestedNameSpecifier0(theTypeName, _) =>
+ case NestedNameSpecifier0(theTypeName, sep) =>
convert(theTypeName) match {
- case name@CPPTypedefName(_) => name
+ case name@CPPTypedefName(_) => name.appendName(sep)
case x => ??(theTypeName)
}
- case NestedNameSpecifier1(namespaceName, _) => convert(namespaceName)
- case NestedNameSpecifier3(_) => CPPTypedefName(Seq())
- case NestedNameSpecifier4(inner, id, _) =>
+ case NestedNameSpecifier1(namespaceName, sep) => convert(namespaceName).appendName(sep)
+ case NestedNameSpecifier3(sep) => CPPTypedefName(sep)
+ case NestedNameSpecifier4(inner, id, sep) =>
convert(inner) match {
- case CPPTypedefName(nestedName) => CPPTypedefName(nestedName :+ convert(id))
+ case name@CPPTypedefName(_) => name.appendName(convert(id)).appendName(sep)
case _ => ??(inner)
}
case x => ??(x)
}
def convert(implicit namespaceName: NamespaceNameContext): CPPTypedefName[G] = namespaceName match {
- case NamespaceName0(OriginalNamespaceName0(id)) => CPPTypedefName(Seq(convert(id)))
- case NamespaceName1(NamespaceAlias0(id)) => CPPTypedefName(Seq(convert(id)))
+ case NamespaceName0(OriginalNamespaceName0(id)) => CPPTypedefName(convert(id))
+ case NamespaceName1(NamespaceAlias0(id)) => CPPTypedefName(convert(id))
}
// Do not support enum-names, typedef-names and template-names
@@ -537,7 +543,7 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
// Do not support template-names
def convert(implicit className: ClassNameContext): CPPTypeSpecifier[G] = className match {
- case ClassName0(name) => CPPTypedefName(Seq(convert(name)))
+ case ClassName0(name) => CPPTypedefName(convert(name))
case x => ??(x)
}
@@ -622,13 +628,13 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
// Do not support if spread operator '...' is used
def convert(implicit declaratorId: DeclaratoridContext): CPPDeclarator[G] = declaratorId match {
- case Declaratorid0(None, idExpr) => CPPName(convert(idExpr).nestedName.mkString("::"))
+ case Declaratorid0(None, idExpr) => CPPName(convert(idExpr).nestedName)
case x => ??(x)
}
// Do not support operatorFunctionId, conversionFunctionId, literalOperatorId, templateId, and things starting with a tilde
def convert(implicit unqualifiedId: UnqualifiedIdContext): CPPTypedefName[G] = unqualifiedId match {
- case UnqualifiedId0(clangppId) => CPPTypedefName(Seq(convert(clangppId)))
+ case UnqualifiedId0(clangppId) => CPPTypedefName(convert(clangppId))
case x => ??(x)
}
@@ -667,7 +673,7 @@ case class CPPToCol[G](override val originProvider: OriginProvider, override val
}
def local(ctx: ParserRuleContext, name: String): Expr[G] =
- CPPLocal(Seq(name))(blame(ctx))(origin(ctx))
+ CPPLocal(name)(blame(ctx))(origin(ctx))
def convert(decl: LangGlobalDeclContext): Seq[GlobalDeclaration[G]] = decl match {
case LangGlobalDecl0(decl) => convert(decl)
diff --git a/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala b/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala
index f3aa6e288b..9c1e767d3f 100644
--- a/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala
+++ b/src/rewrite/vct/rewrite/ResolveExpressionSideEffects.scala
@@ -320,6 +320,7 @@ case class ResolveExpressionSideEffects[Pre <: Generation]() extends Rewriter[Pr
case assn: SilverLocalAssign[Pre] => rewriteDefault(assn)
case proof: FramedProof[Pre] => rewriteDefault(proof)
case _: CStatement[Pre] => throw ExtraNode
+ case _: CPPStatement[Pre] => throw ExtraNode
case _: JavaStatement[Pre] => throw ExtraNode
}
}
diff --git a/src/rewrite/vct/rewrite/adt/ImportADT.scala b/src/rewrite/vct/rewrite/adt/ImportADT.scala
index ed250c978f..f48fa7a41d 100644
--- a/src/rewrite/vct/rewrite/adt/ImportADT.scala
+++ b/src/rewrite/vct/rewrite/adt/ImportADT.scala
@@ -4,7 +4,7 @@ import hre.util.ScopedStack
import vct.col.ast.RewriteHelpers.RewriteProgram
import vct.col.ast.`type`.TFloats
import vct.col.ast.util.Declarator
-import vct.col.ast.{CType, Declaration, GlobalDeclaration, JavaType, PVLType, Program, TAny, TArray, TAxiomatic, TBag, TBool, TBoundedInt, TChar, TClass, TEither, TFloat, TFraction, TInt, TMap, TMatrix, TModel, TNotAValue, TNothing, TNull, TOption, TPointer, TProcess, TRational, TRef, TResource, TSeq, TSet, TString, TTuple, TType, TUnion, TVar, TVoid, TZFraction, Type}
+import vct.col.ast.{CPPType, CType, Declaration, GlobalDeclaration, JavaType, PVLType, Program, TAny, TArray, TAxiomatic, TBag, TBool, TBoundedInt, TChar, TClass, TEither, TFloat, TFraction, TInt, TMap, TMatrix, TModel, TNotAValue, TNothing, TNull, TOption, TPointer, TProcess, TRational, TRef, TResource, TSeq, TSet, TString, TTuple, TType, TUnion, TVar, TVoid, TZFraction, Type}
import vct.col.typerules.CoercingRewriter
import vct.col.rewrite.error.ExtraNode
import vct.col.origin.{Blame, SourceNameOrigin, UnsafeCoercion}
@@ -64,6 +64,7 @@ case object ImportADT {
case TUnion(ts) => "union$" + ts.map(typeText).mkString("__") + "$"
case _: JavaType[_] => throw ExtraNode
case _: CType[_] => throw ExtraNode
+ case _: CPPType[_] => throw ExtraNode
case _: PVLType[_] => throw ExtraNode
}
}
diff --git a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
index f00e6b16d3..29e663d188 100644
--- a/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
+++ b/src/rewrite/vct/rewrite/lang/LangCPPToCol.scala
@@ -167,7 +167,7 @@ case class LangCPPToCol[Pre <: Generation](rw: LangSpecificToCol[Pre]) extends L
def rewriteNamespaceDef(ns: CPPNamespaceDefinition[Pre]): Unit = {
ns.drop()
namespace.having(ns) {
- // Do not enter a scope, so classes of the namespace are declared to the program.
+ // Do not enter a scope, so methods of the namespace are declared globally to the program.
ns.declarations.foreach(rw.dispatch)
}
}
diff --git a/src/viper/viper/api/transform/ColToSilver.scala b/src/viper/viper/api/transform/ColToSilver.scala
index d44cf30354..928de29efd 100644
--- a/src/viper/viper/api/transform/ColToSilver.scala
+++ b/src/viper/viper/api/transform/ColToSilver.scala
@@ -1,7 +1,7 @@
package viper.api.transform
import hre.util.ScopedStack
-import vct.col.ast.{AmbiguousLocation, ArrayLocation, FieldLocation, InstancePredicateLocation, ModelLocation, PointerLocation, PredicateLocation, SilverFieldLocation}
+import vct.col.ast.{PredicateLocation, SilverFieldLocation}
import vct.col.origin.{AccountedDirection, FailLeft, FailRight}
import vct.col.ref.Ref
import vct.col.util.AstBuildHelpers.unfoldStar
@@ -253,6 +253,7 @@ case class ColToSilver(program: col.Program[_]) {
def typ(t: col.Type[_]): silver.Type = t match {
case col.TBool() => silver.Bool
+ case col.TSYCLQueue() => silver.Ref
case col.TInt() => silver.Int
case col.TRational() => silver.Perm
case col.TRef() => silver.Ref
diff --git a/test/main/vct/test/integration/examples/SYCLSpec.scala b/test/main/vct/test/integration/examples/SYCLSpec.scala
new file mode 100644
index 0000000000..00c66b076a
--- /dev/null
+++ b/test/main/vct/test/integration/examples/SYCLSpec.scala
@@ -0,0 +1,7 @@
+package vct.test.integration.examples
+
+import vct.test.integration.helper.VercorsSpec
+
+class SYCLSpec extends VercorsSpec {
+ vercors should verify using silicon example "concepts/sycl/MethodResolving.cpp"
+}
\ No newline at end of file
From 203008f9e7a50580502e3435038f3ffec55abd12 Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Thu, 6 Jul 2023 10:06:01 +0200
Subject: [PATCH 09/11] fixed cpp include path finding
---
src/main/vct/options/Options.scala | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/vct/options/Options.scala b/src/main/vct/options/Options.scala
index 9e60931503..d1295c7e85 100644
--- a/src/main/vct/options/Options.scala
+++ b/src/main/vct/options/Options.scala
@@ -348,8 +348,9 @@ case class Options
simplifyPathsAfterRelations: Seq[PathOrStd] = Seq("simplify").map(name => PathOrStd.Path(Resources.getSimplificationPath(name))),
adtPath: Path = Resources.getAdtPath,
cc: Path = Resources.getCcPath,
- ccpp: Path = Resources.getCPPcPath,
cIncludePath: Path = Resources.getCIncludePath,
+ ccpp: Path = Resources.getCPPcPath,
+ cppIncludePath: Path = Resources.getCPPIncludePath,
classPath: Seq[ClassPathEntry] = Seq(ClassPathEntry.DefaultJre, ClassPathEntry.SourcePackageRoot),
z3Path: Path = viper.api.Resources.getZ3Path,
boogiePath: Path = viper.api.Resources.getBoogiePath,
From 710b88462fe7a865e35cc7cc87233b397607f02f Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Thu, 6 Jul 2023 10:30:14 +0200
Subject: [PATCH 10/11] fixed cpp and sycl tests not getting found by scalaTest
-i matrix
---
test/main/vct/test/integration/meta/ExampleCoverage.scala | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/main/vct/test/integration/meta/ExampleCoverage.scala b/test/main/vct/test/integration/meta/ExampleCoverage.scala
index a0de490ab5..816df554d6 100644
--- a/test/main/vct/test/integration/meta/ExampleCoverage.scala
+++ b/test/main/vct/test/integration/meta/ExampleCoverage.scala
@@ -14,6 +14,7 @@ class ExampleCoverage extends AnyFlatSpec {
new CIncludeSpec(),
new ClassesSpec(),
new CounterSpec(),
+ new CPPSpec(),
new DemoSpec(),
new FinalConstExprSpec(),
new ExtractSpec(),
@@ -38,6 +39,7 @@ class ExampleCoverage extends AnyFlatSpec {
new SilverDomainSpec(),
new SmtSpec(),
new SummationSpec(),
+ new SYCLSpec(),
new TechnicalAbruptSpec(),
new TechnicalEnumSpec(),
new TechnicalFloatSpec(),
From 2e0f92bb93fbb58426d0123babef33bae9d9f72d Mon Sep 17 00:00:00 2001
From: Ellen Wittingen
Date: Thu, 6 Jul 2023 11:04:28 +0200
Subject: [PATCH 11/11] cleaned up some tests
---
examples/concepts/cpp/Arrays.cpp | 9 ++++++++-
examples/concepts/cpp/Pointers.cpp | 28 ++--------------------------
examples/concepts/cpp/Types.cpp | 2 --
3 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/examples/concepts/cpp/Arrays.cpp b/examples/concepts/cpp/Arrays.cpp
index 2ae61a1f12..efd21c6a74 100644
--- a/examples/concepts/cpp/Arrays.cpp
+++ b/examples/concepts/cpp/Arrays.cpp
@@ -3,7 +3,7 @@
//:: tools silicon
//:: verdict Pass
-//@ requires a != nullptr && size > 0;
+//@ requires size > 0;
//@ context \pointer(a, size, read);
//@ requires (\forall int i = 0 .. size; {: a[i] :} == 0);
//@ ensures \result == b;
@@ -11,4 +11,11 @@ int sumWithLast(int a[], int size, int b) {
int sum = a[size-1] + b;
//@ assert a[size-1] == 0;
return sum;
+}
+
+//@ requires size > 2;
+//@ context \pointer(a, size, write);
+//@ ensures a[2] == 5;
+void writeToArray(int a[], int size) {
+ a[2] = 5;
}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Pointers.cpp b/examples/concepts/cpp/Pointers.cpp
index 2806e4777f..61b926c08e 100644
--- a/examples/concepts/cpp/Pointers.cpp
+++ b/examples/concepts/cpp/Pointers.cpp
@@ -3,34 +3,10 @@
//:: tools silicon
//:: verdict Pass
-// Examples taken from https://en.cppreference.com/w/cpp/language/pointer
-
-
-// &x is not supported but I do need it for SYCL buffers
//@ context \pointer(ints, size, write);
void test(int ints[], int size, int* p) {
- // char x = 'a';
- // char* charPtr = &x;
- // assert *charPtr == x;
-
- int arr[5];
- // int* arrPtr[5] = &arr;
- // assert arrPtr[4] == arr[4];
-
-// Does not support arrays containing pointers?
-// int* ptrArr[5];
-// ptrArr[2] = p;
-
+ int* intsPtr = ints;
+ //@ assert intsPtr == ints;
void* voidPtr = nullptr;
-
- int n;
- // int* p = &n;
- // *p = 10;
- // assert n == 10;
-
- if (size >= 4) {
- ints[3] = 5;
- }
- //@ assert size >= 4 ==> ints[3] == 5;
}
\ No newline at end of file
diff --git a/examples/concepts/cpp/Types.cpp b/examples/concepts/cpp/Types.cpp
index faa28e7d79..1e40272177 100644
--- a/examples/concepts/cpp/Types.cpp
+++ b/examples/concepts/cpp/Types.cpp
@@ -7,13 +7,11 @@ void test() {
bool aBool = true;
int anInt = 5;
- //short aShort = 5;
long aLong = 5;
double aDouble = 5.1;
float aFloat = 5.1;
char aChar = 'a';
-// char aCharArray[] = "Hello there";
void* voidPtr = nullptr;
}
\ No newline at end of file