Functional programming style pattern-matching library for C++

Mach7: Pattern Matching for C++ Build Status: Linux, OSX Build Status: Windows Build Status: GitHub Actions

by Yuriy Solodkyy, Gabriel Dos Reis, Bjarne Stroustrup

Abstract

Pattern matching is an abstraction mechanism that can greatly simplify source code. Commonly, pattern matching is built into a language to provide better syntax, faster code, correctness guarantees and improved diagnostics. Mach7 is a library solution to pattern matching in C++ that maintains many of these features. All the patterns in Mach7 are user-definable, can be stored in variables, passed among functions, and allow the use of open class hierarchies.

Mach7 by Example

Fibonacci numbers demonstrates the use of patterns with built-in types in Mach7:

// Fibonacci numbers
int fib(int n)
{
    var<int> m;

    Match(n)
    {
      Case(1)     return 1;
      Case(2)     return 1;
      Case(2*m)   return sqr(fib(m+1)) - sqr(fib(m-1));
      Case(2*m+1) return sqr(fib(m+1)) + sqr(fib(m));
    }
    EndMatch
}

Lambda calculator demonstrates use of pattern matching to decompose objects and nested patterns:

// Declare C++ equivalent of an Algebraic Data Type Term and its 3 variants:
struct Term       { virtual ~Term() {}     };
struct Var : Term { std::string name;      };
struct Abs : Term { Var&  var;  Term& body;};
struct App : Term { Term& func; Term& arg; };

// Tell Mach7 library which members should be bound in which binding positions
namespace mch
{
    template <> struct bindings<Var> { Members(Var::name); };
    template <> struct bindings<Abs> { Members(Abs::var , Abs::body); };
    template <> struct bindings<App> { Members(App::func, App::arg);  };
}

// Implement fully-functional lambda-calculator
Term* eval(Term* t)
{
    var<const Var&> v;
    var<const Term&> b,a;

    Match(*t)
    {
      Case(C<Var>())               return &match0;
      Case(C<Abs>())               return &match0;
      Case(C<App>(C<Abs>(v,b),a))  return eval(subs(b,v,a));
      Otherwise() cerr << "error"; return nullptr ;
    }
    EndMatch
}

It can also be used to demonstrate relational matching on several arguments:

bool operator==(const Term& left, const Term& right)
{
    var<std::string> s;
    var<const Term&> v,t,f;

    Match(left,right)
    {
      Case(C<Var>(s),     C<Var>(+s)     ) return true;
      Case(C<Abs>(&v,&t), C<Abs>(&+v,&+t)) return true;
      Case(C<App>(&f,&t), C<App>(&+f,&+t)) return true;
      Otherwise()                          return false;
    }
    EndMatch

    return false; // To prevent all control path warning
}

Next example demonstrates that the library can deal efficiently and in a type-safe manner with non-polymorphic classes like boost::variant as well.

void print(const boost::variant<double,float,int>& v)
{
    var<double> d; var<float> f; var<int> n;

    Match(v)
    {
      Case(C<double>(d)) cout << "double " << d << endl; break;
      Case(C<float> (f)) cout << "float  " << f << endl; break;
      Case(C<int>   (n)) cout << "int    " << n << endl; break;
    }
    EndMatch
}

Breve syntax is not the only thing Mach7 has to offer - the generated code is faster than Visitors!

For a more detailed set of examples, have a look at the code that was prepared for CppCon 2014 presentation, and implemented using visitors as well as pattern matching. These are simple enough to help you get started on your own Mach7 project.

Continuous Integration

We use Travis CI and AppVeyor for continuous integration and currently have all check-ins validated in the following configurations:

Build Status G++ Clang
Linux 4.9 3.4
OSX 4.9 3.5
Build Status: Visual C++ 2019 2017 2015 2013 2012 2010 /analyze
x86 Fail OK OK OK OK OK OK
x64 Fail OK OK OK OK N/A OK

Build Status: GitHub Actions

Branches

  • master - main development branch
  • release - cleaned-up branch with non-essential files deleted. FI from but does not RI back to master to avoid deletion of files there. Don't do any actual editing in this branch.

Building sources

If you haven't done so yet, get a copy of this Git repo locally by executing:

git clone https://github.com/solodon4/Mach7.git

The library itself is header only and does not require building. To build unit and timing tests we've accumulated over time several scripts, which we don't completely abandon in favor of newer ones as they maintain the flags the original experiments on the library were built with.

