{-# LANGUAGE UnicodeSyntax #-} module Main (main) where import qualified Editing.EditsPreparation import qualified Editing.Parse import qualified Editing.Execute import qualified Editing.Diff import qualified Cxx.Show import qualified Cxx.Parse import Parsers (eof, parseOrFailE) import Util (test_cmp, (<<), (.)) import Request (EditableRequest(..), EditableRequestKind(..)) import Prelude hiding ((.)) import Data.SetOps basic_tests :: IO () basic_tests = do f "" "make foo bar bas" "Unexpected end of command. Expected \"::\" or template-arguments." f "" "make " "Unexpected end of command. Expected \"declaration\", \"body\", production-name, \"all\", \"any\", \"every\", \"each\", ordinal, or declarator-id." f "" "make i pointer to" "Unexpected end of command. Expected type description." s "mutable int i;" "make i const" "const mutable int i;" s "int i;" "make i a const double" "double const i;" s "int const i;" "make i a double" "double const i;" s "void g(int); void f() { bind(&g)(3, 2); }" "make g a function taking two integers" "void g(int, int); void f() { bind(&g)(3, 2); }" -- "bind(&g)(3, 2);" is determined not to be declaration because it would be a reference initialized with two arguments. s "int i;" "make i a *&" "int *& i;" s "int * p = f();" "make p auto" "auto p = f();" s "inline void f();" "make f noninline" "void f();" s "int (* const i)(double);" "make i nonconst" "int (* i)(double);" s "int i;" "make i a pointer&" "int *& i;" f "int i;" "make j const" "Could not find free declaration of j." s "void f() { int i; i; i = 0; }" "make i a pointer" "void f() { int * i; i; i = 0; }" s "struct X { static void f(); }" "append semicolon and make f pure" "struct X { virtual void f()= 0 ; };" s "struct X { virtual void f() = 0; };" "make f static" "struct X { static void f() ; };" s "struct X { void f(); };" "make f virtual pure const inline explicit" "struct X { virtual inline explicit void f()const = 0 ; };" s "struct X { ~X(); };" "make ~ X virtual" "struct X { virtual ~X(); };" s "struct X { virtual inline explicit void f()const = 0 ; };" "make f impure nonvirtual nonexplicit noninline" "struct X { void f()const ; };" s "struct X { X(int i); };" "make i a reference to const and make constructor explicit" "struct X { explicit X(const int & i); };" s "int *p;" "make p a const*volatile" "const int *volatile p;" s "void N::f() {}" "make N::f inline" "inline void N::f() {}" s "struct X { void operator++(); };" "make operator++ a const function returning an X&" "struct X { X & operator++()const ; };" s "int x /*haha*/ ; // ok dan /* mja */" "make x const" "const int x /*haha*/ ; // ok dan /* mja */" s "T const ( &f() )[3] { T x = {v}; }" "make f inline" "inline T const ( &f() )[3] { T x = {v}; }" s "int *i; int * & j;" "make i a pointer to a pointer" "int ** i; int * & j;" s "struct Factorial { static int v = N; };" "make v const" "struct Factorial { const static int v = N; };" s "{ struct S {}; int (S:: * p) = 0; int (S:: * & r) = p; }" "make p and r const" "{ struct S {}; int (S:: * const p) = 0; int (S:: * const & r) = p; }" s "int i;" "make i an array" "int i[];" s "void f() { try { int long i; } catch(int long j) {} }" "make i and j long long" "void f() { try { long long int i; } catch(long long int j) {} }" s "void f() { try { long long i; } catch(long long j) {} }" "make i and j long" "void f() { try { long i; } catch(long j) {} }" s "int i;" "make i a const array" "const int i[];" s "int i;" "make i a const array of pointers" "int *const i[];" s "int i[];" "make i const" "const int i[];" s "struct X { ~X(); }" "append ; and make destructor virtual and show" "struct X { virtual ~X(); };" s "{ try{}catch(const int i){} }" "make i volatile" "{ try{}catch(volatile const int i){} }" s "void f(int i, double d){}" "make i and d long" "void f(long int i, long double d){}" s "void f(int i, int j, int k);" "make second parameter-declaration const and erase third parameter-declaration" "void f(int i, const int j);" s "void f(float, int, char, double);" "make second and third parameter-declaration const" "void f(float, const int, const char, double);" s "{ if(int i = 3) ; }" "make i const" "{ if(const int i = 3) ; }" s "int i;" "make i an array of const" "const int i[];" s "int i;" "make i a static const function" "static int i()const ;" s "int i;" "make i a pointer to a function" "int (* i)();" s "int i;" "make i a pointer to a function taking two doubles" "int (* i)(double, double);" s "int i;" "make i a function returning a const" "const int i();" s "int i;" "make i a function returning a const pointer and taking a bool" "int *const i(bool);" s "{ cout << 3, 3.2, 3ul, 3e+2, 0x3, 03, .3, 3., .3e1, 3.E0; int i; }" "make i const" "{ cout << 3, 3.2, 3ul, 3e+2, 0x3, 03, .3, 3., .3e1, 3.E0; const int i; }" s "void f(int i) { try {} catch(int j) {} }" "make f and i and j const" "void f(const int i) const { try {} catch(const int j) {} }" f "void f(int i) { try {} catch(int j) {} }" "make j mutable" "Invalid decl-specifier for type-specifier-seq: mutable" s "struct X { void f(int p); };" "make f static inline and make p a reference to long" "struct X { static inline void f(long int & p); };" s "struct X { operator ()(); };" "make operator() const" "struct X { operator ()()const ; };" -- Spaces don't matter when matching declarator-ids. s "<< 3, i; int i = 2;" "make i const" "<< 3, i; const int i = 2;" putStrLn "All make tests passed." t "erase all 2 and insert x before second 3 and prepend y" $ Right "y1 3 x3 4 5" t "erase everything before last 2 and replace everything after 4 with x" $ Right "2 3 4x" t "insert x after all 2 and append y" $ Right "1 2x 3 2x 3 4 5y" t "erase first 2 and replace second 2 with x and omit last " $ Right "1 3 x 3 45" t "erase first and last 2 and all 3 and 4 and everything before first 2 and everything after 4" $ Right " " t "erase third last space and kill everything after second last " $ Right "1 2 3 23 " t "insert x after 1 2 and before all 3 and erase 5 and prepend y" $ Right "y1 2x x3 2 x3 4 " t "erase everything before 4 and everything after 5" $ Right "4 5" t "insert x before 3 4 and 5" $ Right "1 2 3 2 x3 4 x5" t "insert x after 1 and all 3 and before 5 and erase 4" $ Right "1x 2 3x 2 3x x5" t "erase second space before 4" $ Right "1 2 3 23 4 5" t "erase first 2 3 and 3 2 and 4 5 and last " $ Right "1 3 " t "move 1 till second 3 to before 5" $ Right "3 4 1 2 3 2 5" t "move 1 till after second 3 to before 5" $ Right " 4 1 2 3 2 35" t "swap last 2 3 and last space before 4" $ Right "1 2 3 2 34 5" t "swap last 2 3 with last space before 4" $ Right "1 2 3 2 34 5" t "swap 1 and first 3 and second 3 and 5" $ Right "3 2 1 2 5 4 3" t "replace 2 after second space with x" $ Right "1 2 3 x 3 4 5" t "move everything till 4 to end and erase 4 " $ Right "51 2 3 2 3 " t "erase everything" $ Right "" t "insert x after second space before 4" $ Right "1 2 3 2 x3 4 5" t "add < and > around second 3" $ Right "1 2 3 2 <3> 4 5" t "add braces around everything" $ Right "{1 2 3 2 3 4 5}" t "move everything after second 3 to begin" $ Right " 4 51 2 3 2 3" t "move second 3 to end and 5 to begin" $ Right "51 2 3 2 4 3" t "erase first space until second space before 4" $ Right "1 3 4 5" t "erase spaces" $ return "1232345" t "erase second last space before 4" $ Right "1 2 3 23 4 5" t "erase after second 2" $ Right "1 2 3 2" t "erase after second 2 until before 5" $ Right "1 2 3 25" t "erase 1 and erase 1" $ Right " 2 3 2 3 4 5" t "erase before second last space" $ Right " 4 5" t "move 4 5 to before 1 and erase everything after second 2" $ Right "4 51 2 3 2" t "erase everything between last and first 2" $ Right "1 22 3 4 5" t "erase everything between second 2 and begin" $ Right "2 3 4 5" t "erase all space between second 2 and 4" $ Right "1 2 3 234 5" t "erase from first 3 until after everything" $ Right "1 2 " t "erase 2 after and before first 3" $ return "1 3 3 4 5" t "add + before and after 4" $ return "1 2 3 2 3 +4+ 5" t "move before second 3 until 4 to begin" $ Right "3 1 2 3 2 4 5" t "erase everything between begin and end" $ Right "" t "move everything between first 3 and 4 to begin" $ Right " 2 3 1 2 34 5" t "erase before second 3 until 4" $ Right "1 2 3 2 4 5" t "insert x before second 3 and at end" $ Right "1 2 3 2 x3 4 5x" t "erase until after second 3" $ Right " 4 5" t "erase from before second 3" $ Right "1 2 3 2 " t "replace all but first and second last space with x" $ Right "1 2x3x2x3 4x5" t "change all but first and second last space to x" $ Right "1 2x3x2x3 4x5" t "erase between second and fourth space and 1" $ Right " 2 3 4 5" t "erase between the first and third space and prepend x" $ Right "x1 2 3 4 5" t "add parentheses around every space between first 2 and 4 and around 5 and erase second last 3" $ Right "1 2( )( )2( )3( )4 (5)" t "move from first 3 until 4 to begin" $ Right "3 2 3 41 2 5" t "erase everything from before everything until the second 3" $ Right "3 4 5" t "add parentheses around first 2 and 5" $ Right "1 (2) 3 2 3 4 (5)" t "erase everything between first space and last space" $ Right "1 5" t "erase all 3 and all 2 between begin and end" $ Right "1 4 5" t "erase everything between second and first 2 " $ Right "1 2 2 3 4 5" t "erase from second 2 till last space" $ Right "1 2 3 5" t "erase from second 2 until after 3 and add x before 4" $ Right "1 2 3 x4 5" -- t "erase everything between 1 and the second 2 and everything between 4 and 5" $ Right "12 3 45" t "erase from before 4 until end" $ Right "1 2 3 2 3 " t "use 5x and y4" $ Right "1 2 3 2 3 y4 5x" t "erase everything from after 1 until second last space" $ Right "1 4 5" t "add parentheses around everything between 1 and second space before 4" $ Right "1( 2 3 2) 3 4 5" t "add + and - around all 3 and second 2 and prepend x" $ Right "x1 2 +3- +2- +3- 4 5" t "move 4 till end to front" $ Right "4 51 2 3 2 3 " t "erase all space after first 2" $ Right "1 232345" t "add x before first 3 after second 2" $ Right "1 2 3 2 x3 4 5" t "add x before second space after second 3" $ Right "1 2 3 2 3 4x 5" t "add x after all space before first 3" $ Right "1 x2 x3 2 3 4 5" t "erase all space before last 3" $ Right "12323 4 5" t "erase second 2 till end" $ Right "1 2 3 " t "append x before 5 and prepend y before all 2 between first 3 and 5" $ Right "1 2 3 y2 3 4 x5" t "move everything after second 3 to begin" $ Right " 4 51 2 3 2 3" t "replace first 2 with x and replace all 2 with x" $ Right "1 x 3 x 3 4 5" t "erase everything until 4 and 5" $ Right "4 " t "erase 3 2 till 5" $ Right "1 2 5" t "move second 2 to back and prepend x" $ Right "x1 2 3 3 4 52" t "cut everything before first 2 and first and second 3 and everything after 4 and prepend x" $ Right "x2 2 4" t "replace all 2 with 3 and erase all 3 and add x after second 2" $ Right "1 3 3x 4 5" t "insert spacer before 4 and insert a semicolon after 1 and erase last space" $ Right "1; 2 3 2 3 spacer45" t "erase first and second last " $ Right "12 3 2 34 5" t "replace 1 with x and all 2 with y and erase second 3" $ Right "x y 3 y 4 5" t "move everything after last 3 to front and erase 5" $ Right " 4 1 2 3 2 3" t "erase spaces around first 2" $ Right "123 2 3 4 5" t "erase spaces around 3 after second 2" $ Right "1 2 3 234 5" t "erase 1 and 2 around first space" $ Right " 3 2 3 4 5" t "erase all but first two spaces" $ Right "1 2 32345" t "add x after 4 and add y after 4" $ Right "1 2 3 2 3 4yx 5" t "erase 4 and add y before 4 and add x after 4" $ Right "1 2 3 2 3 yx 5" t "move 4 to end and insert x before 5" $ Right "1 2 3 2 3 x54" t "erase 4 and move 5 to begin" $ Right "51 2 3 2 3 " t "move 3 2 3 to front and insert x before second 2" $ Right "3 x2 31 2 4 5" t "append float x; int y;" $ Right "1 2 3 2 3 4 5float x; int y;" t "erase 5 and move everything after last 3 to front" $ Right " 4 1 2 3 2 3" t "move everything before 4 to end and move first 3 to front" $ Right "34 51 2 2 3 " t "move 3 4 5 to before 4" $ Left "Move destination lies in source range." t "move 1 and 4 to after first 3" $ Right " 2 314 2 3 5" -- Order-sensitive edits: t "add parentheses around everything and append x" $ Right "(1 2 3 2 3 4 5)x" t "add parentheses around all 3 and all 2 and erase 4" $ Right "1 (2) (3) (2) (3) 5" t "append x and add parentheses around everything" $ Right "(1 2 3 2 3 4 5x)" t "append x after everything before 4 and add y before 4" $ Right "1 2 3 2 3 xy4 5" t "insert y before 4 and insert z after second 3 " $ Right "1 2 3 2 3 zy4 5" t "prepend x and move 5 to begin and insert y before 1 and insert z before everything" $ Right "z5xy1 2 3 2 3 4 " t "add parentheses around everything and prepend x" $ Right "x(1 2 3 2 3 4 5)" t "prepend x and add parentheses around everything" $ Right "(x1 2 3 2 3 4 5)" t "prepend x before everything after 4 and add y after 4" $ Right "1 2 3 2 3 4yx 5" t "add y after 4 and prepend x before everything after 4" $ Right "1 2 3 2 3 4xy 5" -- Semantic edits: ct "a x;" "add b after first identifier" $ Right "ab x;" ct "struct X { operator bool() { return true; } };" "move declaration of operator bool to end" $ Right "struct X { };operator bool() { return true; } " ct "namespace N { void f(); } class C { void g() {} };" "swap body of N and body of C" $ Right "namespace N { void g() {} } class C { void f(); };" ct "void f() { int i; } void g() { int j; } void h() {}" "prepend BARK; in f and append BARK; in g and in h" $ Right "void f() { BARK;int i; } void g() { int j; BARK;} void h() {BARK;}" ct "class C { int f() {} };" "add int x; in C and add return x; in f" $ Right "class C { int f() {return x;} int x;};" ct "void f() { cout << 3; g(); }" "erase everything from after 3; until after body of f" $ Right "void f() { cout << 3;}" ct "int main() { cout << 3; }" "move << 3 to front and erase declaration of main" $ Right "<< 3" ct "{ cout << x; } enum E { x };" "add `cout, y;` in main and add ,y in E" $ Right "{ cout << x; cout, y;} enum E { x ,y};" ct "namespace N { void f(); void g(); void f(); } void h();" "add int x; after declaration of g in N" $ Right "namespace N { void f(); void g();int x; void f(); } void h();" ct "struct X { void f(); }; struct Y { void f(); };" "erase declaration of f in Y" $ Right "struct X { void f(); }; struct Y { };" ct "namespace N { void f(); void g(); void f(); } void h();" "move declaration of h to after declaration of g in N" $ Right "namespace N { void f(); void g(); void h();void f(); } " ct "void f() {} void g() {} namespace N { void f() {} } void f(int) {}" "add int x; in f in N and in g and append y" $ Right "void f() {} void g() {int x;} namespace N { void f() {int x;} } void f(int) {}y" ct "void f() { int x; } void g() { int x; } void h() { int x; }" "erase declaration of x in f and h" $ Right "void f() { } void g() { int x; } void h() { }" ct "namespace N { int x; } int x; void f() { int x; }" "use int y; in N and f" $ Right "namespace N { int y; } int x; void f() { int y; }" ct "void f() {} void f(int) {} void f(double) {} void f(char) {}" "add int x; in first f and in third and fourth body of f" $ Right "void f() {int x;} void f(int) {} void f(double) {int x;} void f(char) {int x;}" ct "namespace A { int x; namespace B { int x; namespace C { int x; namespace D { int x; } } } }" "erase declaration of x in D in C in B in A" $ Right "namespace A { int x; namespace B { int x; namespace C { int x; namespace D { } } } }" ct "struct X { X(int); };" "erase second declaration of X" $ Right "struct X { };" ct "template void f(); void f(int);" "erase second declaration of f" $ Right "template void f(); " ct "struct X { template X(U); };" "erase second declaration of X" $ Right "struct X { };" ct "struct X { int x; X(); void f(); ~X(); struct Y {}; operator int(); X(int); };" "erase constructors and replace destructor with int y;" $ Right "struct X { int x; void f(); int y; struct Y {}; operator int(); };" ct "template struct X { template inline X(T, U); ~X(); }; template template X::X(T, U) {} template X::~X() {}" "erase second constructor and second destructor" $ Right "template struct X { template inline X(T, U); ~X(); }; " ct "void f(int i);" "erase declaration of i" $ Right "void f();" ct "struct X { int i; };" "erase declaration of i" $ Right "struct X { };" ct "{ 3; 4; 5; }" "swap first and last statement" $ Right "{ 5; 4; 3; }" ct "{ 3; 4; 5; }" "swap statements around 4;" $ Right "{ 5; 4; 3; }" ct "{ 3; 4; 5; 6; }" "swap statements before 5 with last statement" $ Right "{ 6; 5; 3; 4; }" ct "void f(int,double,char);" "swap first two parameter-declarations" $ return "void f(double,int,char);" --todo: ct "{ if(b) 3; 4; 5; }" "add curlies around first two statements after if" $ Right "{ if(b) {3; 4;} 5; }" --todo: ct "{ 3; 4; 5; }" "add curlies around first and second statement" $ Right "{ {3; 4;} 5; }" ct "{ 3; 4; 5; }" "add curlies around first statement and around second statement" $ Right "{ {3;} {4;} 5; }" ct "<< max(3, 2, 1)" "add curlies around code between parens" $ return "<< max({3, 2, 1})" ct "{ 1;2;3;4;5; }" "swap first two statements with last two statements" $ Right "{ 4;5; 3;1;2;}" ct "{ 1;2;3; }" "swap first two statements" $ Right "{ 2;1;3; }" --ct "void f() { 1; } void g() { 1; 2; 3; 4; }" "replace first two and last statement in g with 0;" $ Right "void f() { 1; } void g() { 0;3; 0;}" ct "void f() { int x = 3; cout << x; } int i;" "replace everything after first statement in f with BARK;" $ Right "void f() { int x = 3; BARK;} int i;" ct "template struct S;" "erase second template-parameter" $ return "template struct S;" ct "void g(string s); void f(int i, double d, char c, float, bool b);" "erase first and last two parameter-declarations in declaration of f and replace third parameter-declaration in declaration of f with wchar_t c" $ return "void g(string s); void f(double d, wchar_t c);" ct "int f();" "replace type-specifier with void" $ Right "void f();" ct "void g() { 0; struct X { void f() { 1;2;3;4; } }; 1; }" "erase statements around 2 in f" $ Right "void g() { 0; struct X { void f() { 2;} }; 1; }" ct "int a;in@@@t x;int y;int z;" "erase @@@ and erase int a; and erase second declaration" $ Right "int y;int z;" ct "@ int x;" "erase @ and replace declaration of x by bla" $ return " bla" ct "@@@@@ void f(){} int x;" "erase @@@@@ and erase first x after function-definition" $ Right " void f(){} int ;" ct "@@@@int x; int y; int z;" "erase @@@@ and erase from start until second declaration" $ Right "int z;" ct "@@@@int x; int y; int z;" "erase @@@@ and erase from second declaration until last space" $ Right "int x; z;" ct "class X extends Y { int i:2; };" "replace extends with : and replace literal after : with 3" $ Right "class X : Y { int i:3; };" ct "T f() { 0;x; } U y;" "erase everything after 0 in f" $ Right "T f() { 0} U y;" ct "T f() { 0;x; } U y;" "erase everything before x in f" $ Right "T f() { x; } U y;" ct "T f() { 0;1;2;3;4; } U y;" "erase everything between second and fourth statement in f" $ Right "T f() { 0;1;3;4; } U y;" ct "; void g() {} void f() { {1;} }" "erase first semicolon and erase curlies around 1;" $ return " void g() {} void f() { 1; }" -- Edit errors: ct "struct X { void f() { cout << 3; int x; cout << 3; } };" "erase second 3 after declaration of x in f in X" $ Left "String `3` does not occur twice after free declaration of x in f in X." t "erase second 4 after 1" $ Left "String `4` does not occur twice after 1." t "move second 2 to x" $ Left "Unexpected `x` after `second 2 to `. Expected \"beginning\", \"begin\", \"front\", \"start\", \"end\", \"back\", \"before\", or \"after\"." t "replace alligators with chickens" $ Left "String `alligators` does not occur." t "use banana" $ Left "No non-exact match for banana." t "use 5426" $ Left "No non-exact match for 5426." t "erase 2" $ Left "String `2` occurs multiple times." t "replace 1 and erase with 4" $ Left "String `erase` does not occur." t "replace tenth last 2 by x" $ Left "String `2` does not occur 10 times." t "erase second 9" $ Left "String `9` does not occur." t "replace all 2 with 3 and replace second 2 with x" $ Left "Overlapping edits: replace 2 with 3 and replace 2 with x." t "erase everything before first 3 and replace first 2 with x" $ Left "Overlapping edits: erase `1 2 ` and replace 2 with x." t "erase 5 between 1 and 4" $ Left "String `5` does not occur between 1 and 4." t "prepend x and replace 4 with a and replace 4 with b" $ Left "Overlapping edits: replace 4 with a and replace 4 with b." -- Syntax errors: t "isnert 3 before 4" $ Left "Unexpected `isnert` at start. Expected edit command." t "insert " $ Left "Unexpected end of command. Expected option, wrapping description, or verbatim string." t "insert kung fu" $ Left "Unexpected end of command. Expected \" and\", \" in\", \" at\", \" around\", \" before\", or \" after\"." t "move " $ Left "Unexpected end of command. Expected \"till\", \"until\", \"from\", \"everything\", \"code\", \"before\", \"between\", \"after\", \"declaration\", \"body\", production-name, verbatim string, \"all\", \"any\", \"every\", \"each\", or ordinal." t "move x " $ Left "Unexpected end of command. Expected \" till\", \" until\", \" around\", \" before\", \" after\", \" between\", \" in\", \" and\", or \" to\"." t "move x to "$ Left "Unexpected end of command. Expected \"beginning\", \"begin\", \"front\", \"start\", \"end\", \"back\", \"before\", or \"after\"." t "erase all 2 and " $ Left "Unexpected end of command. Expected verbatim string, \"till\", \"until\", \"from\", \"everything\", \"code\", \"before\", \"between\", \"after\", \"declaration\", \"body\", production-name, \"all\", \"any\", \"every\", \"each\", ordinal, wrapping description, option, or edit command." putStrLn "All basics tests passed." where ct :: String → String → Either String String → IO () ct x c o = test_cmp c o $ case parseOrFailE (Editing.Parse.commandsP << eof) c "command" of Left e → Left e Right (cmds, _) → editable_body . Editing.Execute.execute Nothing cmds (EditableRequest (Evaluate (∅)) x) s, f :: String → String → String → IO () s code cmdstring expectation = ct code cmdstring (Right expectation) -- test for success f code cmdstring expectation = ct code cmdstring (Left expectation) -- test for failure t = ct "1 2 3 2 3 4 5" diff_tests :: IO () diff_tests = do dt' "foo; bar; monkey; chicken; bas;" "bar; monkey; chicken;" "Erased `foo;` and `bas;`." "Prepended `foo;` and appended `bas;`." dt' "{ fstream f(\"t.cpp\"); string s(istreambuf_iterator(f), istreambuf_iterator()); }" "{ fstream f(\"t.cpp\"); string s((istreambuf_iterator(f)), istreambuf_iterator()); }" "Inserted ( before `istreambuf_iterator`, and inserted ) after `istreambuf_iterator(f)`." "Erased ( before `istreambuf_iterator` and ) after `istreambuf_iterator(f)`." -- Todo: One day, the former should say "wrapped ...". dt' "int f(int & i) { i = 4; return i;} int g(int && i){return f(i);} int main() { cout << g(2); }" "int & f(int & i) { i = 4; return i;} int & g(int && i){return f(i);} int & g(int & i){return f(i);} int main() { cout << g(2); }" "Replaced `int f` with `int & f`, replaced `int g` with `int & g`, and inserted `int & g(int & i){return f(i);}` before `int main`." "Replaced `int & f` with `int f`, replaced `int & g` with `int g`, and erased `int & g(int & i){return f(i);}`." dt' "{string foo = \"kangaroo\"; auto m = foo.find_first_of('m'); cout << *m;}" "{string foo = \"kangaroo\"; size_t m = foo.find_first_of('m'); cout << foo[m];}" "Replaced `auto m` with `size_t m`, and replaced `<< *m` with `<< foo[m]`." "Replaced `size_t m` with `auto m`, and replaced `<< foo[m]` with `<< *m`." -- Todo: Group. dt "{int i=0,t=time(0);for(;i<5000000;i++)asm(\".org 0xffff\");cout << time(0)-t; }" "{int i=0,t=time(0);for(;i<5000;i++)int tmp=1*88+71/4000^66;cout << time(8)-t; }" "Replaced i<5000000 with i<5000, replaced `asm(\".org 0xffff\")` with `int tmp=1*88+71/4000^66`, and replaced 0 with 8." dt' "struct curr_func { string name; cf(string n):name(n){} }; \\ #define DEFUN(name) name try { throw curr_func(#name); } catch(curr_func& cfun) \\ DEFUN(void haha(int a)) { cout << cfun.name; } int main() { cout << haha; }" "struct curr_func { string name; curr_func(string n):name(n){} }; \\ #define DEFUN(name) name try { throw curr_func(#name); } catch(curr_func& cfun) \\ DEFUN(void haha(int a)) { cout << cfun.name << \": \" << a; } int main() { haha(42); }" "Replaced cf with curr_func, inserted `<< \": \" << a` after `<< cfun.name`, and replaced `cout << haha` with haha(42)." "Replaced curr_func with cf, erased `<< \": \" << a`, and replaced haha(42) with `cout << haha`." dt "{float i=0,t=time(0);for(;i<5000000;i++) { if(x == 3) f(reinterpret_cast(x)); } }" "{int i=0,t=time(null);for(;i<5000000;++i) { if(x != 3) f(static_cast(x)); } }" "Replaced `float i` with `int i`, replaced 0 with null, replaced i++ with ++i, replaced `x == 3` with `x != 3`, and replaced `reinterpret_cast` with `static_cast`." {- dt' "struct a { int b; a():b([]{ return 1 + 2 + 3; }){}}a_; int main() { cout << a_.b }" "struct a { int b; a({}):b([]{ return 1 + 2 + 3; }()){}}a_; int main() { cout << a_.b; }" "Replaced \"a():b([]{\" with \"a({}):b([]{\", replaced \")\" after \"return 1 + 2 + 3; }\" with \"())\", and inserted \";\" after \"cout << a_.b\"." "Replaced \"a({}):b([]{\" with \"a():b([]{\", replaced \"}()){}}a_\" with \"}){}}a_\", and erased \";\" after \"cout << a_.b\"." -} dt "struct curr_func { string name; cf(string n):name(n){} }; \\ #define DEFUN(name) name try { throw curr_func(#name); } catch(curr_func& cfun) \\ DEFUN(void haha(int a)) { cout << cfun.name; } int main() { cout << haha; }" "struct { string name; cf(string n){} }; \\ #define DEFUN(name) name try { } catch(curr_func& cfun) \\ DEFUN(void haha(int a) { cout << \"tortoise\"; } ) { cout << ETYPE(cfun.name); } int main() { do_something(complicated); cout << haha; }" "Replaced `struct curr_func` with struct, erased :name(n) and `throw curr_func(#name);`, inserted `{ cout << \"tortoise\"; }` before `) { cout`, replaced `<< cfun.name` with `<< ETYPE(cfun.name)`, and inserted `do_something(complicated);` before `cout << haha`." {- dt "{ char str[] = \"giraffe\"; char * pch; pch=(char*) memchr(str, 'y', (int)strlen(str)); if (pch!=NULL) { printf(\"'y' was found at position #%d\", pch-str+1); } }" "{ char * str = \"giraffe\"; char * pch; pch=(char*) memchr(str, 'v', (size_t)strlen(str)); if (pch!=NULL) { printf(\"'v' was found at position #%d\", pch-str-1); memset(str, '*', 6); puts(str); printf(\"%s\", str); } }" "Replaced `char str[]` with `char * str`, replaced 'y' with 'v', replaced int with size_t, replaced `\"'y' was` with `\"'v' was`, and replaced pch-str+1 with `pch-str-1); memset(str, '*', 6); puts(str); printf(\"%s\", str`." -} dt "geordi: { char y(34); stringstream i(\"geordi: { char y(34); stringstream i(!); string t; getline(i, t, '!'); cout << t << y << i.str() << y << i.rdbuf(); }\"); string t; getline(i, t, '!'); cout<< t << y << i.str() << y << i.rdbuf(); }" "geordi: { stringstream i(\"geordi: { stringstream i(!); string t; getline(i, t, '!'); cout << t << i.str() << i.rdbuf(); }\"); string t; getline(i, t, '!'); cout << t << i.str() << i.rdbuf(); }" "Erased `char y(34);` and `char y(34);` and `<< y` and `<< y` and `<< y` and `<< y`." -- Todo: "Erased all \"char y(34);\" and all \"<< y\"." dt "char *& f() { static char *p; cout << &p << endl; return p; } int main() { char *p = f(); cout << &p << endl; }" "char *& f() { static char *p; cout << &p << ' '; return p; } int main() { char *p = f(); cout << &p; }" "Replaced `<< endl` with `<< ' '`, and erased `<< endl`." -- Todo: say "first" and "last". putStrLn "All diff tests passed." where dt :: String → String → String → IO () dt x y r = test_cmp x r $ show $ Editing.Diff.diff x y dt' :: String → String → String → String → IO () dt' x y xy yx = do test_cmp x xy $ show $ Editing.Diff.diff x y test_cmp y yx $ show $ Editing.Diff.diff y x dts :: String → [(String, String)] → IO () dts _ [] = return () dts s ((s', d) : r) = dt s s' d >> dts s' r make_type_tests :: IO () make_type_tests = do t "void(pointer)" $ Right "void(T *)" t "pointer to const pointer to long double" $ Right "long double*const *" t "function taking an int and returning nothing" $ Right "void(int )" let q = "void(int (* const (** (* const volatile (X::* volatile* (* )(int) )(char*)) [2])(long) ) [3])" in t q $ Right q t "function returning nothing and taking a pointer to a function returning a bool and taking an int" $ Right "void (bool (*)(int))" t "function taking a pointer to a (function returning a bool and taking an int), returning nothing" $ Right "void(bool (*)(int))" t "reference to a pointer to a function returning nothing, and taking an int" $ Right "void(*&)(int)" t "function taking an int, a char, a double, and returning nothing" $ Right "void(int, char, double)" t "function returning nothing and taking an int, a char, and a double" $ Right "void (int, char, double)" t "function returning a B>" $ Right "B>()" t "vector" $ Right "vector" t "function returning a ::B>2)>::value_type and taking a vector>" $ Right "::B>2)>::value_type (vector>)" t "function taking no arguments, returning a reference to an array of three pointers to functions taking integers and returning nothing" $ Right "void(*(&())[3])(int )" t "pointer to a constant volatile pointer to an array of 3 ints" $ Right "int(*volatile const *)[3]" t "function returning nothing and taking a reference to an array of three pointers to void" $ Right "void (void*(&)[3])" t "pointer to void(void)" $ Right "void(*)(void)" t "reference to pointer to const array" $ Right "T const (*&)[]" t "function taking a const (pointer to int) and a volatile function" $ Right "T (int*const , T ()volatile )" t "function taking two integers, three doubles, and returning a boolean" $ Right "bool(int, int, double, double, double)" t "function taking two pointers to integers" $ Right "T (int*, int*)" t "rvalue reference to function" $ Right "T (&&)()" t "constant constant pointer to volatile volatile int" $ Right "volatile volatile int*const " --t "pointer to a function from string_bla to int" $ Right "int(*)(string_bla )" t "pointer to " $ Left "Unexpected end of type description. Expected type description." t "pointer to function taking pointer to function" $ Right "T (*)(T (*)())" --t "pointer to int and double" $ Left "Unexpected \"a\" after \"to int \". Expected type-specifier, abstract-declarator, or end of type description." t "function returning " $ Left "Unexpected end of type description. Expected type description." t "function taking a pointer and a reference and returning a reference to a constant array" $ Right "T const (&(T *, T &))[]" t "array of " $ Left "Unexpected end of type description. Expected type description or integer-literal." t "foo bar bas" $ Left "Unexpected `bas` after `foo bar `. Expected \"::\" or template-arguments." t "array of seven characters" $ Right "char[7]" t "pointer to (function taking constant integer)*" $ Right "T (**)(const int)" t "pointer to void()" $ Right "void(*)()" t "function taking a pointer to void() returning a reference to an int[3]" $ Right "int(&(void(*)() ))[3]" t "void(pointer to function)" $ Right "void(T (*)())" t "function*(const int)" $ Right "T (*(const int))()" t "constant pointer to a function" $ Right "T (*const )()" t "(function taking an int[3] )*" $ Right "T (*)(int[3] )" t "(function*[3])&()" $ Right "T (*(&())[3])()" t "int(::T::U::V::**)" $ Right "int(::T::U::V::**)" t "int(X::*)()const volatile" $ Right "int(X::*)()const volatile" t "int volatile X::* Y::* const Z::*" $ Right "int volatile X::* Y::* const Z::*" {- t "pointer to a member function" $ Right "void(T::*)()" t "pointer to member integer" $ Right "int T::*" t "pointer to member" $ Right "T T::*" t "pointer to member pointer to member pointer to member array" $ Right "T(T::* T::* T::*)[]" -} t "array*const" $ Right "T (*const)[]" t "function taking (pointer to function returning int taking int) returning int" $ Right "int(int (*)(int))" --t "function+" $ Left "Unexpected \"+\" after \"function\". Expected \"taking\", \"returning\", \"from\", abstract-declarator, or end of type description." t "void(register pointer to string)" $ Right "void(register string*)" t "array of three arrays of 2 arrays of 1 integer" $ Right "int[3][2][1]" putStrLn "All make-type tests passed." where t :: String → Either String String → IO () t i o = test_cmp i o (either (Left . id) (Right . Cxx.Show.show_simple) $ Cxx.Parse.makeType i) precedence_tests :: IO () precedence_tests = do s "x::y" "x::y" s "if (b) int *ptr = new int(3), a(2);" "if (b) {int *ptr = (new int(3));int a(2);}" s "if(b) if(c) foo; else bar;" "if(b) { if(c) { foo; } else { bar; } }" s "a=bx->*x.x.*x" "((x->x)->*(x.x)).*x" s "x || x && x | x ^ x bitand x == x < x << x" "x || (x && (x | (x ^ (x bitand (x == (x < (x << x)))))))" s "*++vector{2,5,4}.rbegin()" "*(++(((vector{2,5,4}).rbegin)()))" s "x---------x" "((((x--)--)--)--)-x" s "z+operator+(x,y)" "z+(operator+(x,y))" s "x.operator()() * operator new[ ]()" "((x.operator())()) * (operator new[ ]())" s "throw 2 + 1, throw, 9" "((throw (2 + 1)), throw), 9" s "x + x *= x + x /= x + x" "(x + x) *= ((x + x) /= (x + x))" s "(x)y + x(y)" "((x)y) + (x(y))" f "(x+y)z" "Unexpected `z` after (x+y). Expected postfix operator, binary operator, ternary operator, or end of code." s "a+++a, b++ +b, c+ ++c, d+++ +d, e+ +++e" "(((((a++)+a), ((b++) +b)), (c+ (++c))), ((d++)+ (+d))), (e+ (++(+e)))" s "x += operatornew, b(), !c" "((x += operatornew), (b())), (!c)" s "sizeof u + sizeof(x) + sizeof(y*z)" "((sizeof u) + sizeof(x)) + (sizeof(y*z))" s "x.template a()" "(x.template a)()" s "const_cast>>(x)" "const_cast>>(x)" -- Tricky closing angle brackets. s "x.~y" "x.~y" s "f (x+3,y)-g(x+3)" "(f ((x+3),y))-(g(x+3))" s "::x + y::z + a::b::c::d::e" "(::x + y::z) + a::b::c::d::e" s "x[y + 'z']" "x[y + 'z']" -- No parens around x + z or around 'z'. f "x*" "Unexpected end of code. Expected pm-expression." f "x && throw 3" "Unexpected `throw` after `x && `. Expected inclusive-or-expression." f "&operator" "Unexpected end of code. Expected overloadable operator or conversion-type-id." f "x.*" "Unexpected end of code. Expected cast-expression." f "x--x" "Unexpected `x` after x--. Expected postfix operator, binary operator, ternary operator, or end of code." f "x." "Unexpected end of code. Expected id-expression, \"template\", or pseudo-destructor-name." f "x-" "Unexpected end of code. Expected multiplicative-expression." f "x( " "Unexpected end of code. Expected \")\" or expression-list." f "x(y" "Unexpected end of code. Expected \")\", \"(\", braced-init-list, \"::\", template-arguments, postfix operator, binary operator, ternary operator, or comma." f "x?y" "Unexpected end of code. Expected colon, \"(\", braced-init-list, \"::\", template-arguments, postfix operator, binary operator, or ternary operator." f "x[" "Unexpected end of code. Expected expression or braced-init-list." f "x.operator foo bar()" "Unexpected `(` after `foo bar`. Expected \"::\" or template-arguments." putStrLn "All precedence tests passed." where s :: String → String → IO () -- Test for success. s i o = test_cmp i (Right o) (Cxx.Parse.precedence i) f :: String → String → IO () -- Test for failure. f i o = test_cmp i (Left o) (Cxx.Parse.precedence i) parse_tests :: IO () parse_tests = do t "struct A;" t "void f(int, ...);" t "{ if(int i = 3); }" t "int (::x::y);" putStrLn "All parse tests passed." where t :: String → IO () t s = test_cmp s (Right s) $ fmap Cxx.Show.show_simple $ Cxx.Parse.parseRequest s main :: IO () main = do basic_tests Editing.EditsPreparation.use_tests diff_tests make_type_tests precedence_tests parse_tests