https://github.com/Hirrolot/datatype99 Skip to content Sign up * Why GitHub? Features - + Mobile - + Actions - + Codespaces - + Packages - + Security - + Code review - + Project management - + Integrations - + GitHub Sponsors - + Customer stories - + Security - * Team * Enterprise * Explore + Explore GitHub - Learn & contribute + Topics - + Collections - + Trending - + Learning Lab - + Open source guides - Connect with others + The ReadME Project - + Events - + Community forum - + GitHub Education - + GitHub Stars program - * Marketplace * Pricing Plans - + Compare plans - + Contact Sales - + Nonprofit - + Education - [ ] [search-key] * # In this repository All GitHub | Jump to | * No suggested jump to results * # In this repository All GitHub | Jump to | * # In this user All GitHub | Jump to | * # In this repository All GitHub | Jump to | Sign in Sign up {{ message }} Hirrolot / datatype99 * Watch 3 * Star 145 * Fork 4 C99 with sum types MIT License 145 stars 4 forks Star Watch * Code * Issues 0 * Pull requests 0 * Actions * Projects 0 * Security * Insights More * Code * Issues * Pull requests * Actions * Projects * Security * Insights master 2 branches 1 tag Go to file Code Clone HTTPS GitHub CLI [https://github.com/H] Use Git or checkout with SVN using the web URL. [gh repo clone Hirrol] Work fast with our official CLI. Learn more. * Open with GitHub Desktop * Download ZIP Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Go back Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Go back Launching Xcode If nothing happens, download Xcode and try again. Go back Launching Visual Studio If nothing happens, download the GitHub extension for Visual Studio and try again. Go back Latest commit @Hirrolot Hirrolot Update CHANGELOG.md ... 12b15de Feb 4, 2021 Update CHANGELOG.md 12b15de Git stats * 50 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .github/workflows Run scripts/test.sh in the CI Feb 4, 2021 examples Epilepsy -> Metalang99 Feb 4, 2021 metalang99 @ 3cbe5cb Epilepsy -> Metalang99 Feb 4, 2021 scripts Epilepsy -> Metalang99 Feb 4, 2021 .clang-format Epilepsy -> Metalang99 Feb 4, 2021 .gitignore Initial commit Nov 12, 2020 .gitmodules Epilepsy -> Metalang99 Feb 4, 2021 CHANGELOG.md Update CHANGELOG.md Feb 4, 2021 LICENSE Initial commit Nov 12, 2020 README.md Epilepsy -> Metalang99 Feb 4, 2021 datatype99.h Epilepsy -> Metalang99 Feb 4, 2021 tests.c Epilepsy -> Metalang99 Feb 4, 2021 View code README.md datatype99 CI Support me on Patreon datatype99 is a header-only library that augments C99 with sum types. It looks like this: [ examples/binary_tree.c ] // Sums all nodes of a binary tree. #include #include datatype( BinaryTree, (Leaf, int), (Node, struct BinaryTree *, int, struct BinaryTree *) ); int sum(const BinaryTree *tree) { match(*tree) { of(Leaf, x) { return *x; } of(Node, lhs, x, rhs) { return sum(*lhs) + *x + sum(*rhs); } } } #define TREE(tree) ((BinaryTree *)(BinaryTree[]){tree}) #define NODE(left, number, right) TREE(Node(left, number, right)) #define LEAF(number) TREE(Leaf(number)) int main(void) { const BinaryTree *tree = NODE(NODE(LEAF(1), 2, NODE(LEAF(3), 4, LEAF(5))), 6, LEAF(7)); printf("%d\n", sum(tree)); } Output 28 ... and it compiles in <0.2 secs -- no slowdown of your development workflow. Table of contents * Highlights * Installation * Usage * Syntax and semantics + EBNF syntax + Semantics o datatype99 o match99 o of99 o matches99 * Credits Highlights * Type-safe. Unlike manually written tagged unions, datatype99 is type-safe: normally you cannot access invalid data or construct an invalid variant. Pattern matching is exhaustive too. * Pure C99. No external tools are required; datatype99 is implemented using only preprocessor macros. * Zero boilerplate. datatype99 deals with all the dirty stuff. * Can be used everywhere. Literally everywhere provided that you have a standard-confirming C99 preprocessor. Even on freestanding environments. * Intuitive. You already know how to use it! Installation $ git clone https://github.com/Hirrolot/datatype99.git --recursive Then add datatype99 and datatype99/metalang99/include to your include paths. To use datatype99, just #include beforehand. No additional setup is needed: datatype99 is implemented using only preprocessor macros. To speed up compilation, consider using precompiled headers and -ftrack-macro-expansion=0 (GCC-only). The last option is especially useful because it tells GCC not to print big bullshit macro errors. If you do not want the shortened versions to appear (e.g., datatype and match instead of datatype99 and match99), define DATATYPE99_NO_ALIASES before #include . Usage A sum type is created using the datatype macro. I guess you have already caught the syntax but actually there exist one more kind of a variant: an empty variant which is expressed simply as (Foo). It holds no data. Pattern matching is likewise intuitive. Just two brief notes: * To match an empty variant, write of(Foo) { ... }. * To match the default case, i.e. when all other cases failed, write otherwise { ... }. Happy hacking! Syntax and semantics Having a well-defined semantics of the macros, you can write an FFI which is quite common in C. EBNF syntax ::= "datatype99(" { "," }+ ")" ; ::= "(" [ { "," }+ ] ")" ; ::= ; ::= ; ::= "match99(" ")" { }+ ; ::= "matches99(" "," ")" ; ::= "of99(" [ { "," }+ ] ")" ; ::= "otherwise99" ; Semantics datatype99 This macro accepts a sum type name as a first argument and the rest of arguments shall be comma-separated variants. 1. For each non-empty variant, the following type definition is generated (the metavariable ranges over a corresponding variant's types): typedef struct { 0 _0; ... N _N; } ; 2. For each non-empty variant, the following type definitions to types of each field of are generated: typedef 0 _0; ... typedef N _N; 3. For each variant, the following type definition to a corresponding sum type is generated: typedef struct SumT; 4. For each sum type, the following tagged union is generated (inside the union, only fields to structures of non-empty variants are generated): typedef struct { enum { 0Tag, ..., NTag } tag; union { char dummy; 0 0; ... N N; } data; } ; 5. For each variant, the following function called a value constructor is generated: inline static (...) { /* ... */ } match99 This macro implements pattern matching for an instance of a sum type. It accepts an expression of a sum type as a single argument. Afterwards, a chain of arms shall follow. match99 has the expected semantics: it tries to match the given instance of a sum type with the given variants, and, if a match has succeeded, it executes the corresponding statement and moves down to the next instruction. If all matches have failed, it executes the statement after otherwise99 and moves down to the next instruction. of99 This macro accepts a variant name as a first argument and the rest of arguments comprise a list of variable names. Each variable name is a pointer to a corresponding data of the variant (e.g., let there be (Foo, T1, T2) and of99(Foo, x, y), then x has the type T1 * and y is T2 *). To match an empty variant, write of99(Bar). matches99 This macro just tests an instance of a sum type for a given variant. If the given instance corresponds to the given variant, it expands to truthfulness, otherwise, it expands to falsehood. Credits Thanks to Rust and ML for their implementations of sum types. About C99 with sum types Resources Readme License MIT License Releases 1 v0.1.0 Latest Feb 4, 2021 Packages 0 No packages published Languages * C 99.3% * Shell 0.7% * (c) 2021 GitHub, Inc. * Terms * Privacy * Security * Status * Docs * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time. You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.