Using CMake (3.2 or later)

CMake support is the most recent and is still very experimental at this point. To build with cmake, perform the following commands from within Mach7 folder:

cmake -H. -Bbuild
cmake --build build --target install

Note: this requires administrative privileges under all systems, if you don't like this, try commands below:

cmake -H. -Bbuild -DCMAKE_INSTALL_PREFIX=/wherever/doesn't/require/administrative/priviege
cmake --build build --target install

But please make sure msvc/clang/gcc is able to find the path your provide above when including Mach7's headers in your own project:

Using Makefiles for GCC (4.4 or later) or Clang (3.3 or later)

Top-level Makefile synopsis:

make         - build all library tests
make all     - same as above right now
make unit    - build all unit tests
make time    - build all timing tests
make cmpl    - build all tests for timing the compilation times of the library
make clean   - clean all built targets and intermediaries
make test    - run all the built tests
make check   - run those tests for which there are correct_output/*.out files and check that the output is the same
make doc     - build Mach7 documentation (requires doxygen)
make includes.png - build graph representation of header inclusions (requires graphviz dot)

To see a list of more specific targets supported by other makefiles, see comments inside them.

To build a particular file, say test/unit/example05.cpp, build a target with the same filename and extension .exe instead of .cpp (even on Unix family OS). For example:

cd $MACH7_ROOT/code/test/unit
make example05.exe

Lower-level makefiles support most of the phony targets of the top-level makefile, to which the top-level makefile forwards the corresponding calls. For example:

To build and run just the unit tests:

cd $MACH7_ROOT/code/test/unit
make
make check
make test

Similarly, to build and run all the timing tests:

cd $MACH7_ROOT/code/test/time
make
make test

Using Visual C++ (2010 or later)

Mach7 uses its own build.bat script to build all the examples and unit tests that come with it. The script assumes each .cpp file to be a standalone program. You can find the most up-to-date list of supported commands by running:

build.bat /?
Syntax:
build [ pgo | repro | tmp | <ver> ] [ filemask*.cpp ... ]
build [ syntax | timing | cmp | doc | clean | test | check ]
Commands supported so far:
build [ pgo | repro | tmp | <ver> | <arch> ] [ filemask*.cpp ... ] - build given C++ files
build        - Build all examples using the most recent MS Visual C++ compiler installed
build unit   - Build all unit tests
build syntax - Build all supported library options combination for syntax variations
build timing - Build all supported library options combination for timing variations
build cmp    - Build all executables for comparison with other languages
build doc    - Build Mach7 documentation
build clean  - Clean all built examples
build test   - Run all built examples
build check  - Run those examples for which there are correct_output/*.out files and
               check that output is the same
Modifiers:
       pgo   - Perform Profile-Guided Optimization on produced executables
       repro - In case of error, create and compile a pre-processed repro
       tmp   - Keep temporaries
      <ver>  - Use a specific version of Visual Studio to compile the source
               code. <ver> can be one of the following:
                - 2019 - Visual C++ 16.0
                - 2017 - Visual C++ 15.0
                - 2015 - Visual C++ 14.0
                - 2013 - Visual C++ 12.0
                - 2012 - Visual C++ 11.0
                - 2010 - Visual C++ 10.0
                - 2008 - Visual C++  9.0
                - 2005 - Visual C++  8.0
                - 2003 - Visual C++  7.1
                  0000 - Do not use any VS to set up the environment, I will set it up by myself
      <arch> - Target architecture. Can be one of the following: x86, x64, arm

Talks

Publications

Others about Mach7

Projects using Mach7

  • Yodl: a VHDL frontend for Yosys
  • Arrow: Arrow is a fast (as or faster than C) general-purpose programming language. It does not employ a garbage collector and has minimal runtime overhead.

License

Mach7 is licensed under the BSD License.

Support

If you have any question about Mach7 or have trouble using it, the best way to get answers is to post an issue and label it as Question. This will contribute to our poor man's FAQ and hopefully help others with a similar question. I get notifications about new issues and usually respond within the same day. If you prefer not to discuss your question on GitHub, feel free to send me a private email (note there is a + in the email address).

Call for Help

We are looking for contributors to the project. If you are a student taking a programming languages class or any other class that would require you to write a small compiler or interpreter, we would love you try Mach7 for the job. We promise to help with any issues you might have with the library.

Known bugs and limitations

Right now, there are several experimental headers that one would need to include to enable one or the other syntax to work. This is a work in progress, so before you start working with a particular syntax, check examples with that syntax and make note of which of headers they include. We will clear this eventually leaving only one header, but at the moment it is a mess, and the most intuitive match.hpp is probably not the header you want as it represents older experiments. The most recent experimentation and the header you are probably looking for is mach7/type_switchN-patterns-xtl.hpp.

The library is not yet suitable for multi-threaded environment. Lock-free version of vtbl-map is in the works.

Please refrain from using solution or project files checked in here. They are not in sync with most recent changes to directory structure and are difficult to maintain. They will ultimately be replaced with a less verbose system (likely CMake), and in the meantime please use build.bat to build tests on Windows.

For the most up-to-date list of known issues see Mach7 Issues.

Owner
Yuriy Solodkyy
“Why join the navy if you can be a pirate?”
Yuriy Solodkyy
Comments
  • No compile time complaint where there should be one

    No compile time complaint where there should be one

    Hi Yuriy,

    I played around with compile-lambda-a.cpp and added a new function whose purpose is to replace every string in any lambda term with "foobar". This makes use of a nested Match {...} EndMatch construct. The full version of this file is available at a gist that I uploaded.

    The relevant parts are given here:

    void change_vars(Term& t) {
        var<Var&>  v;
        var<Term&> t1, t2;
        var<std::string> s;
    
        Match(t)
        {
            Case(C<Var>(s)) { return; }
            Case(C<Abs>(&v,&t1)) {
                ((Var &) v).name = std::string("foobar");
    
                // "Match(t1) {" instead of the line below
                // produces a SIGSEGV. Why is that?
                Match((Term &) t1){
                    Case(C<Var>(v)) {
                        ((Var &) v).name = std::string("foobar");
                        return;
                    }
                    Otherwise() { return; }
                } EndMatch
    
                change_vars(t1);
                return ;
            }
            Case(C<App>(&t1,&t2)) {
                change_vars(t1);
                change_vars(t2);
                return ;
            }
        }
        EndMatch
    
        return;
    }
    

    I know by now, that the instanciation of the var template produces structs with appropriately overloaded conversion operators. But in the context of the Match statement unambiguous type deduction should not be working and thus the compiler should produce an error when it encountered Match(t1){ (see comment in above code block). But that does not happen.

    With Match(t1) instead of the correct Match((Term &) t1) the code compiles, but quickly produces a SIGSEGV. Why does it even compile?

    Best regards Florian

  • Need clarification on how to mutate Boost.Variants

    Need clarification on how to mutate Boost.Variants

    Although I try hard, I cannot figure out how I can use Mach7 to switch on a mutable variant in order to mutate its contents. The following is how I solve my problem in a 'traditional' way:

    struct M{ char im = 0; };
    struct N{ char in = 0; };
    typedef boost::variant<M, N> VM;
    
    void visit(VM& vm)
    {
      if(M* m = boost::get<M>(&vm))
        m->im = 'm';
      else if (N* n = boost::get<N>(&vm))
        n->in = 'n';
    }
    

    How am I suppose to do the same with Mach7? I was only able to come up with this:

    void visit7(VM& vm)
    {
      mch::var<M&> m;
      mch::var<N&> n;
    
      Match(vm)
      {
        Case(mch::C<M>(m))
        {
          M* mp = m.m_value;
          mp->im = 'm';
        }
        Case(mch::C<N>(n))
        {
          N* np = n.m_value;
          np->in = 'n';
        }
      }
      EndMatch
    }
    

    But I suppose there must be a better way. Can you show me how it is intended to be used?

  • a safer addition to address.hpp

    a safer addition to address.hpp

    This is a it safer alternative to https://github.com/solodon4/Mach7/pull/46. It only works for T*, std::unique_ptr<T> and std::shared_ptr<T>. And it can be extended by users by means of specializing the new trait.

  • Linker errors when building unit tests

    Linker errors when building unit tests

    This occurs with both CMake and the Bakefile system I'm working on:

    [6/172] Linking CXX executable unit/example01
    FAILED: : && /home/ryan/stuff/Downloads/clang+llvm-3.6.0-x86_64-linux-gnu/bin/clang++   -fcolor-diagnostics   unit/CMakeFiles/example01.dir/example01.cpp.o  -o unit/example01  -rdynamic && :
    unit/CMakeFiles/example01.dir/example01.cpp.o: In function `mch::vtblmap<mch::type_switch_info>::get(void const*)':
    ../unit/example01.cpp:(.text._ZN3mch7vtblmapINS_16type_switch_infoEE3getEPKv[_ZN3mch7vtblmapINS_16type_switch_infoEE3getEPKv]+0xd3): undefined reference to `mch::vtblmap<mch::type_switch_info>::update(long)'
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    This happens when linking pretty much any of the tests.

  • Boost variant adaptor is broken: which() may return 0

    Boost variant adaptor is broken: which() may return 0

    The current implementation of vtblmap4.hpp initialises and assumes vtbl indexes are not 0. The boost adaptor may return a vtbl index of 0 when storing the first type of the variant.

    1. https://github.com/solodon4/Mach7/blob/40f062d21d721e251ba15c5e8e99068129a6bacf/code/mach7/vtblmap4.hpp#L253
    2. https://github.com/solodon4/Mach7/blob/40f062d21d721e251ba15c5e8e99068129a6bacf/code/mach7/vtblmap4.hpp#L264
    3. https://github.com/solodon4/Mach7/blob/40f062d21d721e251ba15c5e8e99068129a6bacf/code/mach7/vtblmap4.hpp#L270
    4. https://github.com/solodon4/Mach7/blob/40f062d21d721e251ba15c5e8e99068129a6bacf/code/mach7/adapters/boost/adapt_boost_variant.hpp#L62

    This results in an error when first matching against an index 0 and then having a collision. Which will reuse the cache-entry with a dirty switch_info.

    I see three fixes:

    1. Boost adaptor: change code to p->which() + 1;
    2. Initialize cache entries with -1 value instead of 0. (or use some value outside the 48-bit pointer range)
    3. Add a dirty flag to the cache entry to test isOccupied correctly.

    I think option 2 is the best if possible. Option 1 keeps the bug around for other adaptors. Option 3 has a clear overhead.

    Minimal example and pull request follow.

  • problems building unit tests with make

    problems building unit tests with make

    I can't build and execute unit tests on Red Hat Linux using make.

    Top-level Makefile contains like:

    # Create a list of source files.
    SOURCES  = $(shell ls *.cpp)
    

    But ls *.cpp is not a valid bash command, and I get an error. You probably meant either find -name *.cpp or find -maxdepth 1 -name *.cpp, but I do not know which one.

    If I fix this, and then run make test, I get a bash error:

    basename: extra operand `comp.clang.hpp'
    Try `basename --help' for more information.
    ======================================== [ *.exe ]
    /bin/sh: line 17: ./*.exe: No such file or directory
    
  • fix Travis CI and add more cases

    fix Travis CI and add more cases

    The reason travis ci cannot pass is that xcode develop toolchain is not installed by default.

    this pr use osx_image: xcode10, which has installed xcode.

    https://travis-ci.org/FirstLoveLife/Mach7/builds/502937900

  • Error while building

    Error while building

    I am getting the following error while doing cmake --build . :

    In file included from /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/algebraic.cpp:45:0:
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../match.hpp:946:9: note: #pragma message: Default pattern matching syntax is: G
       XTL_MESSAGE("Default pattern matching syntax is: G")
             ^
    In file included from /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/../metatools.hpp:47:0,
                     from /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/bindings.hpp:48,
                     from /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../unisyn.hpp:49,
                     from /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../match.hpp:111,
                     from /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/algebraic.cpp:45:
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/primitive.hpp:470:82: error: invalid use of ‘this’ at top level
         template <typename T> bool operator()(T&& t) const noexcept_when(noexcept_of(this->m_pat(std::forward<T>(t)))) { return m_pat(std::forward<T>(t)
                                                                                      ^
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/../config.hpp:345:37: note: in definition of macro ‘noexcept_when’
     #define noexcept_when(...) noexcept(__VA_ARGS__)
                                         ^
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/primitive.hpp:470:70: note: in expansion of macro ‘noexcept_of’
         template <typename T> bool operator()(T&& t) const noexcept_when(noexcept_of(this->m_pat(std::forward<T>(t)))) { return m_pat(std::forward<T>(t)
                                                                          ^
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/primitive.hpp:491:72: error: invalid use of ‘this’ at top level
         operator const result_type&() const noexcept_when(noexcept_of(eval(this->m_pat))) { return eval(this->m_pat); } // FIX: avoid implicit conversio
                                                                            ^
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/../config.hpp:345:37: note: in definition of macro ‘noexcept_when’
     #define noexcept_when(...) noexcept(__VA_ARGS__)
                                         ^
    /home/mnciitbhu/Git_Clones/Mach7/code/test/unit/../../patterns/primitive.hpp:491:55: note: in expansion of macro ‘noexcept_of’
         operator const result_type&() const noexcept_when(noexcept_of(eval(this->m_pat))) { return eval(this->m_pat); } // FIX: avoid implicit conversio
                                                           ^
    unit/CMakeFiles/algebraic.dir/build.make:54: recipe for target 'unit/CMakeFiles/algebraic.dir/algebraic.cpp.o' failed
    make[2]: *** [unit/CMakeFiles/algebraic.dir/algebraic.cpp.o] Error 1
    CMakeFiles/Makefile2:143: recipe for target 'unit/CMakeFiles/algebraic.dir/all' failed
    make[1]: *** [unit/CMakeFiles/algebraic.dir/all] Error 2
    Makefile:75: recipe for target 'all' failed
    make: *** [all] Error 2
    

    Am I missing anything?

  • Does Mach7 switch on heterogenous interfaces?

    Does Mach7 switch on heterogenous interfaces?

    I tested that the library for the support of boost::variant, and the simple example works fine, after I defined all the template specializations as per your example. However, I somehow got the expectation that I should be able to use the switch with two variants, like this:

    void test(variant<X, Y, Z> vx, variant<M, N> vm)
    {
        var<X> x; var<Y> y; var<Z> z;
        var<M> m; var<N> n;
    
        Match(vx, vm)
        {
            Case(C<X>(x), C<M>(m)) use(x, m);
            Case(C<Y>(y), C<M>(m)) use(y, m);
            // etc.
        }
        EndMatch
    }
    

    This fails to compile with classical meta-programming errors, but before I analyze them in detail, I wanted to check with you if my use case is even supposed to work?

    Is Mach7 intended to switch on multiple heterogeneous types? Or is it just a bug in the implementation? Or perhaps my bug?

  • [maybe bug] Subtype Dynamic Cast failing inexplicably.

    [maybe bug] Subtype Dynamic Cast failing inexplicably.

    I have several different functions using Match/Case on the same type hierarchy, but which accept references to certain subgraphs of that hierarchy. I noticed that some Cases were not matching as expected, so I uncommented the debugging line in subtype_dynamic_cast from xtl.hpp.

    My stringify function is being used to serialize ASTs, and accepts a reference to a Node (the root of the type DAG), since it needs to be able to handle any node and has a void return type. In this case, the debug print shows:

    subtype_dynamic_cast<PKN4GPSM7PolygonE>(PKN4GPSM4NodeE) = 0x102813d00
    

    When fed a Polygon. However, matching on the same Polygon (in a context where the reference is to a Expr, an intermediate type between Polygon and Node), I get:

    subtype_dynamic_cast<PKN4GPSM7PolygonE>(PN4GPSM4ExprINS_7SurfaceENS_6AnyValEEE) = 0x0
    

    Nonetheless, my own debug print of the typeid() shows N4GPSM7PolygonE.

  • Added CaseInT macro in order to provide a working Case-Statement inside of Template definitions

    Added CaseInT macro in order to provide a working Case-Statement inside of Template definitions

    Background:

    I wanted to be able to build type predicates without the use of preprocessor macros

    template<typename T> struct makeTypePredicate {
        bool operator()(const AstNode *n){
            Match(n){
                CaseInT(mch::C<T>()){ return true; }
            } EndMatch;
    
            return false;
        }
    };
    
  • Stand-alone with C++17 std library, no boost

    Stand-alone with C++17 std library, no boost

    I was wondering if there's any plan to making Mach7 stand-alone with the introduction of std::variant and std::visit in C++, in comparison to boost::variant currently used on master. I briefly searched open issues but maybe I missed the relevant conversation.

    Is there any additional dependencies on boost except variant?

  • Case macro using C++17 structured bindings.

    Case macro using C++17 structured bindings.

    Discussion in #67 and https://github.com/solodon4/Mach7/blob/master/code/test/unit/example04-smart-ptr.cpp notes that binding a reference from a smart pointer is unwieldy due to poor language support for proxies.

    It seems that being able to unpack directly into the target variables via structured bindings would make for a much cleaner solution.

    Are there any major hurdles in the existing implementation to doing this?

  • Mixing polymorphism and templates.

    Mixing polymorphism and templates.

    I'm working on a statically type-checked DSL. An expression node of type T has type Expr<T>, and definition of T itself (representing a literal) is something like class T : Expr<T>. There are a handful of Expr-subclasses that still have unbound type parameters (i.e. Let<U,T> binds variables of type U and returns a value of type T).

    I would like to, at a minimum, be able to pattern match over bounded sets of possible U and T without resorting to (manual) copy-paste.

    The annoying, but reasonably scalable for a small set of types, solution would be a copy-paste macro.

    The nice and extensible solution would be some ability to pattern match based on a variance specification for template arguments: if A is a subtype of B, then being able to match an instance of Expr<A> in a pattern that specifies Expr<B> would be ideal (in Scala notation, the pattern would be for Expr<+B>).

    I suspect I'm not the only person who would like to be able to do something like this, and I'm wondering what the obstacles are to implementation.

  • [Question] Reader/Writer Locks

    [Question] Reader/Writer Locks

    I am working on a concurrent implementation of your C++ Pattern Matching Library. Currently I am working with the vtblmap3st file using reader/writer locks to see if this out performs a single lock. I have a question whether or not locking/unlocking the shared and non-shared locks where the reference to the pointer ce is returned is safe, or this could corrupt the data in the cache.

  • [Segfault] when binding `var<vector<type *>>` to class member of the same type

    [Segfault] when binding `var>` to class member of the same type

    Env: clang++ with clang++ --version:

    clang version 3.8.0 (tags/RELEASE_380/final)
    Target: x86_64-unknown-linux-gnu
    Thread model: posix
    InstalledDir: /usr/sbin
    

    Description

    This code produces the error

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff6121d54 in __memmove_ssse3_back () from /usr/lib/libc.so.6
    

    at this line. As you can see params is an instance of the var template which I'm trying to fill with a copy of the member argv_ of the ExpFunc object. The type of argv is vector<Expression*> and argv_ is stored as non-pointer, non-reference in ExpFunc. params was instanciated as follows:

    var<vector<Expresson *>> params;
    

    You can find the whole test here. I deleted most of the other unit tests and the respective include files in order to make sure that the error arises from a use of Mach7.

  • Nested patterns and scalars

    Nested patterns and scalars

    Is it possible to mix instances of var and nested patterns in the binding part of a constructor pattern? For example, is the following code allowed:

    Case(C<ExpLogical>(
             C<ExpRelation>(
                 C<ExpCharacter>(charVal),
                 C<ExpName>(name),
                 relOp),
             C<ExpAttribute>(attrName),
             logOp)){
    

    where attrName, name, charVal, logOp and relOp are instances of the var template and Exp* have the layout:

    namespace mch {
        template <> struct bindings<ExpUNot> {
            Members(ExpUNot::operand1_);
        };
    
        template <> struct bindings<ExpCharacter> {
            Members(ExpCharacter::value_);
        };
    
        template <> struct bindings<ExpAttribute> {
            Members(ExpAttribute::name_);
        };
    
        template <> struct bindings<ExpLogical> {
            Members(ExpLogical::operand1_,
                    ExpLogical::operand2_,
                    ExpLogical::fun_);
        };
    
        template <> struct bindings<ExpFunc> {
            Members(ExpFunc::name_,
                    ExpFunc::argv_);
        };
    
        template <> struct bindings<ExpName> {
            //TODO: add prefix
            Members(//ExpName::prefix_, // unique_ptr<ExpName>
                    ExpName::name_,
                    ExpName::indices_);
        };
    
        template <> struct bindings<ExpRelation> {
            Members(ExpRelation::operand1_,
                    ExpRelation::operand2_,
                    ExpRelation::fun_);
        };
    };
    

    Here some Context. I need to search an Expression AST for a very specific pattern. Without the ExpRelation::fun_ and ExpLogical::fun_ bindings it worked quite well, but when I first began to experiment with the first code snippet instead of the simpler

    Case(C<ExpLogical>(
             C<ExpRelation>(
                 C<ExpCharacter>(charVal),
                 C<ExpName>(name)),
             C<ExpAttribute>(attrName))){
    

    no pattern seemed to match anymore.

Simple header only pattern matching for c++14

Simple, Extensible C++ Pattern Matching Library I have recently been looking at Haskell and Rust. One of the things I wanted in C++ from those languag

Nov 22, 2022
A portable fork of the high-performance regular expression matching library

Vectorscan? A fork of Intel's Hyperscan, modified to run on more platforms. Currently ARM NEON/ASIMD is 100% functional, and Power VSX are in developm

Nov 15, 2022
Functional C++ iterator library

iter (alpha) Functional C++20 iterator library. Godbolt demo Small, single header, feature-rich, functional C++20 iterator library that aims to be sim

Jun 5, 2022
ServiceLocator - Service Locator Pattern Header-Only Library

Service Locator Very fast, header-only C++ Service Locator Pattern library What is the Service Locator Pattern The Service Locator Pattern is a design

Feb 21, 2022
PLP Project Programming Language | Programming for projects and computer science and research on computer and programming.
PLP Project Programming Language | Programming for projects and computer science and research on computer and programming.

PLPv2b PLP Project Programming Language Programming Language for projects and computer science and research on computer and programming. What is PLP L

Aug 20, 2022
Pan-Genomic Matching Statistics
Pan-Genomic Matching Statistics

SPUMONI Pan-genomic Matching Statistics for Targeted Nanopore Sequencing Based on MONI: A MEM-finder with Multi-Genome References. MONI index uses the

Aug 27, 2022
fuzzy matching selection gui

fm === fm provides a gui to select an item from a list using a fuzzy matching algorithm. When an item is selected, it is sent to the plumber `send` po

Nov 1, 2022
Distance matching plugin

Distance Matching This plug-in is custom implementation of the Distance Matching technique which was shown by Laurent Delayen at Nucl.ai 2016. In two

Nov 14, 2022
An in-progress matching decompilation of Final Fantasy VII For the PSX.

FFVII An in-progress decompilation of the original US release of Final Fantasy VII on the PSX. Building (Linux) Install build dependencies The build p

Oct 4, 2022
K-Closest Points and Maximum Clique Pruning for Efficient and Effective 3-D Laser Scan Matching (RA-L 2022)
K-Closest Points and Maximum Clique Pruning for Efficient and Effective 3-D Laser Scan Matching (RA-L 2022)

KCP The official implementation of KCP: K-Closest Points and Maximum Clique Pruning for Efficient and Effective 3D Laser Scan Matching, accepted for p

Oct 1, 2022
Bringing the power, stability and functional capabilities of C++ to Python.

going-native-py Bringing the power, stability and functional capabilities of C++ to Python. This is just a get your hands dirty approach and should be

May 22, 2021
A concatenative functional language to be used as a sidekick for the mlatu language

gerku _, | | __ _, ___ ,_ __ | | __ _, _, /\___ / _` | / _ \| '__)| |

Jan 14, 2022
A bytecode interpreter for statically typed functional languages.

A bytecode interpreter for statically typed functional languages.

Dec 25, 2021
Flutter-Clock-and-Reminder-App - a highly functional clock and reminder app developed on flutter framework.

clock_app A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if thi

Aug 4, 2022
A fully-functional open source and open hardware mechanical USB computer keyboard with only three keys!
A fully-functional open source and open hardware mechanical USB computer keyboard with only three keys!

threeboard threeboard is a fully-functional open source and open hardware mechanical USB computer keyboard with only three keys. It supports multiple

Nov 15, 2022
ArkScript is a small, fast, functional and scripting language for C++ projects
ArkScript is a small, fast, functional and scripting language for C++ projects

ArkScript Documentation Discord server: invite link, to discuss the specification of the language and receive help Modules Nota bene: the project is r

Nov 27, 2022
A modern and functional replacement for the About Windows dialog
A modern and functional replacement for the About Windows dialog

Modern Winver A modern and more functional replacement for the About Windows screen powered by UWP and RegistryRT, providing details on Windows and yo

Nov 26, 2022
Somewhat functional dynamically typed language
Somewhat functional dynamically typed language

Wellang About This is a project originally started by Tristan Wellman(read CONTRIBUTING.md for contribution info). This is a high level assembly langu

Nov 13, 2022
Hello from pattern-f.

TQ-pre-jailbreak A PRE-jailbreak for iOS 14.0 ~ iOS 14.3 on all devices. Generally speaking, jailbreak starts from an arbitrary kernel r/w vulnerabili

Dec 1, 2022