├── .clang-format ├── .github └── workflows │ └── c-cpp.yml ├── .gitignore ├── .gitmodules ├── .readthedocs.yaml ├── ARCHITECTURE.md ├── CHANGELOG.md ├── CMakeLists.txt ├── CONTRIBUTING.md ├── Doxyfile ├── LICENSE ├── README.md ├── bench ├── 100_call.c ├── 100_v.c ├── README.md ├── compare_25_items.c ├── filter_map.c ├── list_of_63_items.c └── many_call_in_arg_pos.c ├── docs ├── Makefile ├── assert.rst ├── bool.rst ├── choice.rst ├── conf.py ├── either.rst ├── gen.rst ├── ident.rst ├── index.rst ├── lang.rst ├── list.rst ├── make.bat ├── maybe.rst ├── nat.rst ├── requirements.txt ├── seq.rst ├── stmt.rst ├── tuple.rst ├── util.rst └── variadics.rst ├── examples ├── .gitignore ├── CMakeLists.txt ├── ackermann.c ├── assert_for_each.c ├── binary_tree.c ├── demo.c ├── duffs_device.c ├── factorial.c ├── lambda_calculus.c ├── overload.c └── rectangle.c ├── idioms.md ├── include ├── metalang99.h └── metalang99 │ ├── assert.h │ ├── bool.h │ ├── choice.h │ ├── control.h │ ├── either.h │ ├── eval │ ├── acc.h │ ├── eval.h │ ├── rec.h │ └── syntax_checker.h │ ├── gen.h │ ├── ident.h │ ├── lang.h │ ├── lang │ └── closure.h │ ├── list.h │ ├── logical.h │ ├── maybe.h │ ├── nat.h │ ├── nat │ ├── dec.h │ ├── div.h │ ├── eq.h │ └── inc.h │ ├── priv │ ├── bool.h │ ├── compiler_specific.h │ ├── tuple.h │ └── util.h │ ├── seq.h │ ├── stmt.h │ ├── tuple.h │ ├── util.h │ └── variadics.h ├── optimization_tips.md ├── scripts ├── bench.sh ├── check-arities.py ├── check-fmt.sh ├── docs.sh ├── fmt.sh ├── open-docs.sh ├── open-spec.sh ├── spec.sh ├── test-all.sh ├── test-examples.sh └── test.sh ├── spec ├── .gitignore ├── references.bib ├── spec.pdf └── spec.tex └── tests ├── .gitignore ├── CMakeLists.txt ├── assert.c ├── bool.c ├── choice.c ├── either.c ├── eval └── rec.c ├── gen.c ├── ident.c ├── lang.c ├── list.c ├── maybe.c ├── metalang99.c ├── nat.c ├── seq.c ├── stmt.c ├── tuple.c ├── util.c └── variadics.c /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: LLVM 3 | 4 | IndentWidth: 4 5 | ContinuationIndentWidth: 4 6 | ColumnLimit: 100 7 | 8 | AllowShortFunctionsOnASingleLine: Empty 9 | AllowAllArgumentsOnNextLine: false 10 | BinPackArguments: false 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | BinPackParameters: true 13 | 14 | AlignConsecutiveMacros: true 15 | AlignAfterOpenBracket: AlwaysBreak 16 | 17 | StatementMacros: ["ML99_EVAL", "ML99_CLANG_PRAGMA", "ML99_GCC_PRAGMA"] 18 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: C/C++ CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | test: 11 | strategy: 12 | matrix: 13 | os: [ubuntu-latest, macos-latest, windows-latest] 14 | include: 15 | - os: ubuntu-latest 16 | compiler: gcc 17 | - os: macos-latest 18 | compiler: clang 19 | - os: windows-latest 20 | compiler: msvc 21 | 22 | runs-on: ${{ matrix.os }} 23 | env: 24 | CC: ${{ matrix.compiler }} 25 | 26 | steps: 27 | - uses: actions/checkout@v2 28 | 29 | - name: Test 30 | run: ./scripts/test-all.sh 31 | 32 | test-tcc: 33 | runs-on: ubuntu-latest 34 | env: 35 | CC: tcc 36 | 37 | steps: 38 | - uses: actions/checkout@v2 39 | 40 | - name: Install TCC 41 | run: sudo apt install tcc 42 | 43 | - name: Test 44 | run: ./scripts/test-all.sh 45 | 46 | test-cxx-stmt: 47 | runs-on: ubuntu-latest 48 | 49 | steps: 50 | - uses: actions/checkout@v2 51 | 52 | - name: Test C++ statement chaining 53 | run: | 54 | g++ tests/stmt.c -o stmt -Iinclude -Wall -Wextra -pedantic -std=c++11 -ftrack-macro-expansion=0 55 | ./stmt 56 | 57 | bench: 58 | runs-on: ubuntu-latest 59 | 60 | steps: 61 | - uses: actions/checkout@v2 62 | 63 | - name: Bench 64 | run: ./scripts/bench.sh 65 | 66 | check-arities: 67 | runs-on: ubuntu-latest 68 | 69 | steps: 70 | - uses: actions/checkout@v2 71 | 72 | - name: Install Doxygen 73 | run: sudo apt install doxygen 74 | 75 | - name: Check arity specifiers 76 | run: python3 scripts/check-arities.py 77 | 78 | check-fmt: 79 | runs-on: ubuntu-latest 80 | 81 | steps: 82 | - uses: actions/checkout@v2 83 | 84 | - name: Download run-clang-format 85 | run: git submodule update --init run-clang-format 86 | 87 | - name: Check code formatting 88 | run: ./scripts/check-fmt.sh 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Doxygen XML output 55 | xml 56 | 57 | # Sphinx output 58 | _build 59 | 60 | # CMake build files 61 | build/ 62 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "run-clang-format"] 2 | path = run-clang-format 3 | url = https://github.com/Sarcasm/run-clang-format 4 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # See . 2 | 3 | version: 2 4 | 5 | build: 6 | os: ubuntu-22.04 7 | tools: 8 | python: "3.12" 9 | 10 | python: 11 | install: 12 | - requirements: docs/requirements.txt 13 | 14 | sphinx: 15 | builder: html 16 | configuration: docs/conf.py 17 | fail_on_warning: true 18 | -------------------------------------------------------------------------------- /ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | _This document describes the high-level architecture of Metalang99._ 4 | 5 | ## Interpreter 6 | 7 | The interpreter interprets the core metalanguage described in the [specification]. 8 | 9 | [specification]: https://github.com/hirrolot/metalang99/blob/master/spec/spec.pdf 10 | 11 | ### `eval/eval.h` 12 | 13 | `eval/eval.h` exposes a single macro `ML99_PRIV_EVAL` which evaluates a given metaprogram. It is implemented as a machine in [continuation-passing style] which is described in the specification too. 14 | 15 | [continuation-passing style]: https://en.wikipedia.org/wiki/Continuation-passing_style 16 | 17 | ### `eval/rec.h` 18 | 19 | `eval/rec.h` contains a macro recursion engine upon which everything executes. 20 | 21 | ## Standard library 22 | 23 | The Metalang99 standard library is a set of functions implemented using the core metalanguage. They are located inside corresponding files listed at the [documentation]'s front page. 24 | 25 | [documentation]: https://metalang99.readthedocs.io/en/latest/ 26 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10.0) 2 | project(metalang99 LANGUAGES C) 3 | 4 | # Fix the warnings about `DOWNLOAD_EXTRACT_TIMESTAMP` in newer CMake versions. 5 | if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") 6 | cmake_policy(SET CMP0135 NEW) 7 | endif() 8 | 9 | add_library(${PROJECT_NAME} INTERFACE) 10 | target_include_directories(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | To introduce changes: 4 | 5 | 1. Fork this repository. 6 | 2. Create your own branch `xxx` from `master`. 7 | 3. Make required changes. 8 | 4. Open a PR to `master` from your `xxx`. 9 | 5. Wait until it gets reviewed. 10 | 11 | To be able to work with low-level stuff such as the interpreter, I highly recommend to first observe the [Cloak Wiki]. 12 | 13 | To be able to work with the metalanguage itself, some basic familiarity with programming language theory is expected. For learning materials, see https://github.com/steshaw/plt. 14 | 15 | [Cloak Wiki]: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms 16 | 17 | Some useful scripts are: 18 | 19 | | Description | Command | 20 | |----------|----------| 21 | | Format all the code base | `./scripts/fmt.sh` | 22 | | Check code formatting | `./scripts/check-fmt.sh` | 23 | | Test only `tests/` | `./scripts/test.sh` | 24 | | Test only `examples/` | `./scripts/test-examples.sh` | 25 | | Test both `tests/` and `examples/` | `./scripts/test-all.sh` | 26 | | Generate the documentation | `./scripts/docs.sh` | 27 | | Open the documentation | `./scripts/open-docs.sh` | 28 | | Generate the specification | `./scripts/spec.sh` | 29 | | Open the specification | `./scripts/open-spec.sh` | 30 | | Run the benchmarks | `./scripts/bench.sh` | 31 | 32 | Happy hacking! 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 hirrolot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bench/100_call.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define F_IMPL(x, y, z) v(x + y + z) 4 | 5 | #define _5 \ 6 | ML99_call(F, v(1), v(2), v(3)), ML99_call(F, v(1), v(2), v(3)), \ 7 | ML99_call(F, v(1), v(2), v(3)), ML99_call(F, v(1), v(2), v(3)), \ 8 | ML99_call(F, v(1), v(2), v(3)) 9 | #define _10 _5, _5 10 | #define _100 _10, _10, _10, _10, _10, _10, _10, _10, _10, _10 11 | 12 | ML99_EVAL(_100) 13 | -------------------------------------------------------------------------------- /bench/100_v.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define _10 \ 4 | v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), \ 5 | v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~), v(~~~~~~~~~~) 6 | #define _100 _10, _10, _10, _10, _10, _10, _10, _10, _10, _10 7 | 8 | ML99_EVAL(_100) 9 | -------------------------------------------------------------------------------- /bench/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarking 2 | 3 | Execute `./scripts/bench.sh` from the root directory to run the benchmarks. 4 | -------------------------------------------------------------------------------- /bench/compare_25_items.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NUMBERS \ 4 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 5 | 6 | ML99_ASSERT(ML99_listEq(v(ML99_natEq), ML99_list(v(NUMBERS)), ML99_list(v(NUMBERS)))); 7 | -------------------------------------------------------------------------------- /bench/filter_map.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define _10 5, 5, 5, 5, 5, 3, 3, 3, 3, 3 4 | #define _50 _10, _10, _10, _10, _10 5 | 6 | #define F_IMPL(x) ML99_if(ML99_natEq(v(x), v(5)), ML99_just(v(x)), ML99_nothing()) 7 | #define F_ARITY 1 8 | 9 | ML99_LIST_EVAL(ML99_listFilterMap(v(F), ML99_list(v(_50, _10, 3, 3, 3)))) 10 | -------------------------------------------------------------------------------- /bench/list_of_63_items.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define NUMBERS \ 4 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \ 5 | 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, \ 6 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 7 | 8 | ML99_EVAL(ML99_list(v(NUMBERS))) 9 | -------------------------------------------------------------------------------- /bench/many_call_in_arg_pos.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define F_IMPL(x) v(x) 4 | 5 | #define CALL ML99_call(F, ML99_call(F, ML99_call(F, v(~~~~~)))) 6 | #define _5 CALL, CALL, CALL, CALL, CALL 7 | #define _10 _5, _5 8 | #define _100 _10, _10, _10, _10, _10, _10, _10, _10, _10, _10 9 | 10 | ML99_EVAL(_100) 11 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/assert.rst: -------------------------------------------------------------------------------- 1 | assert.h 2 | ======== 3 | 4 | .. doxygenfile:: assert.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/bool.rst: -------------------------------------------------------------------------------- 1 | bool.h 2 | ====== 3 | 4 | .. doxygenfile:: bool.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/choice.rst: -------------------------------------------------------------------------------- 1 | choice.h 2 | ======== 3 | 4 | .. doxygenfile:: choice.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | # -- Project information ----------------------------------------------------- 18 | 19 | import subprocess 20 | 21 | subprocess.call("cd .. ; doxygen", shell=True) 22 | 23 | project = 'Metalang99' 24 | copyright = '2021, hirrolot' 25 | author = 'hirrolot' 26 | 27 | # The full version, including alpha/beta/rc tags 28 | release = '1.13.5' 29 | 30 | 31 | # -- General configuration --------------------------------------------------- 32 | 33 | # Add any Sphinx extension module names here, as strings. They can be 34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 35 | # ones. 36 | extensions = ["breathe"] 37 | 38 | # Add any paths that contain templates here, relative to this directory. 39 | templates_path = ['_templates'] 40 | 41 | # List of patterns, relative to source directory, that match files and 42 | # directories to ignore when looking for source files. 43 | # This pattern also affects html_static_path and html_extra_path. 44 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 45 | 46 | 47 | # -- Options for HTML output ------------------------------------------------- 48 | 49 | # The theme to use for HTML and HTML Help pages. See the documentation for 50 | # a list of builtin themes. 51 | # 52 | html_theme = "insipid" 53 | 54 | breathe_projects = {"Metalang99": "../xml"} 55 | breathe_default_project = "Metalang99" 56 | primary_domain = 'c' 57 | highlight_language = 'c' 58 | -------------------------------------------------------------------------------- /docs/either.rst: -------------------------------------------------------------------------------- 1 | either.h 2 | ======== 3 | 4 | .. doxygenfile:: either.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/gen.rst: -------------------------------------------------------------------------------- 1 | gen.h 2 | ===== 3 | 4 | .. doxygenfile:: gen.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/ident.rst: -------------------------------------------------------------------------------- 1 | ident.h 2 | ======= 3 | 4 | .. doxygenfile:: ident.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Metalang99 documentation master file, created by 2 | sphinx-quickstart on Mon Jan 4 08:10:23 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | The Metalang99 Standard Library 7 | =============================== 8 | 9 | The Metalang99 standard library exports a set of macros implemented using the `Metalang99 metalanguage`_. 10 | 11 | Definitions 12 | ----------- 13 | 14 | - A plain macro is a macro whose result can be computed only by preprocessor expansion. 15 | 16 | - A Metalang99-compliant macro is a macro called through `ML99_call`/`ML99_callUneval`, directly or indirectly. To compute its result, the Metalang99 interpreter is needed. 17 | 18 | - A desugaring macro is a convenience macro `X(params...)` which expands to `ML99_call(X, params...)` so that you can invoke `X` as `X(v(1), v(2), v(3))`. Desugaring macros are provided for all public Metalang99-compliant macros. 19 | 20 | Naming conventions 21 | ------------------ 22 | 23 | - Plain macros follow the `SCREAMING_CASE` convention. 24 | - Metalang99-compliant macros follow the `camelCase` convention. 25 | - Macros denoting language terms (defined by `lang.h`) follow the `camelCase` convention. 26 | 27 | Sometimes, there exist two versions of the same macro: one is plain, and the other is Metalang99-compliant. For example, here are two complete metaprograms, one using `ML99_untuple` and the second one using `ML99_UNTUPLE`: 28 | 29 | .. code:: c 30 | 31 | ML99_EVAL(ML99_untuple(v((1, 2, 3)))) 32 | 33 | .. code:: c 34 | 35 | ML99_UNTUPLE((1, 2, 3)) 36 | 37 | Both metaprograms result in `1, 2, 3`. 38 | 39 | Version manipulation macros 40 | --------------------------- 41 | 42 | *The following macros are defined in metalang99.h*. 43 | 44 | `ML99_MAJOR`, `ML99_MINOR`, and `ML99_PATCH` denote the major, the minor, and the patch version numbers, respectively. 45 | 46 | `ML99_VERSION_COMPATIBLE(x, y, z)` and `ML99_VERSION_EQ(x, y, z)` are function-like macros that expand to a constant boolean expression: 47 | 48 | - The former holds iff the current Metalang99 version is at least vx.y.z in a `SemVer`_-compatible way. Thus, if the current version is v1.2.3, then `ML99_VERSION_COMPATIBLE` will hold for v1.2.3, v1.2.6, v1.6.0, but not for v2.5.0 or v3.0.0. 49 | - The latter one holds iff the version is exactly vx.y.z. 50 | 51 | These macros can be used as follows: 52 | 53 | .. code:: c 54 | 55 | #if !ML99_VERSION_COMPATIBLE(1, 2, 3) 56 | #error Please, update your Metalang99 to v1.2.3 or higher! 57 | #endif 58 | 59 | .. toctree:: 60 | :hidden: 61 | 62 | lang 63 | choice 64 | tuple 65 | variadics 66 | list 67 | seq 68 | either 69 | maybe 70 | nat 71 | ident 72 | bool 73 | util 74 | assert 75 | gen 76 | stmt 77 | 78 | Contents 79 | ==================================== 80 | 81 | - `lang.h`_ - The core metalanguage. 82 | - `choice.h`_ - Choice types: `(tag, ...)`. 83 | - `tuple.h`_ - Tuples: `(x, y, z)`. 84 | - `variadics.h`_ - Variadic arguments: `x, y, z`. 85 | - `list.h`_ - Cons-lists. 86 | - `seq.h`_ - Sequences: `(x)(y)(z)`. 87 | - `either.h`_ - A choice type with two cases. 88 | - `maybe.h`_ - An optional value. 89 | - `nat.h`_ - Natural numbers: [0; 255]. 90 | - `ident.h`_ - Identifiers: `[a-zA-Z0-9_]+`. 91 | - `bool.h`_ - Boolean algebra. 92 | - `util.h`_ - Utilitary stuff. 93 | - `assert.h`_ - Static assertions. 94 | - `gen.h`_ - Support for C language constructions. 95 | - `stmt.h`_ - Statement chaining. 96 | 97 | Indices and tables 98 | ==================================== 99 | 100 | * :ref:`genindex` 101 | * :ref:`search` 102 | 103 | .. _Metalang99 metalanguage: https://github.com/hirrolot/metalang99 104 | .. _SemVer: https://semver.org/ 105 | 106 | .. _lang.h: lang.html 107 | .. _choice.h: choice.html 108 | .. _tuple.h: tuple.html 109 | .. _variadics.h: variadics.html 110 | .. _list.h: list.html 111 | .. _seq.h: seq.html 112 | .. _either.h: either.html 113 | .. _maybe.h: maybe.html 114 | .. _nat.h: nat.html 115 | .. _ident.h: ident.html 116 | .. _bool.h: bool.html 117 | .. _util.h: util.html 118 | .. _assert.h: assert.html 119 | .. _gen.h: gen.html 120 | .. _stmt.h: stmt.html 121 | -------------------------------------------------------------------------------- /docs/lang.rst: -------------------------------------------------------------------------------- 1 | lang.h 2 | ====== 3 | 4 | .. doxygenfile:: lang.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/list.rst: -------------------------------------------------------------------------------- 1 | list.h 2 | ====== 3 | 4 | .. doxygenfile:: list.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/maybe.rst: -------------------------------------------------------------------------------- 1 | maybe.h 2 | ======= 3 | 4 | .. doxygenfile:: maybe.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/nat.rst: -------------------------------------------------------------------------------- 1 | nat.h 2 | ===== 3 | 4 | .. doxygenfile:: nat.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | breathe >= 4.25.1 2 | insipid-sphinx-theme >= 0.2.8 3 | -------------------------------------------------------------------------------- /docs/seq.rst: -------------------------------------------------------------------------------- 1 | seq.h 2 | ===== 3 | 4 | .. doxygenfile:: seq.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/stmt.rst: -------------------------------------------------------------------------------- 1 | stmt.h 2 | ====== 3 | 4 | .. doxygenfile:: stmt.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/tuple.rst: -------------------------------------------------------------------------------- 1 | tuple.h 2 | ======= 3 | 4 | .. doxygenfile:: tuple.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/util.rst: -------------------------------------------------------------------------------- 1 | util.h 2 | ====== 3 | 4 | .. doxygenfile:: util.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /docs/variadics.rst: -------------------------------------------------------------------------------- 1 | variadics.h 2 | =========== 3 | 4 | .. doxygenfile:: variadics.h 5 | :project: Metalang99 6 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(examples LANGUAGES C) 3 | 4 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 5 | add_compile_options(-Wall -Wextra -pedantic -std=c99 6 | -ftrack-macro-expansion=0) 7 | elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang") 8 | add_compile_options("-fmacro-backtrace-limit=1") 9 | elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 10 | # Enable a standard-conforming C99/C11 preprocessor. 11 | add_compile_options("/std:c11") 12 | elseif(CMAKE_C_COMPILER_ID STREQUAL "TinyCC") 13 | add_compile_definitions(ML99_ALLOW_POOR_DIAGNOSTICS) 14 | endif() 15 | 16 | include_directories(../include) 17 | 18 | add_executable(ackermann ackermann.c) 19 | add_executable(assert_for_each assert_for_each.c) 20 | add_executable(binary_tree binary_tree.c) 21 | add_executable(demo demo.c) 22 | add_executable(duffs_device duffs_device.c) 23 | add_executable(factorial factorial.c) 24 | add_executable(overload overload.c) 25 | add_executable(rectangle rectangle.c) 26 | add_executable(lambda_calculus lambda_calculus.c) 27 | 28 | foreach(TARGET ${BUILDSYSTEM_TARGETS}) 29 | set_target_properties(TARGET PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON) 30 | endforeach() 31 | -------------------------------------------------------------------------------- /examples/ackermann.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ack(m, n) ML99_natMatchWithArgs(m, v(ack_), n) 4 | 5 | #define ack_Z_IMPL(n) ML99_inc(v(n)) 6 | #define ack_S_IMPL(m, n) ML99_natMatchWithArgs(v(n), v(ack_S_), v(m)) 7 | #define ack_S_Z_IMPL(m) ack(v(m), v(1)) 8 | #define ack_S_S_IMPL(n, m) ack(v(m), ack(ML99_inc(v(m)), v(n))) 9 | 10 | ML99_ASSERT_EQ(ack(v(0), v(0)), v(1)); 11 | ML99_ASSERT_EQ(ack(v(0), v(1)), v(2)); 12 | ML99_ASSERT_EQ(ack(v(0), v(2)), v(3)); 13 | 14 | ML99_ASSERT_EQ(ack(v(1), v(0)), v(2)); 15 | ML99_ASSERT_EQ(ack(v(1), v(1)), v(3)); 16 | ML99_ASSERT_EQ(ack(v(1), v(2)), v(4)); 17 | 18 | ML99_ASSERT_EQ(ack(v(2), v(0)), v(3)); 19 | ML99_ASSERT_EQ(ack(v(2), v(1)), v(5)); 20 | ML99_ASSERT_EQ(ack(v(2), v(2)), v(7)); 21 | 22 | int main(void) {} 23 | -------------------------------------------------------------------------------- /examples/assert_for_each.c: -------------------------------------------------------------------------------- 1 | // Asserts multiple expressions at once. 2 | 3 | #include 4 | 5 | #include 6 | 7 | #define ASSERT_FOR_EACH(...) \ 8 | do { \ 9 | ML99_EVAL(ML99_variadicsForEach( \ 10 | ML99_compose(v(ML99_semicoloned), ML99_reify(v(assert))), \ 11 | v(__VA_ARGS__))) \ 12 | } while (0) 13 | 14 | int main(void) { 15 | ASSERT_FOR_EACH(123 == 123, 2 + 2 == 4, "foo"[1] == 'o'); 16 | 17 | /* 18 | * If we combine multiple assertions with the && operator, we will not be able to distinguish 19 | * them if one of them fails apparently: 20 | * 21 | * main: Assertion `123 == 321 && 2 + 2 == 4 && "foo"[1] == 'o' failed. 22 | * assert(123 == 321 && 2 + 2 == 4 && "foo"[1] == 'o'); 23 | */ 24 | 25 | /* 26 | * ... unlike `ASSERT_FOR_EACH` telling us which one has failed: 27 | * 28 | * main: Assertion `123 == 321' failed. 29 | * ASSERT_FOR_EACH(123 == 321, 2 + 2 == 4, "foo"[1] == 'o'); 30 | */ 31 | } 32 | -------------------------------------------------------------------------------- /examples/binary_tree.c: -------------------------------------------------------------------------------- 1 | // Sums all nodes of a binary tree, recursively. 2 | 3 | #include 4 | 5 | #define leaf(x) ML99_choice(v(leaf), x) 6 | #define node(lhs, data, rhs) ML99_choice(v(node), lhs, data, rhs) 7 | 8 | #define sumTree(tree) ML99_match(tree, v(sumTree_)) 9 | #define sumTree_leaf_IMPL(x) v(x) 10 | #define sumTree_node_IMPL(lhs, data, rhs) ML99_add3(sumTree(v(lhs)), v(data), sumTree(v(rhs))) 11 | 12 | /* 13 | * 4 14 | * / \ 15 | * / \ 16 | * / \ 17 | * 2 6 18 | * / \ / \ 19 | * 1 3 5 7 20 | */ 21 | #define TREE node(node(leaf(v(1)), v(2), leaf(v(3))), v(4), node(leaf(v(5)), v(6), leaf(v(7)))) 22 | 23 | ML99_ASSERT_EQ(sumTree(TREE), v(28)); 24 | 25 | int main(void) {} 26 | -------------------------------------------------------------------------------- /examples/demo.c: -------------------------------------------------------------------------------- 1 | // `...` is sometimes used to workaround a TCC bug, see 2 | // . 3 | 4 | #include 5 | 6 | // Compile-time list manipulation: 7 | 8 | // 3, 3, 3, 3, 3 9 | static int five_threes[] = { 10 | ML99_LIST_EVAL_COMMA_SEP(ML99_listReplicate(v(5), v(3))), 11 | }; 12 | 13 | // 5, 4, 3, 2, 1 14 | static int from_5_to_1[] = { 15 | ML99_LIST_EVAL_COMMA_SEP(ML99_listReverse(ML99_list(v(1, 2, 3, 4, 5)))), 16 | }; 17 | 18 | // 9, 2, 5 19 | static int lesser_than_10[] = { 20 | ML99_LIST_EVAL_COMMA_SEP( 21 | ML99_listFilter(ML99_appl(v(ML99_greater), v(10)), ML99_list(v(9, 2, 11, 13, 5)))), 22 | }; 23 | 24 | // Macro recursion: 25 | #define factorial(n) ML99_natMatch(n, v(factorial_)) 26 | #define factorial_Z_IMPL(...) v(1) // `...` due to the TCC's bug. 27 | #define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n))) 28 | 29 | ML99_ASSERT_EQ(factorial(v(4)), v(24)); 30 | 31 | // Overloading on a number of arguments: 32 | typedef struct { 33 | double width, height; 34 | } Rect; 35 | 36 | #define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__) 37 | #define Rect_new_1(x) \ 38 | { x, x } 39 | #define Rect_new_2(x, y) \ 40 | { x, y } 41 | 42 | static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10); 43 | 44 | // ... and more! 45 | 46 | int main(void) { 47 | // Yeah. All is done at compile time. 48 | } 49 | -------------------------------------------------------------------------------- /examples/duffs_device.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Duff's device [1] is a technique to implement loop unrolling through amalgamation of a switch 3 | * statement with a do-while loop. 4 | * 5 | * In this example, we are going to implement automatic generation of Duff's device. 6 | * 7 | * [1]: https://en.wikipedia.org/wiki/Duff's_device 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | 14 | #define DUFFS_DEVICE(unrolling_factor, counter_ty, count, ...) \ 15 | do { \ 16 | if ((count) > 0) { \ 17 | counter_ty DUFFS_DEVICE_n = ((count) + ML99_DEC(unrolling_factor)) / unrolling_factor; \ 18 | switch ((count) % unrolling_factor) { \ 19 | case 0: \ 20 | do { \ 21 | __VA_ARGS__ \ 22 | ML99_EVAL(ML99_callUneval(genCases, ML99_DEC(unrolling_factor), __VA_ARGS__)) \ 23 | } while (--DUFFS_DEVICE_n > 0); \ 24 | } \ 25 | } \ 26 | } while (0) 27 | 28 | #define genCases_IMPL(i, ...) \ 29 | ML99_IF( \ 30 | ML99_NAT_EQ(i, 0), \ 31 | ML99_empty(), \ 32 | ML99_TERMS( \ 33 | v(/* FALLTHROUGH */ case i \ 34 | : __VA_ARGS__), \ 35 | ML99_callUneval(genCases, ML99_DEC(i), __VA_ARGS__))) 36 | 37 | int main(void) { 38 | #define ARRAY_LEN 50 39 | #define UNROLLING_FACTOR 3 40 | 41 | int array[ARRAY_LEN] = { ML99_EVAL(ML99_times(v(ARRAY_LEN), v(5, ))) }; 42 | int *n_ptr = array; 43 | 44 | // Square all the elements in the array. 45 | DUFFS_DEVICE(UNROLLING_FACTOR, int, ARRAY_LEN, { 46 | *n_ptr *= *n_ptr; 47 | n_ptr++; 48 | }); 49 | 50 | for (int i = 0; i < ARRAY_LEN; i++) { 51 | assert(25 == array[i]); 52 | } 53 | } 54 | 55 | /* 56 | The generated Duff's device: 57 | 58 | int DUFFS_DEVICE_n = ((50) + 2) / 3; 59 | switch ((50) % 3) { 60 | case 0: 61 | do { 62 | { 63 | *n_ptr *= *n_ptr; 64 | n_ptr++; 65 | } 66 | case 2: { 67 | *n_ptr *= *n_ptr; 68 | n_ptr++; 69 | } 70 | case 1: { 71 | *n_ptr *= *n_ptr; 72 | n_ptr++; 73 | } 74 | } while (--DUFFS_DEVICE_n > 0); 75 | } 76 | */ 77 | -------------------------------------------------------------------------------- /examples/factorial.c: -------------------------------------------------------------------------------- 1 | // `...` is sometimes used to workaround a TCC bug, see 2 | // . 3 | 4 | #include 5 | 6 | #define factorial(n) ML99_natMatch(n, v(factorial_)) 7 | #define factorial_Z_IMPL(...) v(1) // `...` due to the TCC's bug. 8 | #define factorial_S_IMPL(n) ML99_mul(ML99_inc(v(n)), factorial(v(n))) 9 | 10 | ML99_ASSERT_EQ(factorial(v(0)), v(1)); 11 | ML99_ASSERT_EQ(factorial(v(1)), v(1)); 12 | ML99_ASSERT_EQ(factorial(v(2)), v(2)); 13 | ML99_ASSERT_EQ(factorial(v(3)), v(6)); 14 | ML99_ASSERT_EQ(factorial(v(4)), v(24)); 15 | 16 | int main(void) {} 17 | -------------------------------------------------------------------------------- /examples/lambda_calculus.c: -------------------------------------------------------------------------------- 1 | /* 2 | * An untyped lambda calculus [1] interpreter using De Bruijn indices [2] and normal order 3 | * evaluation strategy [3]. 4 | * 5 | * [1] https://en.wikipedia.org/wiki/Lambda_calculus 6 | * [2] https://en.wikipedia.org/wiki/De_Bruijn_index 7 | * [3] https://en.wikipedia.org/wiki/Evaluation_strategy#Normal_order 8 | */ 9 | 10 | #include 11 | 12 | // Syntactic terms { 13 | 14 | #define var(i) ML99_call(var, i) 15 | #define appl(M, N) ML99_call(appl, M, N) 16 | #define lam(M) ML99_call(lam, M) 17 | 18 | #define var_IMPL(i) v(VAR(i)) 19 | #define appl_IMPL(M, N) v(APPL(M, N)) 20 | #define lam_IMPL(M) v(LAM(M)) 21 | 22 | #define VAR(i) ML99_CHOICE(var, i) 23 | #define APPL(M, N) ML99_CHOICE(appl, M, N) 24 | #define LAM(M) ML99_CHOICE(lam, M) 25 | // } (Syntactic terms) 26 | 27 | // Variable substitution: `M[1=x]` { 28 | 29 | #define subst(M, x) ML99_call(subst, M, x) 30 | 31 | #define subst_IMPL(M, x) substAux_IMPL(M, x, 1) 32 | #define substAux_IMPL(M, x, depth) ML99_callUneval(ML99_matchWithArgs, M, substAux_, x, depth) 33 | 34 | #define substAux_var_IMPL(i, x, depth) \ 35 | ML99_IF( \ 36 | ML99_NAT_EQ(i, depth), \ 37 | v(x), \ 38 | ML99_call(ML99_if, ML99_callUneval(ML99_greater, i, depth), v(VAR(ML99_DEC(i)), VAR(i)))) 39 | #define substAux_appl_IMPL(M, N, x, depth) \ 40 | appl(substAux_IMPL(M, x, depth), substAux_IMPL(N, x, depth)) 41 | #define substAux_lam_IMPL(M, x, depth) \ 42 | lam(ML99_call(substAux, v(M), incFreeVars_IMPL(x), v(ML99_INC(depth)))) 43 | // } (Variable substitution) 44 | 45 | // Increment free variables in `M` { 46 | 47 | #define incFreeVars(M) ML99_call(incFreeVars, M) 48 | 49 | #define incFreeVars_IMPL(M) incFreeVarsAux_IMPL(M, 1) 50 | #define incFreeVarsAux_IMPL(M, depth) ML99_callUneval(ML99_matchWithArgs, M, incFreeVarsAux_, depth) 51 | 52 | #define incFreeVarsAux_var_IMPL(i, depth) \ 53 | ML99_call(ML99_if, ML99_callUneval(ML99_greaterEq, i, depth), v(VAR(ML99_INC(i)), VAR(i))) 54 | #define incFreeVarsAux_appl_IMPL(M, N, depth) \ 55 | appl(incFreeVarsAux_IMPL(M, depth), incFreeVarsAux_IMPL(N, depth)) 56 | #define incFreeVarsAux_lam_IMPL(M, depth) lam(incFreeVarsAux_IMPL(M, ML99_INC(depth))) 57 | // } (Increment free variables) 58 | 59 | // Evaluation { 60 | 61 | #define eval(M) ML99_call(eval, M) 62 | 63 | #define eval_IMPL(M) ML99_callUneval(ML99_match, M, eval_) 64 | #define eval_var_IMPL(i) v(VAR(i)) 65 | #define eval_appl_IMPL(M, N) ML99_callUneval(ML99_matchWithArgs, M, eval_appl_, N) 66 | #define eval_lam_IMPL(M) lam(eval_IMPL(M)) 67 | 68 | #define eval_appl_var_IMPL(i, N) appl(v(VAR(i)), eval_IMPL(N)) 69 | #define eval_appl_appl_IMPL(M, N, N1) \ 70 | ML99_call(ML99_matchWithArgs, eval(appl_IMPL(M, N)), v(eval_appl_appl_, N1)) 71 | #define eval_appl_lam_IMPL(M, N) eval(subst_IMPL(M, N)) 72 | 73 | #define eval_appl_appl_var_IMPL eval_appl_var_IMPL 74 | #define eval_appl_appl_appl_IMPL(M, N, N1) appl(appl_IMPL(M, N), eval_IMPL(N1)) 75 | #define eval_appl_appl_lam_IMPL eval_appl_lam_IMPL 76 | // } (Evaluation) 77 | 78 | // Syntactical equality { 79 | 80 | #define termEq(lhs, rhs) ML99_matchWithArgs(lhs, v(termEq_), rhs) 81 | #define termEq_var_IMPL(i, rhs) termEqPropagate(var, rhs, i) 82 | #define termEq_appl_IMPL(M, N, rhs) termEqPropagate(appl, rhs, M, N) 83 | #define termEq_lam_IMPL(M, rhs) termEqPropagate(lam, rhs, M) 84 | 85 | #define termEqPropagate(term_kind, rhs, ...) \ 86 | ML99_IF( \ 87 | ML99_IDENT_EQ(TERM_, ML99_CHOICE_TAG(rhs), term_kind), \ 88 | ML99_matchWithArgs(v(rhs), v(termEq_##term_kind##_), v(__VA_ARGS__)), \ 89 | ML99_false()) 90 | 91 | #define termEq_var_var_IMPL(j, i) v(ML99_NAT_EQ(i, j)) 92 | #define termEq_appl_appl_IMPL(M, N, M1, N1) ML99_and(termEq(v(M), v(M1)), termEq(v(N), v(N1))) 93 | #define termEq_lam_lam_IMPL(M, M1) termEq(v(M), v(M1)) 94 | 95 | #define TERM_var_var () 96 | #define TERM_appl_appl () 97 | #define TERM_lam_lam () 98 | // } (Syntactical equality) 99 | 100 | #define ASSERT_REDUCES_TO(lhs, rhs) \ 101 | /* Use two interpreter passes: one for `eval(lhs)`, one for `termEq`. Thereby we achieve more \ 102 | * Metalang99 reduction steps available. */ \ 103 | ML99_ASSERT_UNEVAL(ML99_EVAL(termEq(v(ML99_EVAL(eval(v(lhs)))), v(ML99_EVAL(eval(v(rhs))))))) 104 | 105 | // The identity combinator { 106 | 107 | #define I LAM(VAR(1)) 108 | 109 | ASSERT_REDUCES_TO(APPL(I, VAR(5)), VAR(5)); 110 | // } (The identity combinator) 111 | 112 | // The K, S combinators { 113 | 114 | #define K LAM(LAM(VAR(2))) 115 | #define S LAM(LAM(LAM(APPL(APPL(VAR(3), VAR(1)), APPL(VAR(2), VAR(1)))))) 116 | 117 | ASSERT_REDUCES_TO(APPL(APPL(S, K), K), I); 118 | ASSERT_REDUCES_TO(APPL(APPL(APPL(S, K), S), K), K); 119 | 120 | ASSERT_REDUCES_TO(APPL(APPL(APPL(S, K), VAR(5)), VAR(6)), VAR(6)); 121 | ASSERT_REDUCES_TO(APPL(APPL(K, VAR(5)), VAR(6)), VAR(5)); 122 | // } (The K, S combinators) 123 | 124 | // Church booleans { 125 | 126 | #define T LAM(LAM(VAR(2))) 127 | #define F LAM(LAM(VAR(1))) 128 | 129 | #define NOT LAM(APPL(APPL(VAR(1), F), T)) 130 | #define AND LAM(LAM(APPL(APPL(VAR(2), VAR(1)), VAR(2)))) 131 | #define OR LAM(LAM(APPL(APPL(VAR(2), VAR(2)), VAR(1)))) 132 | #define XOR LAM(LAM(APPL(APPL(VAR(2), APPL(NOT, VAR(1))), VAR(1)))) 133 | 134 | #define IF LAM(LAM(LAM(APPL(APPL(VAR(3), VAR(2)), VAR(1))))) 135 | 136 | ASSERT_REDUCES_TO(APPL(NOT, T), F); 137 | ASSERT_REDUCES_TO(APPL(NOT, F), T); 138 | ASSERT_REDUCES_TO(APPL(NOT, APPL(NOT, T)), T); 139 | ASSERT_REDUCES_TO(APPL(NOT, APPL(NOT, F)), F); 140 | 141 | ASSERT_REDUCES_TO(APPL(APPL(AND, T), T), T); 142 | ASSERT_REDUCES_TO(APPL(APPL(AND, T), F), F); 143 | ASSERT_REDUCES_TO(APPL(APPL(AND, F), T), F); 144 | ASSERT_REDUCES_TO(APPL(APPL(AND, F), F), F); 145 | 146 | ASSERT_REDUCES_TO(APPL(APPL(OR, T), T), T); 147 | ASSERT_REDUCES_TO(APPL(APPL(OR, T), F), T); 148 | ASSERT_REDUCES_TO(APPL(APPL(OR, F), T), T); 149 | ASSERT_REDUCES_TO(APPL(APPL(OR, F), F), F); 150 | 151 | ASSERT_REDUCES_TO(APPL(APPL(XOR, T), T), F); 152 | ASSERT_REDUCES_TO(APPL(APPL(XOR, T), F), T); 153 | ASSERT_REDUCES_TO(APPL(APPL(XOR, F), T), T); 154 | ASSERT_REDUCES_TO(APPL(APPL(XOR, F), F), F); 155 | 156 | ASSERT_REDUCES_TO(APPL(APPL(APPL(IF, T), VAR(5)), VAR(6)), VAR(5)); 157 | ASSERT_REDUCES_TO(APPL(APPL(APPL(IF, F), VAR(5)), VAR(6)), VAR(6)); 158 | // } (Church booleans) 159 | 160 | // Church numerals { 161 | 162 | #define ZERO LAM(LAM(VAR(1))) 163 | #define SUCC LAM(LAM(LAM(APPL(VAR(2), APPL(APPL(VAR(3), VAR(2)), VAR(1)))))) 164 | 165 | #define ONE APPL(SUCC, ZERO) 166 | #define TWO APPL(SUCC, ONE) 167 | #define THREE APPL(SUCC, TWO) 168 | #define FOUR APPL(SUCC, THREE) 169 | 170 | #define ADD LAM(LAM(LAM(LAM(APPL(APPL(VAR(4), VAR(2)), APPL(APPL(VAR(3), VAR(2)), VAR(1))))))) 171 | #define MUL LAM(LAM(LAM(LAM(APPL(APPL(VAR(4), APPL(VAR(3), VAR(2))), VAR(1)))))) 172 | 173 | ASSERT_REDUCES_TO(APPL(APPL(ADD, ZERO), ZERO), ZERO); 174 | ASSERT_REDUCES_TO(APPL(APPL(ADD, ZERO), ONE), ONE); 175 | ASSERT_REDUCES_TO(APPL(APPL(ADD, ONE), ZERO), ONE); 176 | ASSERT_REDUCES_TO(APPL(APPL(ADD, ONE), TWO), THREE); 177 | 178 | ASSERT_REDUCES_TO(APPL(APPL(MUL, ZERO), ZERO), ZERO); 179 | ASSERT_REDUCES_TO(APPL(APPL(MUL, ZERO), ONE), ZERO); 180 | ASSERT_REDUCES_TO(APPL(APPL(MUL, ONE), ZERO), ZERO); 181 | ASSERT_REDUCES_TO(APPL(APPL(MUL, TWO), TWO), FOUR); 182 | // } (Church numerals) 183 | 184 | // Church pairs { 185 | 186 | #define PAIR LAM(LAM(LAM(APPL(APPL(VAR(1), VAR(3)), VAR(2))))) 187 | #define FST LAM(APPL(VAR(1), T)) 188 | #define SND LAM(APPL(VAR(1), F)) 189 | 190 | ASSERT_REDUCES_TO(APPL(FST, APPL(APPL(PAIR, VAR(5)), VAR(6))), VAR(5)); 191 | ASSERT_REDUCES_TO(APPL(SND, APPL(APPL(PAIR, VAR(5)), VAR(6))), VAR(6)); 192 | // } (Church pairs) 193 | 194 | // Church lists { 195 | 196 | #define NIL F 197 | #define CONS PAIR 198 | #define IS_NIL LAM(APPL(APPL(VAR(1), LAM(LAM(LAM(F)))), T)) 199 | 200 | #define LIST_1_2_3 APPL(APPL(CONS, VAR(1)), APPL(APPL(CONS, VAR(2)), APPL(APPL(CONS, VAR(3)), NIL))) 201 | 202 | ASSERT_REDUCES_TO(APPL(IS_NIL, NIL), T); 203 | ASSERT_REDUCES_TO(APPL(IS_NIL, LIST_1_2_3), F); 204 | // } (Church lists) 205 | 206 | // Recursion via self-application (or the Y combinator) is perfectly expressible, though when 207 | // executed, it exhausts the Metalang99 recursion engine limit. 208 | 209 | int main(void) {} 210 | -------------------------------------------------------------------------------- /examples/overload.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct { 4 | double width, height; 5 | } Rect; 6 | 7 | #define Rect_new(...) ML99_OVERLOAD(Rect_new_, __VA_ARGS__) 8 | #define Rect_new_1(x) \ 9 | { x, x } 10 | #define Rect_new_2(x, y) \ 11 | { x, y } 12 | 13 | static Rect _7x8 = Rect_new(7, 8), _10x10 = Rect_new(10); 14 | 15 | int main(void) {} 16 | -------------------------------------------------------------------------------- /examples/rectangle.c: -------------------------------------------------------------------------------- 1 | // Computes the area of a rectangle. 2 | 3 | #include 4 | 5 | #define rect(width, height) ML99_tuple(width, height) 6 | #define rectWidth ML99_tupleGet(0) 7 | #define rectHeight ML99_tupleGet(1) 8 | 9 | #define rectArea(rect) ML99_mul(rectWidth(rect), rectHeight(rect)) 10 | 11 | /* 12 | * 15 13 | * +------------------------------+ 14 | * | | 15 | * | | 16 | * | | 7 17 | * | | 18 | * | | 19 | * +------------------------------+ 20 | */ 21 | #define RECTANGLE rect(v(15), v(7)) 22 | 23 | ML99_ASSERT_EQ(rectArea(RECTANGLE), v(15 * 7)); 24 | 25 | int main(void) {} 26 | -------------------------------------------------------------------------------- /idioms.md: -------------------------------------------------------------------------------- 1 | # Idioms 2 | 3 | _This document describes common idioms when using Metalang99, i.e., code patterns that have not been reified into abstractions yet._ 4 | 5 | ## Detecting a keyword followed by parentheses 6 | 7 | To detect something like `abracadabra(1, 2, 3)`, follow this simple pattern: 8 | 9 | ```c 10 | #define DETECT_ABRACADABRA(x) ML99_IS_TUPLE(ML99_CAT(DETECT_ABRACADABRA_, x)) 11 | #define DETECT_ABRACADABRA_abracadabra(...) () 12 | 13 | // 1 14 | DETECT_ABRACADABRA(abracadabra(1, 2, 3)) 15 | 16 | // 0 17 | DETECT_ABRACADABRA(blah) 18 | ``` 19 | 20 | ## Extracting a value of a keyword followed by parentheses 21 | 22 | To get `1, 2, 3` from `abracadabra(1, 2, 3)`: 23 | 24 | ```c 25 | #define EXTRACT_ABRACADABRA(x) ML99_CAT(EXTRACT_ABRACADABRA_, x) 26 | #define EXTRACT_ABRACADABRA_abracadabra(...) __VA_ARGS__ 27 | 28 | // 1, 2, 3 29 | EXTRACT_ABRACADABRA(abracadabra(1, 2, 3)) 30 | ``` 31 | 32 | ## Interspersing a comma 33 | 34 | To intersperse a comma between one or more elements, put a comma before each element and pass them all to `ML99_variadicsTail`: 35 | 36 | ```c 37 | #define ARRAY_SUBSCRIPTS(array, n) \ 38 | ML99_EVAL(ML99_variadicsTail(ML99_repeat(v(n), ML99_appl(v(GEN_SUBSCRIPT), v(array))))) 39 | #define GEN_SUBSCRIPT_IMPL(array, i) v(, (array)[i]) 40 | #define GEN_SUBSCRIPT_ARITY 2 41 | 42 | // (animals)[0], (animals)[1], (animals)[2] 43 | ARRAY_SUBSCRIPTS(animals, 3) 44 | ``` 45 | -------------------------------------------------------------------------------- /include/metalang99.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_H 2 | #define ML99_H 3 | 4 | #if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL 5 | #error Please, specify /Zc:preprocessor to enable a standard-compliant C99/C++11 preprocessor. 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define ML99_MAJOR 1 25 | #define ML99_MINOR 13 26 | #define ML99_PATCH 5 27 | 28 | #define ML99_VERSION_COMPATIBLE(x, y, z) \ 29 | (ML99_MAJOR == (x) && ((ML99_MINOR == (y) && ML99_PATCH >= (z)) || (ML99_MINOR > (y)))) 30 | 31 | #define ML99_VERSION_EQ(x, y, z) (ML99_MAJOR == (x) && ML99_MINOR == (y) && ML99_PATCH == (z)) 32 | 33 | #endif // ML99_H 34 | -------------------------------------------------------------------------------- /include/metalang99/assert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Static assertions. 4 | * 5 | * For the sake of convenience, this header automatically includes `metalang99/bool.h`. 6 | * 7 | * @note [C99] Any of the following assertion macros must **not** appear on the same line number 8 | * twice with itself as well as with any other Metalang99 assertion macro. 9 | * @note [C11] The following assertion macros expand to `_Static_assert` and, therefore, can be used 10 | * on the same line twice. 11 | */ 12 | 13 | #ifndef ML99_ASSERT_H 14 | #define ML99_ASSERT_H 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | /** 22 | * The same as #ML99_ASSERT but results in a Metalang99 term. 23 | * 24 | * It can be used inside other Metalang99-compliant macros, unlike #ML99_ASSERT, which uses 25 | * #ML99_EVAL internally. 26 | */ 27 | #define ML99_assert(expr) ML99_call(ML99_assert, expr) 28 | 29 | /** 30 | * Like #ML99_assert but compares @p lhs with @p rhs for equality (`==`). 31 | */ 32 | #define ML99_assertEq(lhs, rhs) ML99_call(ML99_assertEq, lhs, rhs) 33 | 34 | /** 35 | * Asserts `ML99_EVAL(expr)` at compile-time. 36 | * 37 | * # Examples 38 | * 39 | * @code 40 | * #include 41 | * 42 | * ML99_ASSERT(v(123 == 123)); 43 | * @endcode 44 | */ 45 | #define ML99_ASSERT(expr) ML99_ASSERT_EQ(expr, ML99_true()) 46 | 47 | /** 48 | * Asserts `ML99_EVAL(lhs) == ML99_EVAL(rhs)` at compile-time. 49 | * 50 | * # Examples 51 | * 52 | * @code 53 | * #include 54 | * 55 | * ML99_ASSERT_EQ(v(123), v(123)); 56 | * @endcode 57 | */ 58 | #define ML99_ASSERT_EQ(lhs, rhs) ML99_ASSERT_UNEVAL((ML99_EVAL(lhs)) == (ML99_EVAL(rhs))) 59 | 60 | /** 61 | * Asserts the C constant expression @p expr; 62 | * [static_assert](https://en.cppreference.com/w/c/error/static_assert) in pure C99. 63 | * 64 | * # Examples 65 | * 66 | * @code 67 | * #include 68 | * 69 | * ML99_ASSERT_UNEVAL(123 == 123); 70 | * @endcode 71 | */ 72 | #define ML99_ASSERT_UNEVAL(expr) ML99_PRIV_ASSERT_UNEVAL_INNER(expr) 73 | 74 | /** 75 | * Asserts that `ML99_EVAL(expr)` is emptiness. 76 | * 77 | * # Examples 78 | * 79 | * @code 80 | * #include 81 | * 82 | * // Passes: 83 | * ML99_ASSERT_EMPTY(v()); 84 | * 85 | * // Fails: 86 | * ML99_ASSERT_EMPTY(v(123)); 87 | * @endcode 88 | */ 89 | #define ML99_ASSERT_EMPTY(expr) ML99_ASSERT_EMPTY_UNEVAL(ML99_EVAL(expr)) 90 | 91 | /** 92 | * Asserts that @p expr is emptiness. 93 | * 94 | * # Examples 95 | * 96 | * @code 97 | * #include 98 | * 99 | * // Passes: 100 | * ML99_ASSERT_EMPTY_UNEVAL(); 101 | * 102 | * // Fails: 103 | * ML99_ASSERT_EMPTY_UNEVAL(123); 104 | * @endcode 105 | */ 106 | #define ML99_ASSERT_EMPTY_UNEVAL(expr) \ 107 | ML99_ASSERT_UNEVAL(ML99_PRIV_CAT(ML99_PRIV_ASSERT_EMPTY_, expr)) 108 | 109 | #ifndef DOXYGEN_IGNORE 110 | 111 | #define ML99_assert_IMPL(expr) v(ML99_ASSERT_UNEVAL(expr)) 112 | #define ML99_assertEq_IMPL(lhs, rhs) v(ML99_ASSERT_UNEVAL((lhs) == (rhs))) 113 | 114 | #ifdef ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE 115 | #define ML99_PRIV_ASSERT_UNEVAL_INNER(expr) _Static_assert((expr), "Metalang99 assertion failed") 116 | #else 117 | // How to imitate static assertions in C99: . 118 | #define ML99_PRIV_ASSERT_UNEVAL_INNER(expr) \ 119 | static const char ML99_PRIV_CAT( \ 120 | ml99_assert_, \ 121 | __LINE__)[(expr) ? 1 : -1] ML99_PRIV_COMPILER_ATTR_UNUSED = {0} 122 | #endif 123 | 124 | #define ML99_PRIV_ASSERT_EMPTY_ 1 125 | 126 | // Arity specifiers { 127 | 128 | #define ML99_assert_ARITY 1 129 | #define ML99_assertEq_ARITY 2 130 | // } (Arity specifiers) 131 | 132 | #endif // DOXYGEN_IGNORE 133 | 134 | #endif // ML99_ASSERT_H 135 | -------------------------------------------------------------------------------- /include/metalang99/bool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Boolean algebra. 4 | */ 5 | 6 | #ifndef ML99_BOOL_H 7 | #define ML99_BOOL_H 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | /** 15 | * Truth. 16 | */ 17 | #define ML99_true(...) ML99_callUneval(ML99_true, ) 18 | 19 | /** 20 | * Falsehood. 21 | */ 22 | #define ML99_false(...) ML99_callUneval(ML99_false, ) 23 | 24 | /** 25 | * Logical negation. 26 | * 27 | * # Examples 28 | * 29 | * @code 30 | * #include 31 | * 32 | * // 1 33 | * ML99_not(v(0)) 34 | * 35 | * // 0 36 | * ML99_not(v(1)) 37 | * @endcode 38 | */ 39 | #define ML99_not(x) ML99_call(ML99_not, x) 40 | 41 | /** 42 | * Logical conjunction. 43 | * 44 | * # Examples 45 | * 46 | * @code 47 | * #include 48 | * 49 | * // 0 50 | * ML99_and(v(0), v(0)) 51 | * 52 | * // 0 53 | * ML99_and(v(0), v(1)) 54 | * 55 | * // 0 56 | * ML99_and(v(1), v(0)) 57 | * 58 | * // 1 59 | * ML99_and(v(1), v(1)) 60 | * @endcode 61 | */ 62 | #define ML99_and(x, y) ML99_call(ML99_and, x, y) 63 | 64 | /** 65 | * Logical inclusive OR. 66 | * 67 | * # Examples 68 | * @code 69 | * #include 70 | * 71 | * // 0 72 | * ML99_or(v(0), v(0)) 73 | * 74 | * // 1 75 | * ML99_or(v(0), v(1)) 76 | * 77 | * // 1 78 | * ML99_or(v(1), v(0)) 79 | * 80 | * // 1 81 | * ML99_or(v(1), v(1)) 82 | * @endcode 83 | */ 84 | #define ML99_or(x, y) ML99_call(ML99_or, x, y) 85 | 86 | /** 87 | * Logical exclusive OR. 88 | * 89 | * # Examples 90 | * 91 | * @code 92 | * #include 93 | * 94 | * // 0 95 | * ML99_xor(v(0), v(0)) 96 | * 97 | * // 1 98 | * ML99_xor(v(0), v(1)) 99 | * 100 | * // 1 101 | * ML99_xor(v(1), v(0)) 102 | * 103 | * // 0 104 | * ML99_xor(v(1), v(1)) 105 | * @endcode 106 | */ 107 | #define ML99_xor(x, y) ML99_call(ML99_xor, x, y) 108 | 109 | /** 110 | * Tests @p x and @p y for equality. 111 | * 112 | * # Examples 113 | * 114 | * @code 115 | * #include 116 | * 117 | * // 1 118 | * ML99_boolEq(v(0), v(0)) 119 | * 120 | * // 0 121 | * ML99_boolEq(v(0), v(1)) 122 | * 123 | * // 0 124 | * ML99_boolEq(v(1), v(0)) 125 | * 126 | * // 1 127 | * ML99_boolEq(v(1), v(1)) 128 | * @endcode 129 | */ 130 | #define ML99_boolEq(x, y) ML99_call(ML99_boolEq, x, y) 131 | 132 | /** 133 | * Matches @p x against the two cases: if it is 0 or 1. 134 | * 135 | * # Examples 136 | * 137 | * @code 138 | * #include 139 | * 140 | * #define MATCH_1_IMPL() v(Billie) 141 | * #define MATCH_0_IMPL() v(Jean) 142 | * 143 | * // Billie 144 | * ML99_boolMatch(v(1), v(MATCH_)) 145 | * 146 | * // Jean 147 | * ML99_boolMatch(v(0), v(MATCH_)) 148 | * @endcode 149 | * 150 | * @note This function calls @p f with #ML99_call, so no partial application occurs, and so 151 | * arity specifiers are not needed. 152 | */ 153 | #define ML99_boolMatch(x, matcher) ML99_call(ML99_boolMatch, x, matcher) 154 | 155 | /** 156 | * The same as #ML99_boolMatch but provides additional arguments to all branches. 157 | * 158 | * # Examples 159 | * 160 | * @code 161 | * #include 162 | * 163 | * #define MATCH_1_IMPL(x, y, z) v(Billie ~ x y z) 164 | * #define MATCH_0_IMPL(x, y, z) v(Jean ~ x y z) 165 | * 166 | * // Billie ~ 1 2 3 167 | * ML99_boolMatchWithArgs(v(1), v(MATCH_), v(1, 2, 3)) 168 | * 169 | * // Jean ~ 1 2 3 170 | * ML99_boolMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3)) 171 | * @endcode 172 | */ 173 | #define ML99_boolMatchWithArgs(x, matcher, ...) \ 174 | ML99_call(ML99_boolMatchWithArgs, x, matcher, __VA_ARGS__) 175 | 176 | /** 177 | * If @p cond is true, evaluates to @p x, otherwise @p y. 178 | * 179 | * # Examples 180 | * 181 | * @code 182 | * #include 183 | * 184 | * // 123 185 | * ML99_if(v(1), v(123), v(18)) 186 | * 187 | * // 18 188 | * ML99_if(v(0), v(123), v(18)) 189 | * @endcode 190 | */ 191 | #define ML99_if(cond, x, y) ML99_call(ML99_if, cond, x, y) 192 | 193 | /** 194 | * The plain version of #ML99_if. 195 | * 196 | * This macro can imitate lazy evaluation: `ML99_IF(, , )` will expand to 197 | * one of the two terms, which can be evaluated further; if `` is 0, then `` will 198 | * **not** be evaluated, and the same with ``. 199 | * 200 | * @note @p x and @p y can possibly expand to commas. It means that you can supply `ML99_TERMS(...)` 201 | * as a branch, for example. 202 | */ 203 | #define ML99_IF(cond, x, y) ML99_PRIV_UNTUPLE(ML99_PRIV_IF(cond, (x), (y))) 204 | 205 | #define ML99_TRUE(...) 1 206 | #define ML99_FALSE(...) 0 207 | 208 | #define ML99_NOT(x) ML99_PRIV_NOT(x) 209 | #define ML99_AND(x, y) ML99_PRIV_AND(x, y) 210 | #define ML99_OR(x, y) ML99_PRIV_OR(x, y) 211 | #define ML99_XOR(x, y) ML99_PRIV_XOR(x, y) 212 | #define ML99_BOOL_EQ(x, y) ML99_PRIV_BOOL_EQ(x, y) 213 | 214 | #ifndef DOXYGEN_IGNORE 215 | 216 | #define ML99_true_IMPL(...) v(ML99_TRUE()) 217 | #define ML99_false_IMPL(...) v(ML99_FALSE()) 218 | 219 | #define ML99_not_IMPL(x) v(ML99_NOT(x)) 220 | #define ML99_and_IMPL(x, y) v(ML99_AND(x, y)) 221 | #define ML99_or_IMPL(x, y) v(ML99_OR(x, y)) 222 | #define ML99_xor_IMPL(x, y) v(ML99_XOR(x, y)) 223 | #define ML99_boolEq_IMPL(x, y) v(ML99_BOOL_EQ(x, y)) 224 | 225 | #define ML99_boolMatch_IMPL(x, matcher) ML99_callUneval(matcher##x, ) 226 | #define ML99_boolMatchWithArgs_IMPL(x, matcher, ...) ML99_callUneval(matcher##x, __VA_ARGS__) 227 | 228 | #define ML99_if_IMPL(cond, x, y) v(ML99_PRIV_IF(cond, x, y)) 229 | 230 | // Arity specifiers { 231 | 232 | #define ML99_true_ARITY 1 233 | #define ML99_false_ARITY 1 234 | #define ML99_not_ARITY 1 235 | #define ML99_and_ARITY 2 236 | #define ML99_or_ARITY 2 237 | #define ML99_xor_ARITY 2 238 | #define ML99_boolEq_ARITY 2 239 | #define ML99_boolMatch_ARITY 2 240 | #define ML99_boolMatchWithArgs_ARITY 3 241 | #define ML99_if_ARITY 3 242 | // } (Arity specifiers) 243 | 244 | #endif // DOXYGEN_IGNORE 245 | 246 | #endif // ML99_BOOL_H 247 | -------------------------------------------------------------------------------- /include/metalang99/choice.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Choice types: `(tag, ...)`. 4 | * 5 | * A choice type, also known as [tagged union], is represented as `(tag, ...)`, where `tag` is the 6 | * type of a value and `...` is the value. Perhaps the most common example of a choice type is a 7 | * binary tree: 8 | * 9 | * [[examples/binary_tree.c](https://github.com/hirrolot/metalang99/blob/master/examples/binary_tree.c)] 10 | * @include binary_tree.c 11 | * 12 | * [tagged union]: https://en.wikipedia.org/wiki/Tagged_union 13 | */ 14 | 15 | #ifndef ML99_CHOICE_H 16 | #define ML99_CHOICE_H 17 | 18 | #include 19 | 20 | #include 21 | 22 | /** 23 | * Constructs an instance of a choice type. 24 | * 25 | * # Examples 26 | * 27 | * See 28 | * [examples/binary_tree.c](https://github.com/hirrolot/metalang99/blob/master/examples/binary_tree.c). 29 | * 30 | * @note Specify `~` if you do not want to supply data; then, to match it, write a `_` parameter to 31 | * ignore. 32 | */ 33 | #define ML99_choice(tag, ...) ML99_call(ML99_choice, tag, __VA_ARGS__) 34 | 35 | /** 36 | * Evaluates to the tag of @p choice. 37 | * 38 | * This macro is essentially the same as `ML99_tupleGet(0)`. 39 | * 40 | * # Examples 41 | * 42 | * @code 43 | * #include 44 | * 45 | * // foo 46 | * ML99_choiceTag(ML99_choice(v(foo), v(1, 2, 3))) 47 | * @endcode 48 | */ 49 | #define ML99_choiceTag(choice) ML99_call(ML99_choiceTag, choice) 50 | 51 | /** 52 | * Evaluates to the data of @p choice. 53 | * 54 | * This macro is essentially the same as #ML99_tupleTail. 55 | * 56 | * # Examples 57 | * 58 | * @code 59 | * #include 60 | * 61 | * // 1, 2, 3 62 | * ML99_choiceData(ML99_choice(v(foo), v(1, 2, 3))) 63 | * @endcode 64 | */ 65 | #define ML99_choiceData(choice) ML99_call(ML99_choiceData, choice) 66 | 67 | /** 68 | * Matches the instance @p choice of a choice type. 69 | * 70 | * This macro results in `ML99_call(ML99_cat(matcher, ML99_choiceTag(choice)), )`. 71 | * 72 | * # Examples 73 | * 74 | * See 75 | * [examples/binary_tree.c](https://github.com/hirrolot/metalang99/blob/master/examples/binary_tree.c). 76 | */ 77 | #define ML99_match(choice, matcher) ML99_call(ML99_match, choice, matcher) 78 | 79 | /** 80 | * The same as #ML99_match but supplies additional arguments to all branches. 81 | * 82 | * This macro results in `ML99_call(ML99_cat(matcher, ML99_choiceTag(choice)), , 83 | * args...)`. 84 | * 85 | * # Examples 86 | * 87 | * @code 88 | * #include 89 | * 90 | * #define MATCH_A_IMPL(x, y, z) v(x ~ y ~ z) 91 | * 92 | * // 123 ~ 456 ~ 789 93 | * ML99_matchWithArgs(ML99_choice(v(A), v(123)), v(MATCH_), v(456, 789)) 94 | * @endcode 95 | */ 96 | #define ML99_matchWithArgs(choice, matcher, ...) \ 97 | ML99_call(ML99_matchWithArgs, choice, matcher, __VA_ARGS__) 98 | 99 | #define ML99_CHOICE(tag, ...) (tag, __VA_ARGS__) 100 | #define ML99_CHOICE_TAG(choice) ML99_PRIV_HEAD_AUX choice 101 | #define ML99_CHOICE_DATA(choice) ML99_PRIV_TAIL_AUX choice 102 | 103 | #ifndef DOXYGEN_IGNORE 104 | 105 | #define ML99_choice_IMPL(tag, ...) v(ML99_CHOICE(tag, __VA_ARGS__)) 106 | #define ML99_choiceTag_IMPL(choice) v(ML99_CHOICE_TAG(choice)) 107 | #define ML99_choiceData_IMPL(choice) v(ML99_CHOICE_DATA(choice)) 108 | 109 | #define ML99_match_IMPL(choice, matcher) \ 110 | ML99_callUneval(ML99_PRIV_CAT(matcher, ML99_PRIV_HEAD_AUX choice), ML99_PRIV_TAIL_AUX choice) 111 | 112 | #define ML99_matchWithArgs_IMPL(choice, matcher, ...) \ 113 | ML99_callUneval( \ 114 | ML99_PRIV_CAT(matcher, ML99_PRIV_HEAD_AUX choice), \ 115 | ML99_PRIV_TAIL_AUX choice, \ 116 | __VA_ARGS__) 117 | 118 | // Arity specifiers { 119 | 120 | #define ML99_choice_ARITY 2 121 | #define ML99_choiceTag_ARITY 1 122 | #define ML99_choiceData_ARITY 1 123 | #define ML99_match_ARITY 2 124 | #define ML99_matchWithArgs_ARITY 3 125 | // } (Arity specifiers) 126 | 127 | #endif // DOXYGEN_IGNORE 128 | 129 | #endif // ML99_CHOICE_H 130 | -------------------------------------------------------------------------------- /include/metalang99/control.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * This module is deprecated and exists only for backwards compatibility. 4 | */ 5 | 6 | #ifndef ML99_CONTROL_H 7 | #define ML99_CONTROL_H 8 | 9 | #include // ML99_if, ML99_IF 10 | #include // ML99_times, ML99_repeat 11 | #include // ML99_OVERLOAD 12 | 13 | #endif // ML99_CONTROL_H 14 | -------------------------------------------------------------------------------- /include/metalang99/either.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * A choice type with two cases. 4 | */ 5 | 6 | #ifndef ML99_EITHER_H 7 | #define ML99_EITHER_H 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * The left value @p x. 17 | */ 18 | #define ML99_left(x) ML99_call(ML99_left, x) 19 | 20 | /** 21 | * The right value @p x. 22 | */ 23 | #define ML99_right(x) ML99_call(ML99_right, x) 24 | 25 | /** 26 | * `ML99_true()` if @p either contains a left value, otherwise `ML99_false()`. 27 | * 28 | * # Examples 29 | * 30 | * @code 31 | * #include 32 | * 33 | * // 1 34 | * ML99_isLeft(ML99_left(v(123))) 35 | * 36 | * // 0 37 | * ML99_isLeft(ML99_right(v(123))) 38 | * @endcode 39 | */ 40 | #define ML99_isLeft(either) ML99_call(ML99_isLeft, either) 41 | 42 | /** 43 | * The inverse of #ML99_isLeft. 44 | * 45 | * # Examples 46 | * 47 | * @code 48 | * #include 49 | * 50 | * // 1 51 | * ML99_isRight(ML99_right(v(123))) 52 | * 53 | * // 0 54 | * ML99_isRight(ML99_left(v(123))) 55 | * @endcode 56 | */ 57 | #define ML99_isRight(either) ML99_call(ML99_isRight, either) 58 | 59 | /** 60 | * Tests @p either and @p other for equality. 61 | * 62 | * # Examples 63 | * 64 | * @code 65 | * #include 66 | * #include 67 | * 68 | * // 1 69 | * ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_left(v(123))) 70 | * 71 | * // 0 72 | * ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(8))) 73 | * 74 | * // 0 75 | * ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(123))) 76 | * @endcode 77 | */ 78 | #define ML99_eitherEq(cmp, either, other) ML99_call(ML99_eitherEq, cmp, either, other) 79 | 80 | /** 81 | * Returns the left value on `ML99_left(x)` or emits a fatal error on `ML99_right(y)`. 82 | * 83 | * # Examples 84 | * 85 | * @code 86 | * #include 87 | * 88 | * // 123 89 | * ML99_unwrapLeft(ML99_left(v(123))) 90 | * 91 | * // Emits a fatal error. 92 | * ML99_unwrapLeft(ML99_right(v(123))) 93 | * @endcode 94 | */ 95 | #define ML99_unwrapLeft(either) ML99_call(ML99_unwrapLeft, either) 96 | 97 | /** 98 | * The inverse of #ML99_unwrapLeft. 99 | * 100 | * # Examples 101 | * 102 | * @code 103 | * #include 104 | * 105 | * // 123 106 | * ML99_unwrapRight(ML99_right(v(123))) 107 | * 108 | * // Emits a fatal error. 109 | * ML99_unwrapRight(ML99_left(v(123))) 110 | * @endcode 111 | */ 112 | #define ML99_unwrapRight(either) ML99_call(ML99_unwrapRight, either) 113 | 114 | #define ML99_LEFT(x) ML99_CHOICE(left, x) 115 | #define ML99_RIGHT(x) ML99_CHOICE(right, x) 116 | #define ML99_IS_LEFT(either) ML99_PRIV_IS_LEFT(either) 117 | #define ML99_IS_RIGHT(either) ML99_NOT(ML99_IS_LEFT(either)) 118 | 119 | #ifndef DOXYGEN_IGNORE 120 | 121 | #define ML99_left_IMPL(x) v(ML99_LEFT(x)) 122 | #define ML99_right_IMPL(x) v(ML99_RIGHT(x)) 123 | 124 | #define ML99_isLeft_IMPL(either) v(ML99_IS_LEFT(either)) 125 | #define ML99_isRight_IMPL(either) v(ML99_IS_RIGHT(either)) 126 | 127 | // ML99_eitherEq_IMPL { 128 | 129 | #define ML99_eitherEq_IMPL(cmp, either, other) \ 130 | ML99_matchWithArgs_IMPL(either, ML99_PRIV_eitherEq_, cmp, other) 131 | 132 | #define ML99_PRIV_eitherEq_left_IMPL(x, cmp, other) \ 133 | ML99_matchWithArgs_IMPL(other, ML99_PRIV_eitherEq_left_, cmp, x) 134 | #define ML99_PRIV_eitherEq_right_IMPL(x, cmp, other) \ 135 | ML99_matchWithArgs_IMPL(other, ML99_PRIV_eitherEq_right_, cmp, x) 136 | 137 | #define ML99_PRIV_eitherEq_left_left_IMPL(y, cmp, x) ML99_appl2_IMPL(cmp, x, y) 138 | #define ML99_PRIV_eitherEq_left_right_IMPL ML99_false_IMPL 139 | 140 | #define ML99_PRIV_eitherEq_right_left_IMPL ML99_false_IMPL 141 | #define ML99_PRIV_eitherEq_right_right_IMPL(y, cmp, x) ML99_appl2_IMPL(cmp, x, y) 142 | // } (ML99_eitherEq_IMPL) 143 | 144 | #define ML99_unwrapLeft_IMPL(either) ML99_match_IMPL(either, ML99_PRIV_unwrapLeft_) 145 | #define ML99_PRIV_unwrapLeft_left_IMPL(x) v(x) 146 | #define ML99_PRIV_unwrapLeft_right_IMPL(_x) \ 147 | ML99_fatal(ML99_unwrapLeft, expected ML99_left but found ML99_right) 148 | 149 | #define ML99_unwrapRight_IMPL(either) ML99_match_IMPL(either, ML99_PRIV_unwrapRight_) 150 | #define ML99_PRIV_unwrapRight_left_IMPL(_x) \ 151 | ML99_fatal(ML99_unwrapRight, expected ML99_right but found ML99_left) 152 | #define ML99_PRIV_unwrapRight_right_IMPL(x) v(x) 153 | 154 | #define ML99_PRIV_IS_LEFT(either) ML99_DETECT_IDENT(ML99_PRIV_IS_LEFT_, ML99_CHOICE_TAG(either)) 155 | #define ML99_PRIV_IS_LEFT_left () 156 | 157 | // Arity specifiers { 158 | 159 | #define ML99_left_ARITY 1 160 | #define ML99_right_ARITY 1 161 | #define ML99_isLeft_ARITY 1 162 | #define ML99_isRight_ARITY 1 163 | #define ML99_eitherEq_ARITY 3 164 | #define ML99_unwrapLeft_ARITY 1 165 | #define ML99_unwrapRight_ARITY 1 166 | // } (Arity specifiers) 167 | 168 | #endif // DOXYGEN_IGNORE 169 | 170 | #endif // ML99_EITHER_H 171 | -------------------------------------------------------------------------------- /include/metalang99/eval/acc.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_EVAL_ACC_H 2 | #define ML99_EVAL_ACC_H 3 | 4 | #include 5 | 6 | #define ML99_PRIV_EVAL_ACC (, ) 7 | #define ML99_PRIV_EVAL_ACC_COMMA_SEP () 8 | 9 | #define ML99_PRIV_EVAL_0fspace(acc, ...) (ML99_PRIV_EXPAND acc __VA_ARGS__) 10 | #define ML99_PRIV_EVAL_0fcomma(acc, ...) (ML99_PRIV_EXPAND acc, __VA_ARGS__) 11 | 12 | #define ML99_PRIV_EVAL_ACC_UNWRAP(_emptiness, ...) __VA_ARGS__ 13 | 14 | #endif // ML99_EVAL_ACC_H 15 | -------------------------------------------------------------------------------- /include/metalang99/eval/eval.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_EVAL_EVAL_H 2 | #define ML99_EVAL_EVAL_H 3 | 4 | // Explanation is in the spec: . 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define ML99_PRIV_EVAL(...) \ 14 | ML99_PRIV_REC_UNROLL(ML99_PRIV_EVAL_MATCH( \ 15 | ML99_PRIV_REC_STOP, \ 16 | (~), \ 17 | 0fspace, \ 18 | ML99_PRIV_EVAL_ACC, \ 19 | __VA_ARGS__, \ 20 | (0end, ~), \ 21 | ~)) 22 | 23 | // Recursion hooks { 24 | 25 | #define ML99_PRIV_EVAL_MATCH_HOOK() ML99_PRIV_EVAL_MATCH 26 | #define ML99_PRIV_EVAL_0v_K_HOOK() ML99_PRIV_EVAL_0v_K 27 | #define ML99_PRIV_EVAL_0args_K_HOOK() ML99_PRIV_EVAL_0args_K 28 | #define ML99_PRIV_EVAL_0op_K_HOOK() ML99_PRIV_EVAL_0op_K 29 | #define ML99_PRIV_EVAL_0callUneval_K_HOOK() ML99_PRIV_EVAL_0callUneval_K 30 | // } (Recursion hooks) 31 | 32 | #define ML99_PRIV_EVAL_MATCH(k, k_cx, folder, acc, head, ...) \ 33 | ML99_PRIV_CHECK_TERM(head, ML99_PRIV_TERM_MATCH) \ 34 | (head)(k, k_cx, folder, acc, (__VA_ARGS__), ML99_PRIV_TERM_DATA head) 35 | 36 | #define ML99_PRIV_TERM_MATCH(term) ML99_PRIV_CAT(ML99_PRIV_EVAL_, ML99_PRIV_TERM_KIND term) 37 | #define ML99_PRIV_TERM_KIND(kind, ...) kind 38 | #define ML99_PRIV_TERM_DATA(_kind, ...) __VA_ARGS__ 39 | 40 | // Reduction rules { 41 | 42 | #define ML99_PRIV_EVAL_0v ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0v_K) 43 | #define ML99_PRIV_EVAL_0args ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0args_K) 44 | #define ML99_PRIV_EVAL_0op ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0op_K) 45 | #define ML99_PRIV_EVAL_0callUneval ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_0callUneval_K) 46 | 47 | #define ML99_PRIV_EVAL_0fatal(...) ML99_PRIV_EVAL_0fatal_AUX(__VA_ARGS__) 48 | #define ML99_PRIV_EVAL_0fatal_AUX(_k, _k_cx, _folder, _acc, _tail, f, message) \ 49 | ML99_PRIV_REC_CONTINUE(ML99_PRIV_REC_STOP)((~), ML99_PRIV_FATAL_ERROR(f, message)) 50 | 51 | #ifdef ML99_PRIV_EMIT_ERROR 52 | #define ML99_PRIV_FATAL_ERROR(f, message) ML99_PRIV_EMIT_ERROR(#f ": " message); 53 | #else 54 | // clang-format off 55 | #define ML99_PRIV_FATAL_ERROR(f, message) !"Metalang99 error" (f): message 56 | // clang-format on 57 | #endif 58 | 59 | #define ML99_PRIV_EVAL_0abort(_k, k_cx, folder, acc, _tail, ...) \ 60 | ML99_PRIV_REC_CONTINUE(ML99_PRIV_EVAL_MATCH) \ 61 | (ML99_PRIV_REC_STOP, (~), 0fspace, ML99_PRIV_EVAL_ACC, __VA_ARGS__, (0end, ~), ~) 62 | 63 | #define ML99_PRIV_EVAL_0end(k, k_cx, _folder, acc, _tail, _) \ 64 | ML99_PRIV_REC_CONTINUE(k) \ 65 | (ML99_PRIV_EXPAND k_cx, ML99_PRIV_EVAL_ACC_UNWRAP acc) 66 | // } (Reduction rules) 67 | 68 | // Continuations { 69 | 70 | #define ML99_PRIV_EVAL_0v_K(k, k_cx, folder, acc, tail, ...) \ 71 | ML99_PRIV_MACHINE_REDUCE( \ 72 | k, \ 73 | k_cx, \ 74 | folder, \ 75 | ML99_PRIV_EVAL_##folder(acc, __VA_ARGS__), \ 76 | ML99_PRIV_EXPAND tail) 77 | 78 | #define ML99_PRIV_EVAL_0args_K(k, k_cx, folder, acc, tail, op, ...) \ 79 | ML99_PRIV_MACHINE_REDUCE( \ 80 | ML99_PRIV_EVAL_0callUneval_K, \ 81 | (k, k_cx, folder, acc, tail, op), \ 82 | 0fcomma, \ 83 | ML99_PRIV_EVAL_ACC_COMMA_SEP, \ 84 | __VA_ARGS__, \ 85 | (0end, ~), \ 86 | ~) 87 | 88 | #define ML99_PRIV_EVAL_0op_K(k, k_cx, folder, acc, tail, op, ...) \ 89 | ML99_PRIV_MACHINE_REDUCE( \ 90 | ML99_PRIV_EVAL_0callUneval_K, \ 91 | (k, k_cx, folder, acc, tail), \ 92 | 0fcomma, \ 93 | ML99_PRIV_EVAL_ACC_COMMA_SEP, \ 94 | op, \ 95 | __VA_ARGS__, \ 96 | (0end, ~), \ 97 | ~) 98 | 99 | /* 100 | * In this subroutine, we employ the following optimization: 101 | * 102 | * - If `evaluated_op` expands to many terms, we first evaluate these terms and accumulate them 103 | * (`ML99_PRIV_EVAL_0callUneval_K_1`). 104 | * - Otherwise, we just paste a single term with the rest of the tail 105 | * (`ML99_PRIV_EVAL_0callUneval_K_0`). 106 | */ 107 | #define ML99_PRIV_EVAL_0callUneval_K(k, k_cx, folder, acc, tail, evaluated_op, ...) \ 108 | ML99_PRIV_EVAL_0callUneval_K_AUX(k, k_cx, folder, acc, tail, evaluated_op##_IMPL(__VA_ARGS__)) 109 | 110 | #define ML99_PRIV_EVAL_0callUneval_K_AUX(k, k_cx, folder, acc, tail, ...) \ 111 | ML99_PRIV_CAT(ML99_PRIV_EVAL_0callUneval_K_, ML99_PRIV_CONTAINS_COMMA(__VA_ARGS__)) \ 112 | (k, k_cx, folder, acc, tail, __VA_ARGS__) 113 | 114 | #define ML99_PRIV_EVAL_0callUneval_K_0(k, k_cx, folder, acc, tail, body) \ 115 | ML99_PRIV_MACHINE_REDUCE(k, k_cx, folder, acc, body, ML99_PRIV_EXPAND tail) 116 | 117 | #define ML99_PRIV_EVAL_0callUneval_K_1(k, k_cx, folder, acc, tail, ...) \ 118 | ML99_PRIV_MACHINE_REDUCE( \ 119 | ML99_PRIV_EVAL_0v_K, \ 120 | (k, k_cx, folder, acc, tail), \ 121 | 0fspace, \ 122 | ML99_PRIV_EVAL_ACC, \ 123 | __VA_ARGS__, \ 124 | (0end, ~), \ 125 | ~) 126 | 127 | #define ML99_PRIV_MACHINE_REDUCE(...) ML99_PRIV_EVAL_MATCH(__VA_ARGS__) 128 | // } (Continuations) 129 | 130 | #endif // ML99_EVAL_EVAL_H 131 | -------------------------------------------------------------------------------- /include/metalang99/eval/syntax_checker.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_EVAL_SYNTAX_CHECKER_H 2 | #define ML99_EVAL_SYNTAX_CHECKER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #define ML99_PRIV_CHECK_TERM(term, default) \ 12 | ML99_PRIV_IF(ML99_PRIV_IS_UNTUPLE(term), ML99_PRIV_EMIT_SYNTAX_ERROR, default) 13 | 14 | // clang-format off 15 | #define ML99_PRIV_EMIT_SYNTAX_ERROR(term) \ 16 | ML99_PRIV_REC_CONTINUE(ML99_PRIV_REC_STOP)((~), ML99_PRIV_SYNTAX_ERROR(term)) \ 17 | /* Consume arguments passed to ML99_PRIV_TERM_MATCH, see eval.h. */ \ 18 | ML99_PRIV_EMPTY 19 | // clang-format on 20 | 21 | #define ML99_PRIV_SYNTAX_ERROR(invalid_term) \ 22 | ML99_PRIV_CAT(ML99_PRIV_SYNTAX_ERROR_, ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(invalid_term)) \ 23 | (invalid_term) 24 | 25 | #ifdef ML99_PRIV_EMIT_ERROR 26 | 27 | #define ML99_PRIV_SYNTAX_ERROR_0(invalid_term) \ 28 | ML99_PRIV_EMIT_ERROR("invalid term `" #invalid_term "`"); 29 | #define ML99_PRIV_SYNTAX_ERROR_1(invalid_term) \ 30 | ML99_PRIV_EMIT_ERROR("invalid term `" #invalid_term "`, did you miss a comma?"); 31 | 32 | #else 33 | 34 | // clang-format off 35 | #define ML99_PRIV_SYNTAX_ERROR_0(invalid_term) !"Metalang99 syntax error": {invalid_term} 36 | #define ML99_PRIV_SYNTAX_ERROR_1(invalid_term) \ 37 | !"Metalang99 syntax error (did you miss a comma?)": {invalid_term} 38 | // clang-format on 39 | 40 | #endif 41 | 42 | #endif // ML99_EVAL_SYNTAX_CHECKER_H 43 | -------------------------------------------------------------------------------- /include/metalang99/lang.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * The core metalanguage. 4 | */ 5 | 6 | #ifndef ML99_LANG_H 7 | #define ML99_LANG_H 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | /** 16 | * Evaluates a metaprogram. 17 | * 18 | * # Examples 19 | * 20 | * @code 21 | * #include 22 | * 23 | * #define F_IMPL(x, y) v(x + y) 24 | * 25 | * ML99_EVAL(v(abc ~ 123), ML99_call(F, v(1, 2))) 26 | * @endcode 27 | */ 28 | #define ML99_EVAL(...) ML99_PRIV_EVAL(__VA_ARGS__) 29 | 30 | /** 31 | * Invokes a metafunction with arguments. 32 | */ 33 | #define ML99_call(op, ...) \ 34 | (ML99_PRIV_IF(ML99_PRIV_IS_UNTUPLE_FAST(op), 0args, 0op), op, __VA_ARGS__) 35 | 36 | /** 37 | * Invokes a metafunction @p ident with unevaluated arguments. 38 | * 39 | * It is semantically the same as `ML99_call(ident, v(...))` but performs one less reduction 40 | * steps. 41 | */ 42 | #define ML99_callUneval(ident, ...) (0callUneval, ident, __VA_ARGS__) 43 | 44 | /** 45 | * Applies arguments to @p f. 46 | * 47 | * This function implements [partial 48 | * application](https://en.wikipedia.org/wiki/Partial_application): instead of invoking a 49 | * metafunction with all arguments at once, you specify each argument separately. This concept 50 | * allows better re-use of metafunctions by specifying some arguments immediately, and the other 51 | * arguments later, even in different execution contexts (for example, see this [SO 52 | * answer](https://stackoverflow.com/a/12414292/13166656)). 53 | * 54 | * @p f must be either a term reducing to a macro name or a term obtained via another call to 55 | * #ML99_appl. If @p f is a macro name, then a macro named `_ARITY` (its arity specifier) 56 | * must denote how many times @p f will be applied to its arguments. (In Metalang99, an arity is an 57 | * intentionally more flexible concept than just a number of parameters, see below.) Each time 58 | * #ML99_appl is invoked, it accumulates provided variadic arguments and decrements the arity 59 | * of @p f; when the arity of @p f is already 1, it eventually calls the initial @p f with all the 60 | * accumulated arguments and provided variadic arguments. 61 | * 62 | * Most often, an arity specifier denotes a count of all named parameters plus 1 if a macro is 63 | * variadic (all the functions in the standard library follow this pattern). However, feel free to 64 | * specify arities as you wish, with regard to the aforementioned semantics; for example, you can 65 | * have a macro accepting `x, y, z` with an arity specifier `2`, then you must invoke 66 | * #ML99_appl exactly 2 times (either `x` + `y, z` or `x, y` + `z`). One common pattern is to 67 | * match a head and a tail of variadic arguments: 68 | * 69 | * @code 70 | * #include 71 | * 72 | * #define F_IMPL(x, y, z, head, ...) // ... 73 | * #define F_ARITY 4 74 | * @endcode 75 | * 76 | * In this case, `x`, `y`, and `z` can be specified separately but other arguments all at once. 77 | * 78 | * # Examples 79 | * 80 | * @code 81 | * #include 82 | * 83 | * #define F_IMPL(x, y) v(x##y) 84 | * #define F_ARITY 2 85 | * 86 | * // ab 87 | * ML99_appl(ML99_appl(v(F), v(a)), v(b)) 88 | * @endcode 89 | * 90 | * @note Currently, the maximum arity is #ML99_NAT_MAX. However, some compilers might not support 91 | * more than 127 macro parameters. 92 | */ 93 | #define ML99_appl(f, ...) ML99_call(ML99_appl, f, __VA_ARGS__) 94 | 95 | /** 96 | * Applies @p a and @p b to @p f. 97 | * 98 | * # Examples 99 | * 100 | * @code 101 | * #include 102 | * 103 | * #define F_IMPL(x, y) v(x##y) 104 | * #define F_ARITY 2 105 | * 106 | * // ab 107 | * ML99_appl2(v(F), v(a), v(b)) 108 | * @endcode 109 | */ 110 | #define ML99_appl2(f, a, b) ML99_call(ML99_appl2, f, a, b) 111 | 112 | /** 113 | * Applies @p a, @p b, and @p c to @p f. 114 | */ 115 | #define ML99_appl3(f, a, b, c) ML99_call(ML99_appl3, f, a, b, c) 116 | 117 | /** 118 | * Applies @p a, @p b, @p c, and @p d to @p f. 119 | */ 120 | #define ML99_appl4(f, a, b, c, d) ML99_call(ML99_appl4, f, a, b, c, d) 121 | 122 | /** 123 | * Functional composition of @p f and @p g. 124 | * 125 | * # Examples 126 | * 127 | * @code 128 | * #include 129 | * 130 | * #define F_IMPL(x) v((x + 1)) 131 | * #define G_IMPL(x) v((x * 8)) 132 | * 133 | * #define F_ARITY 1 134 | * #define G_ARITY 1 135 | * 136 | * // ((3 * 8) + 1) 137 | * ML99_appl(ML99_compose(v(F), v(G)), v(3)) 138 | * @endcode 139 | */ 140 | #define ML99_compose(f, g) ML99_call(ML99_compose, f, g) 141 | 142 | /** 143 | * A value that is pasted as-is; no evaluation occurs on provided arguments. 144 | */ 145 | #define v(...) (0v, __VA_ARGS__) 146 | 147 | // clang-format off 148 | /** 149 | * Emits a fatal error. 150 | * 151 | * @p f must be a macro name that has caused the error and the rest of arguments comprise the error 152 | * message. 153 | * 154 | * #ML99_fatal interprets its variadic arguments without preprocessor expansion -- i.e., they are 155 | * pasted as-is. This is intended because otherwise identifiers located in an error message may 156 | * stand for other macros that will be unintentionally expanded. 157 | * 158 | * # Examples 159 | * 160 | * [`playground.c`] 161 | * @code 162 | * #include 163 | * 164 | * ML99_EVAL(ML99_fatal(F, the description of your error)) 165 | * @endcode 166 | * 167 | * [`/bin/sh`] 168 | * @code{.txt} 169 | * playground.c:3:1: error: static assertion failed: "F: the description of your error" 170 | * 3 | ML99_EVAL(ML99_fatal(F, the description of your error)) 171 | * | ^~~~~~~~~ 172 | * @endcode 173 | */ 174 | #define ML99_fatal(f, ...) (0fatal, f, #__VA_ARGS__) 175 | // clang-format on 176 | 177 | /** 178 | * Immediately aborts the interpretation with evaluated arguments. 179 | * 180 | * # Examples 181 | * 182 | * @code 183 | * #include 184 | * 185 | * #define F_IMPL(x) v(~) 186 | * 187 | * // 123 188 | * ML99_call(F, ML99_abort(v(123))) 189 | * @endcode 190 | */ 191 | #define ML99_abort(...) (0abort, __VA_ARGS__) 192 | 193 | /** 194 | * A convenience macro to emphasize that your metafunction expands to more than one term. 195 | * 196 | * This macro just expands to provided arguments. 197 | * 198 | * # Examples 199 | * 200 | * @code 201 | * #include 202 | * 203 | * #define F_IMPL(x) ML99_TERMS(v(1), v(x), v(2)) 204 | * @endcode 205 | */ 206 | #define ML99_TERMS(...) __VA_ARGS__ 207 | 208 | /** 209 | * Delays evaluation for provided terms. 210 | * 211 | * `ML99_QUOTE(...)` is functionally equivalent to `v(...)`. 212 | * 213 | * # Examples 214 | * 215 | * @code 216 | * #include 217 | * 218 | * #define F_IMPL(x) v(~x) 219 | * 220 | * #define PROG ML99_TERMS(v(1), v(2), ML99_call(F, v(7))) 221 | * 222 | * // The same as `PROG` pasted into a source file. 223 | * ML99_EVAL(ML99_QUOTE(PROG)) 224 | * @endcode 225 | */ 226 | #define ML99_QUOTE(...) v(__VA_ARGS__) 227 | 228 | #ifndef DOXYGEN_IGNORE 229 | 230 | #define ML99_compose_IMPL(f, g) ML99_appl2_IMPL(ML99_PRIV_compose, f, g) 231 | #define ML99_PRIV_compose_IMPL(f, g, x) ML99_appl(v(f), ML99_appl_IMPL(g, x)) 232 | 233 | // Arity specifiers { 234 | 235 | #define ML99_appl_ARITY 2 236 | #define ML99_appl2_ARITY 3 237 | #define ML99_appl3_ARITY 4 238 | #define ML99_appl4_ARITY 5 239 | #define ML99_compose_ARITY 2 240 | 241 | #define ML99_PRIV_compose_ARITY 3 242 | // } (Arity specifiers) 243 | 244 | #endif // DOXYGEN_IGNORE 245 | 246 | #endif // ML99_LANG_H 247 | -------------------------------------------------------------------------------- /include/metalang99/lang/closure.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_LANG_CLOSURE_H 2 | #define ML99_LANG_CLOSURE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | /* 11 | * A closure has the form `(arity, f, ...)`, where `arity` is how many times `ML99_appl` can 12 | * be called for this closure, and `...` denotes the closure's environment. 13 | * 14 | * `ML99_appl` is described by the following algorithm: 15 | * - If `f` is an identifier (like `FOO`): 16 | * - If `f##_ARITY` is 1, then just call this function with provided arguments. 17 | * - Otherwise, return `(f##_ARITY - 1, f, provided args...)`. 18 | * - Otherwise (`f` is a closure): 19 | * - If `arity` is 1, then just call `f` with its environment and provided arguments. 20 | * - Otherwise, return `(arity - 1, f, env..., provided args...)`. 21 | * 22 | * Thus, each time except the last, `ML99_appl` extends a closure's environment with new 23 | * arguments; the last time, it calls `f` with its environment. 24 | */ 25 | 26 | #define ML99_appl_IMPL(f, ...) \ 27 | ML99_PRIV_IF(ML99_PRIV_IS_UNTUPLE_FAST(f), ML99_PRIV_APPL_F, ML99_PRIV_APPL_CLOSURE) \ 28 | (f, __VA_ARGS__) 29 | 30 | #define ML99_PRIV_APPL_F(f, ...) \ 31 | ML99_PRIV_IF( \ 32 | ML99_PRIV_NAT_EQ(f##_ARITY, 1), \ 33 | ML99_callUneval(f, __VA_ARGS__), \ 34 | v((ML99_PRIV_DEC(f##_ARITY), f, __VA_ARGS__))) 35 | 36 | #define ML99_PRIV_APPL_CLOSURE(closure, ...) \ 37 | ML99_PRIV_APPL_CLOSURE_AUX(ML99_PRIV_EXPAND closure, __VA_ARGS__) 38 | 39 | #define ML99_PRIV_APPL_CLOSURE_AUX(...) ML99_PRIV_APPL_CLOSURE_AUX_AUX(__VA_ARGS__) 40 | 41 | #define ML99_PRIV_APPL_CLOSURE_AUX_AUX(arity, f, ...) \ 42 | ML99_PRIV_IF( \ 43 | ML99_PRIV_NAT_EQ(arity, 1), \ 44 | ML99_callUneval(f, __VA_ARGS__), \ 45 | v((ML99_PRIV_DEC(arity), f, __VA_ARGS__))) 46 | 47 | #define ML99_appl2_IMPL(f, a, b) ML99_appl(ML99_appl_IMPL(f, a), v(b)) 48 | #define ML99_appl3_IMPL(f, a, b, c) ML99_appl(ML99_appl2_IMPL(f, a, b), v(c)) 49 | #define ML99_appl4_IMPL(f, a, b, c, d) ML99_appl(ML99_appl3_IMPL(f, a, b, c), v(d)) 50 | 51 | #endif // ML99_LANG_CLOSURE_H 52 | -------------------------------------------------------------------------------- /include/metalang99/logical.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * This module is deprecated and exists only for backwards compatibility. 4 | */ 5 | 6 | #ifndef ML99_LOGICAL_H 7 | #define ML99_LOGICAL_H 8 | 9 | #include 10 | 11 | #endif // ML99_LOGICAL_H 12 | -------------------------------------------------------------------------------- /include/metalang99/maybe.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * An optional value. 4 | */ 5 | 6 | #ifndef ML99_MAYBE_H 7 | #define ML99_MAYBE_H 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * Some value @p x. 17 | */ 18 | #define ML99_just(x) ML99_call(ML99_just, x) 19 | 20 | /** 21 | * No value. 22 | */ 23 | #define ML99_nothing(...) ML99_callUneval(ML99_nothing, ) 24 | 25 | /** 26 | * `ML99_true()` if @p maybe contains some value, otherwise `ML99_false()`. 27 | * 28 | * # Examples 29 | * 30 | * @code 31 | * #include 32 | * 33 | * // 1 34 | * ML99_isJust(ML99_just(v(123))) 35 | * 36 | * // 0 37 | * ML99_isJust(ML99_nothing()) 38 | * @endcode 39 | */ 40 | #define ML99_isJust(maybe) ML99_call(ML99_isJust, maybe) 41 | 42 | /** 43 | * The inverse of #ML99_isJust. 44 | * 45 | * # Examples 46 | * 47 | * @code 48 | * #include 49 | * 50 | * // 1 51 | * ML99_isNothing(ML99_nothing()) 52 | * 53 | * // 0 54 | * ML99_isNothing(ML99_just(v(123))) 55 | * @endcode 56 | */ 57 | #define ML99_isNothing(maybe) ML99_call(ML99_isNothing, maybe) 58 | 59 | /** 60 | * Tests @p maybe and @p other for equality. 61 | * 62 | * # Examples 63 | * 64 | * @code 65 | * #include 66 | * #include 67 | * 68 | * // 1 69 | * ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_just(v(123))); 70 | * 71 | * // 0 72 | * ML99_maybeEq(v(ML99_natEq), ML99_just(v(4)), ML99_just(v(6))); 73 | * 74 | * // 0 75 | * ML99_maybeEq(v(ML99_natEq), ML99_just(v(4)), ML99_nothing()); 76 | * @endcode 77 | */ 78 | #define ML99_maybeEq(cmp, maybe, other) ML99_call(ML99_maybeEq, cmp, maybe, other) 79 | 80 | /** 81 | * Returns the contained value on `ML99_just(x)` or emits a fatal error on `ML99_nothing()`. 82 | * 83 | * # Examples 84 | * 85 | * @code 86 | * #include 87 | * 88 | * // 123 89 | * ML99_maybeUnwrap(ML99_just(v(123))) 90 | * 91 | * // Emits a fatal error. 92 | * ML99_maybeUnwrap(ML99_nothing()) 93 | * @endcode 94 | */ 95 | #define ML99_maybeUnwrap(maybe) ML99_call(ML99_maybeUnwrap, maybe) 96 | 97 | #define ML99_JUST(x) ML99_CHOICE(just, x) 98 | #define ML99_NOTHING(...) ML99_CHOICE(nothing, ~) 99 | #define ML99_IS_JUST(maybe) ML99_PRIV_IS_JUST(maybe) 100 | #define ML99_IS_NOTHING(maybe) ML99_NOT(ML99_IS_JUST(maybe)) 101 | 102 | #ifndef DOXYGEN_IGNORE 103 | 104 | #define ML99_just_IMPL(x) v(ML99_JUST(x)) 105 | #define ML99_nothing_IMPL(...) v(ML99_NOTHING()) 106 | 107 | #define ML99_isJust_IMPL(maybe) v(ML99_IS_JUST(maybe)) 108 | #define ML99_isNothing_IMPL(maybe) v(ML99_IS_NOTHING(maybe)) 109 | 110 | // ML99_maybeEq_IMPL { 111 | 112 | #define ML99_maybeEq_IMPL(cmp, maybe, other) \ 113 | ML99_matchWithArgs_IMPL(maybe, ML99_PRIV_maybeEq_, cmp, other) 114 | 115 | #define ML99_PRIV_maybeEq_just_IMPL(x, cmp, other) \ 116 | ML99_matchWithArgs_IMPL(other, ML99_PRIV_maybeEq_just_, cmp, x) 117 | #define ML99_PRIV_maybeEq_nothing_IMPL(_, _cmp, other) v(ML99_IS_NOTHING(other)) 118 | 119 | #define ML99_PRIV_maybeEq_just_just_IMPL(y, cmp, x) ML99_appl2_IMPL(cmp, x, y) 120 | #define ML99_PRIV_maybeEq_just_nothing_IMPL ML99_false_IMPL 121 | // } (ML99_maybeEq_IMPL) 122 | 123 | #define ML99_maybeUnwrap_IMPL(maybe) ML99_match_IMPL(maybe, ML99_PRIV_maybeUnwrap_) 124 | #define ML99_PRIV_maybeUnwrap_just_IMPL(x) v(x) 125 | #define ML99_PRIV_maybeUnwrap_nothing_IMPL(_) \ 126 | ML99_fatal(ML99_maybeUnwrap, expected ML99_just but found ML99_nothing) 127 | 128 | #define ML99_PRIV_IS_JUST(maybe) ML99_DETECT_IDENT(ML99_PRIV_IS_JUST_, ML99_CHOICE_TAG(maybe)) 129 | #define ML99_PRIV_IS_JUST_just () 130 | 131 | // Arity specifiers { 132 | 133 | #define ML99_just_ARITY 1 134 | #define ML99_nothing_ARITY 1 135 | #define ML99_isJust_ARITY 1 136 | #define ML99_isNothing_ARITY 1 137 | #define ML99_maybeEq_ARITY 3 138 | #define ML99_maybeUnwrap_ARITY 1 139 | // } (Arity specifiers) 140 | 141 | #endif // DOXYGEN_IGNORE 142 | 143 | #endif // ML99_MAYBE_H 144 | -------------------------------------------------------------------------------- /include/metalang99/nat/dec.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_NAT_DEC_H 2 | #define ML99_NAT_DEC_H 3 | 4 | #define ML99_PRIV_DEC(x) ML99_PRIV_DEC_AUX(x) 5 | #define ML99_PRIV_DEC_AUX(x) ML99_PRIV_DEC_##x 6 | 7 | #define ML99_PRIV_DEC_0 255 8 | #define ML99_PRIV_DEC_1 0 9 | #define ML99_PRIV_DEC_2 1 10 | #define ML99_PRIV_DEC_3 2 11 | #define ML99_PRIV_DEC_4 3 12 | #define ML99_PRIV_DEC_5 4 13 | #define ML99_PRIV_DEC_6 5 14 | #define ML99_PRIV_DEC_7 6 15 | #define ML99_PRIV_DEC_8 7 16 | #define ML99_PRIV_DEC_9 8 17 | #define ML99_PRIV_DEC_10 9 18 | #define ML99_PRIV_DEC_11 10 19 | #define ML99_PRIV_DEC_12 11 20 | #define ML99_PRIV_DEC_13 12 21 | #define ML99_PRIV_DEC_14 13 22 | #define ML99_PRIV_DEC_15 14 23 | #define ML99_PRIV_DEC_16 15 24 | #define ML99_PRIV_DEC_17 16 25 | #define ML99_PRIV_DEC_18 17 26 | #define ML99_PRIV_DEC_19 18 27 | #define ML99_PRIV_DEC_20 19 28 | #define ML99_PRIV_DEC_21 20 29 | #define ML99_PRIV_DEC_22 21 30 | #define ML99_PRIV_DEC_23 22 31 | #define ML99_PRIV_DEC_24 23 32 | #define ML99_PRIV_DEC_25 24 33 | #define ML99_PRIV_DEC_26 25 34 | #define ML99_PRIV_DEC_27 26 35 | #define ML99_PRIV_DEC_28 27 36 | #define ML99_PRIV_DEC_29 28 37 | #define ML99_PRIV_DEC_30 29 38 | #define ML99_PRIV_DEC_31 30 39 | #define ML99_PRIV_DEC_32 31 40 | #define ML99_PRIV_DEC_33 32 41 | #define ML99_PRIV_DEC_34 33 42 | #define ML99_PRIV_DEC_35 34 43 | #define ML99_PRIV_DEC_36 35 44 | #define ML99_PRIV_DEC_37 36 45 | #define ML99_PRIV_DEC_38 37 46 | #define ML99_PRIV_DEC_39 38 47 | #define ML99_PRIV_DEC_40 39 48 | #define ML99_PRIV_DEC_41 40 49 | #define ML99_PRIV_DEC_42 41 50 | #define ML99_PRIV_DEC_43 42 51 | #define ML99_PRIV_DEC_44 43 52 | #define ML99_PRIV_DEC_45 44 53 | #define ML99_PRIV_DEC_46 45 54 | #define ML99_PRIV_DEC_47 46 55 | #define ML99_PRIV_DEC_48 47 56 | #define ML99_PRIV_DEC_49 48 57 | #define ML99_PRIV_DEC_50 49 58 | #define ML99_PRIV_DEC_51 50 59 | #define ML99_PRIV_DEC_52 51 60 | #define ML99_PRIV_DEC_53 52 61 | #define ML99_PRIV_DEC_54 53 62 | #define ML99_PRIV_DEC_55 54 63 | #define ML99_PRIV_DEC_56 55 64 | #define ML99_PRIV_DEC_57 56 65 | #define ML99_PRIV_DEC_58 57 66 | #define ML99_PRIV_DEC_59 58 67 | #define ML99_PRIV_DEC_60 59 68 | #define ML99_PRIV_DEC_61 60 69 | #define ML99_PRIV_DEC_62 61 70 | #define ML99_PRIV_DEC_63 62 71 | #define ML99_PRIV_DEC_64 63 72 | #define ML99_PRIV_DEC_65 64 73 | #define ML99_PRIV_DEC_66 65 74 | #define ML99_PRIV_DEC_67 66 75 | #define ML99_PRIV_DEC_68 67 76 | #define ML99_PRIV_DEC_69 68 77 | #define ML99_PRIV_DEC_70 69 78 | #define ML99_PRIV_DEC_71 70 79 | #define ML99_PRIV_DEC_72 71 80 | #define ML99_PRIV_DEC_73 72 81 | #define ML99_PRIV_DEC_74 73 82 | #define ML99_PRIV_DEC_75 74 83 | #define ML99_PRIV_DEC_76 75 84 | #define ML99_PRIV_DEC_77 76 85 | #define ML99_PRIV_DEC_78 77 86 | #define ML99_PRIV_DEC_79 78 87 | #define ML99_PRIV_DEC_80 79 88 | #define ML99_PRIV_DEC_81 80 89 | #define ML99_PRIV_DEC_82 81 90 | #define ML99_PRIV_DEC_83 82 91 | #define ML99_PRIV_DEC_84 83 92 | #define ML99_PRIV_DEC_85 84 93 | #define ML99_PRIV_DEC_86 85 94 | #define ML99_PRIV_DEC_87 86 95 | #define ML99_PRIV_DEC_88 87 96 | #define ML99_PRIV_DEC_89 88 97 | #define ML99_PRIV_DEC_90 89 98 | #define ML99_PRIV_DEC_91 90 99 | #define ML99_PRIV_DEC_92 91 100 | #define ML99_PRIV_DEC_93 92 101 | #define ML99_PRIV_DEC_94 93 102 | #define ML99_PRIV_DEC_95 94 103 | #define ML99_PRIV_DEC_96 95 104 | #define ML99_PRIV_DEC_97 96 105 | #define ML99_PRIV_DEC_98 97 106 | #define ML99_PRIV_DEC_99 98 107 | #define ML99_PRIV_DEC_100 99 108 | #define ML99_PRIV_DEC_101 100 109 | #define ML99_PRIV_DEC_102 101 110 | #define ML99_PRIV_DEC_103 102 111 | #define ML99_PRIV_DEC_104 103 112 | #define ML99_PRIV_DEC_105 104 113 | #define ML99_PRIV_DEC_106 105 114 | #define ML99_PRIV_DEC_107 106 115 | #define ML99_PRIV_DEC_108 107 116 | #define ML99_PRIV_DEC_109 108 117 | #define ML99_PRIV_DEC_110 109 118 | #define ML99_PRIV_DEC_111 110 119 | #define ML99_PRIV_DEC_112 111 120 | #define ML99_PRIV_DEC_113 112 121 | #define ML99_PRIV_DEC_114 113 122 | #define ML99_PRIV_DEC_115 114 123 | #define ML99_PRIV_DEC_116 115 124 | #define ML99_PRIV_DEC_117 116 125 | #define ML99_PRIV_DEC_118 117 126 | #define ML99_PRIV_DEC_119 118 127 | #define ML99_PRIV_DEC_120 119 128 | #define ML99_PRIV_DEC_121 120 129 | #define ML99_PRIV_DEC_122 121 130 | #define ML99_PRIV_DEC_123 122 131 | #define ML99_PRIV_DEC_124 123 132 | #define ML99_PRIV_DEC_125 124 133 | #define ML99_PRIV_DEC_126 125 134 | #define ML99_PRIV_DEC_127 126 135 | #define ML99_PRIV_DEC_128 127 136 | #define ML99_PRIV_DEC_129 128 137 | #define ML99_PRIV_DEC_130 129 138 | #define ML99_PRIV_DEC_131 130 139 | #define ML99_PRIV_DEC_132 131 140 | #define ML99_PRIV_DEC_133 132 141 | #define ML99_PRIV_DEC_134 133 142 | #define ML99_PRIV_DEC_135 134 143 | #define ML99_PRIV_DEC_136 135 144 | #define ML99_PRIV_DEC_137 136 145 | #define ML99_PRIV_DEC_138 137 146 | #define ML99_PRIV_DEC_139 138 147 | #define ML99_PRIV_DEC_140 139 148 | #define ML99_PRIV_DEC_141 140 149 | #define ML99_PRIV_DEC_142 141 150 | #define ML99_PRIV_DEC_143 142 151 | #define ML99_PRIV_DEC_144 143 152 | #define ML99_PRIV_DEC_145 144 153 | #define ML99_PRIV_DEC_146 145 154 | #define ML99_PRIV_DEC_147 146 155 | #define ML99_PRIV_DEC_148 147 156 | #define ML99_PRIV_DEC_149 148 157 | #define ML99_PRIV_DEC_150 149 158 | #define ML99_PRIV_DEC_151 150 159 | #define ML99_PRIV_DEC_152 151 160 | #define ML99_PRIV_DEC_153 152 161 | #define ML99_PRIV_DEC_154 153 162 | #define ML99_PRIV_DEC_155 154 163 | #define ML99_PRIV_DEC_156 155 164 | #define ML99_PRIV_DEC_157 156 165 | #define ML99_PRIV_DEC_158 157 166 | #define ML99_PRIV_DEC_159 158 167 | #define ML99_PRIV_DEC_160 159 168 | #define ML99_PRIV_DEC_161 160 169 | #define ML99_PRIV_DEC_162 161 170 | #define ML99_PRIV_DEC_163 162 171 | #define ML99_PRIV_DEC_164 163 172 | #define ML99_PRIV_DEC_165 164 173 | #define ML99_PRIV_DEC_166 165 174 | #define ML99_PRIV_DEC_167 166 175 | #define ML99_PRIV_DEC_168 167 176 | #define ML99_PRIV_DEC_169 168 177 | #define ML99_PRIV_DEC_170 169 178 | #define ML99_PRIV_DEC_171 170 179 | #define ML99_PRIV_DEC_172 171 180 | #define ML99_PRIV_DEC_173 172 181 | #define ML99_PRIV_DEC_174 173 182 | #define ML99_PRIV_DEC_175 174 183 | #define ML99_PRIV_DEC_176 175 184 | #define ML99_PRIV_DEC_177 176 185 | #define ML99_PRIV_DEC_178 177 186 | #define ML99_PRIV_DEC_179 178 187 | #define ML99_PRIV_DEC_180 179 188 | #define ML99_PRIV_DEC_181 180 189 | #define ML99_PRIV_DEC_182 181 190 | #define ML99_PRIV_DEC_183 182 191 | #define ML99_PRIV_DEC_184 183 192 | #define ML99_PRIV_DEC_185 184 193 | #define ML99_PRIV_DEC_186 185 194 | #define ML99_PRIV_DEC_187 186 195 | #define ML99_PRIV_DEC_188 187 196 | #define ML99_PRIV_DEC_189 188 197 | #define ML99_PRIV_DEC_190 189 198 | #define ML99_PRIV_DEC_191 190 199 | #define ML99_PRIV_DEC_192 191 200 | #define ML99_PRIV_DEC_193 192 201 | #define ML99_PRIV_DEC_194 193 202 | #define ML99_PRIV_DEC_195 194 203 | #define ML99_PRIV_DEC_196 195 204 | #define ML99_PRIV_DEC_197 196 205 | #define ML99_PRIV_DEC_198 197 206 | #define ML99_PRIV_DEC_199 198 207 | #define ML99_PRIV_DEC_200 199 208 | #define ML99_PRIV_DEC_201 200 209 | #define ML99_PRIV_DEC_202 201 210 | #define ML99_PRIV_DEC_203 202 211 | #define ML99_PRIV_DEC_204 203 212 | #define ML99_PRIV_DEC_205 204 213 | #define ML99_PRIV_DEC_206 205 214 | #define ML99_PRIV_DEC_207 206 215 | #define ML99_PRIV_DEC_208 207 216 | #define ML99_PRIV_DEC_209 208 217 | #define ML99_PRIV_DEC_210 209 218 | #define ML99_PRIV_DEC_211 210 219 | #define ML99_PRIV_DEC_212 211 220 | #define ML99_PRIV_DEC_213 212 221 | #define ML99_PRIV_DEC_214 213 222 | #define ML99_PRIV_DEC_215 214 223 | #define ML99_PRIV_DEC_216 215 224 | #define ML99_PRIV_DEC_217 216 225 | #define ML99_PRIV_DEC_218 217 226 | #define ML99_PRIV_DEC_219 218 227 | #define ML99_PRIV_DEC_220 219 228 | #define ML99_PRIV_DEC_221 220 229 | #define ML99_PRIV_DEC_222 221 230 | #define ML99_PRIV_DEC_223 222 231 | #define ML99_PRIV_DEC_224 223 232 | #define ML99_PRIV_DEC_225 224 233 | #define ML99_PRIV_DEC_226 225 234 | #define ML99_PRIV_DEC_227 226 235 | #define ML99_PRIV_DEC_228 227 236 | #define ML99_PRIV_DEC_229 228 237 | #define ML99_PRIV_DEC_230 229 238 | #define ML99_PRIV_DEC_231 230 239 | #define ML99_PRIV_DEC_232 231 240 | #define ML99_PRIV_DEC_233 232 241 | #define ML99_PRIV_DEC_234 233 242 | #define ML99_PRIV_DEC_235 234 243 | #define ML99_PRIV_DEC_236 235 244 | #define ML99_PRIV_DEC_237 236 245 | #define ML99_PRIV_DEC_238 237 246 | #define ML99_PRIV_DEC_239 238 247 | #define ML99_PRIV_DEC_240 239 248 | #define ML99_PRIV_DEC_241 240 249 | #define ML99_PRIV_DEC_242 241 250 | #define ML99_PRIV_DEC_243 242 251 | #define ML99_PRIV_DEC_244 243 252 | #define ML99_PRIV_DEC_245 244 253 | #define ML99_PRIV_DEC_246 245 254 | #define ML99_PRIV_DEC_247 246 255 | #define ML99_PRIV_DEC_248 247 256 | #define ML99_PRIV_DEC_249 248 257 | #define ML99_PRIV_DEC_250 249 258 | #define ML99_PRIV_DEC_251 250 259 | #define ML99_PRIV_DEC_252 251 260 | #define ML99_PRIV_DEC_253 252 261 | #define ML99_PRIV_DEC_254 253 262 | #define ML99_PRIV_DEC_255 254 263 | 264 | #endif // ML99_NAT_DEC_H 265 | -------------------------------------------------------------------------------- /include/metalang99/nat/eq.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_NAT_EQ_H 2 | #define ML99_NAT_EQ_H 3 | 4 | #include 5 | 6 | #define ML99_PRIV_NAT_EQ(x, y) ML99_PRIV_NAT_EQ_AUX(x, y) 7 | #define ML99_PRIV_NAT_EQ_AUX(x, y) ML99_PRIV_IS_TUPLE_FAST(ML99_PRIV_NAT_EQ_##x##_##y) 8 | 9 | #define ML99_PRIV_NAT_EQ_0_0 () 10 | #define ML99_PRIV_NAT_EQ_1_1 () 11 | #define ML99_PRIV_NAT_EQ_2_2 () 12 | #define ML99_PRIV_NAT_EQ_3_3 () 13 | #define ML99_PRIV_NAT_EQ_4_4 () 14 | #define ML99_PRIV_NAT_EQ_5_5 () 15 | #define ML99_PRIV_NAT_EQ_6_6 () 16 | #define ML99_PRIV_NAT_EQ_7_7 () 17 | #define ML99_PRIV_NAT_EQ_8_8 () 18 | #define ML99_PRIV_NAT_EQ_9_9 () 19 | #define ML99_PRIV_NAT_EQ_10_10 () 20 | #define ML99_PRIV_NAT_EQ_11_11 () 21 | #define ML99_PRIV_NAT_EQ_12_12 () 22 | #define ML99_PRIV_NAT_EQ_13_13 () 23 | #define ML99_PRIV_NAT_EQ_14_14 () 24 | #define ML99_PRIV_NAT_EQ_15_15 () 25 | #define ML99_PRIV_NAT_EQ_16_16 () 26 | #define ML99_PRIV_NAT_EQ_17_17 () 27 | #define ML99_PRIV_NAT_EQ_18_18 () 28 | #define ML99_PRIV_NAT_EQ_19_19 () 29 | #define ML99_PRIV_NAT_EQ_20_20 () 30 | #define ML99_PRIV_NAT_EQ_21_21 () 31 | #define ML99_PRIV_NAT_EQ_22_22 () 32 | #define ML99_PRIV_NAT_EQ_23_23 () 33 | #define ML99_PRIV_NAT_EQ_24_24 () 34 | #define ML99_PRIV_NAT_EQ_25_25 () 35 | #define ML99_PRIV_NAT_EQ_26_26 () 36 | #define ML99_PRIV_NAT_EQ_27_27 () 37 | #define ML99_PRIV_NAT_EQ_28_28 () 38 | #define ML99_PRIV_NAT_EQ_29_29 () 39 | #define ML99_PRIV_NAT_EQ_30_30 () 40 | #define ML99_PRIV_NAT_EQ_31_31 () 41 | #define ML99_PRIV_NAT_EQ_32_32 () 42 | #define ML99_PRIV_NAT_EQ_33_33 () 43 | #define ML99_PRIV_NAT_EQ_34_34 () 44 | #define ML99_PRIV_NAT_EQ_35_35 () 45 | #define ML99_PRIV_NAT_EQ_36_36 () 46 | #define ML99_PRIV_NAT_EQ_37_37 () 47 | #define ML99_PRIV_NAT_EQ_38_38 () 48 | #define ML99_PRIV_NAT_EQ_39_39 () 49 | #define ML99_PRIV_NAT_EQ_40_40 () 50 | #define ML99_PRIV_NAT_EQ_41_41 () 51 | #define ML99_PRIV_NAT_EQ_42_42 () 52 | #define ML99_PRIV_NAT_EQ_43_43 () 53 | #define ML99_PRIV_NAT_EQ_44_44 () 54 | #define ML99_PRIV_NAT_EQ_45_45 () 55 | #define ML99_PRIV_NAT_EQ_46_46 () 56 | #define ML99_PRIV_NAT_EQ_47_47 () 57 | #define ML99_PRIV_NAT_EQ_48_48 () 58 | #define ML99_PRIV_NAT_EQ_49_49 () 59 | #define ML99_PRIV_NAT_EQ_50_50 () 60 | #define ML99_PRIV_NAT_EQ_51_51 () 61 | #define ML99_PRIV_NAT_EQ_52_52 () 62 | #define ML99_PRIV_NAT_EQ_53_53 () 63 | #define ML99_PRIV_NAT_EQ_54_54 () 64 | #define ML99_PRIV_NAT_EQ_55_55 () 65 | #define ML99_PRIV_NAT_EQ_56_56 () 66 | #define ML99_PRIV_NAT_EQ_57_57 () 67 | #define ML99_PRIV_NAT_EQ_58_58 () 68 | #define ML99_PRIV_NAT_EQ_59_59 () 69 | #define ML99_PRIV_NAT_EQ_60_60 () 70 | #define ML99_PRIV_NAT_EQ_61_61 () 71 | #define ML99_PRIV_NAT_EQ_62_62 () 72 | #define ML99_PRIV_NAT_EQ_63_63 () 73 | #define ML99_PRIV_NAT_EQ_64_64 () 74 | #define ML99_PRIV_NAT_EQ_65_65 () 75 | #define ML99_PRIV_NAT_EQ_66_66 () 76 | #define ML99_PRIV_NAT_EQ_67_67 () 77 | #define ML99_PRIV_NAT_EQ_68_68 () 78 | #define ML99_PRIV_NAT_EQ_69_69 () 79 | #define ML99_PRIV_NAT_EQ_70_70 () 80 | #define ML99_PRIV_NAT_EQ_71_71 () 81 | #define ML99_PRIV_NAT_EQ_72_72 () 82 | #define ML99_PRIV_NAT_EQ_73_73 () 83 | #define ML99_PRIV_NAT_EQ_74_74 () 84 | #define ML99_PRIV_NAT_EQ_75_75 () 85 | #define ML99_PRIV_NAT_EQ_76_76 () 86 | #define ML99_PRIV_NAT_EQ_77_77 () 87 | #define ML99_PRIV_NAT_EQ_78_78 () 88 | #define ML99_PRIV_NAT_EQ_79_79 () 89 | #define ML99_PRIV_NAT_EQ_80_80 () 90 | #define ML99_PRIV_NAT_EQ_81_81 () 91 | #define ML99_PRIV_NAT_EQ_82_82 () 92 | #define ML99_PRIV_NAT_EQ_83_83 () 93 | #define ML99_PRIV_NAT_EQ_84_84 () 94 | #define ML99_PRIV_NAT_EQ_85_85 () 95 | #define ML99_PRIV_NAT_EQ_86_86 () 96 | #define ML99_PRIV_NAT_EQ_87_87 () 97 | #define ML99_PRIV_NAT_EQ_88_88 () 98 | #define ML99_PRIV_NAT_EQ_89_89 () 99 | #define ML99_PRIV_NAT_EQ_90_90 () 100 | #define ML99_PRIV_NAT_EQ_91_91 () 101 | #define ML99_PRIV_NAT_EQ_92_92 () 102 | #define ML99_PRIV_NAT_EQ_93_93 () 103 | #define ML99_PRIV_NAT_EQ_94_94 () 104 | #define ML99_PRIV_NAT_EQ_95_95 () 105 | #define ML99_PRIV_NAT_EQ_96_96 () 106 | #define ML99_PRIV_NAT_EQ_97_97 () 107 | #define ML99_PRIV_NAT_EQ_98_98 () 108 | #define ML99_PRIV_NAT_EQ_99_99 () 109 | #define ML99_PRIV_NAT_EQ_100_100 () 110 | #define ML99_PRIV_NAT_EQ_101_101 () 111 | #define ML99_PRIV_NAT_EQ_102_102 () 112 | #define ML99_PRIV_NAT_EQ_103_103 () 113 | #define ML99_PRIV_NAT_EQ_104_104 () 114 | #define ML99_PRIV_NAT_EQ_105_105 () 115 | #define ML99_PRIV_NAT_EQ_106_106 () 116 | #define ML99_PRIV_NAT_EQ_107_107 () 117 | #define ML99_PRIV_NAT_EQ_108_108 () 118 | #define ML99_PRIV_NAT_EQ_109_109 () 119 | #define ML99_PRIV_NAT_EQ_110_110 () 120 | #define ML99_PRIV_NAT_EQ_111_111 () 121 | #define ML99_PRIV_NAT_EQ_112_112 () 122 | #define ML99_PRIV_NAT_EQ_113_113 () 123 | #define ML99_PRIV_NAT_EQ_114_114 () 124 | #define ML99_PRIV_NAT_EQ_115_115 () 125 | #define ML99_PRIV_NAT_EQ_116_116 () 126 | #define ML99_PRIV_NAT_EQ_117_117 () 127 | #define ML99_PRIV_NAT_EQ_118_118 () 128 | #define ML99_PRIV_NAT_EQ_119_119 () 129 | #define ML99_PRIV_NAT_EQ_120_120 () 130 | #define ML99_PRIV_NAT_EQ_121_121 () 131 | #define ML99_PRIV_NAT_EQ_122_122 () 132 | #define ML99_PRIV_NAT_EQ_123_123 () 133 | #define ML99_PRIV_NAT_EQ_124_124 () 134 | #define ML99_PRIV_NAT_EQ_125_125 () 135 | #define ML99_PRIV_NAT_EQ_126_126 () 136 | #define ML99_PRIV_NAT_EQ_127_127 () 137 | #define ML99_PRIV_NAT_EQ_128_128 () 138 | #define ML99_PRIV_NAT_EQ_129_129 () 139 | #define ML99_PRIV_NAT_EQ_130_130 () 140 | #define ML99_PRIV_NAT_EQ_131_131 () 141 | #define ML99_PRIV_NAT_EQ_132_132 () 142 | #define ML99_PRIV_NAT_EQ_133_133 () 143 | #define ML99_PRIV_NAT_EQ_134_134 () 144 | #define ML99_PRIV_NAT_EQ_135_135 () 145 | #define ML99_PRIV_NAT_EQ_136_136 () 146 | #define ML99_PRIV_NAT_EQ_137_137 () 147 | #define ML99_PRIV_NAT_EQ_138_138 () 148 | #define ML99_PRIV_NAT_EQ_139_139 () 149 | #define ML99_PRIV_NAT_EQ_140_140 () 150 | #define ML99_PRIV_NAT_EQ_141_141 () 151 | #define ML99_PRIV_NAT_EQ_142_142 () 152 | #define ML99_PRIV_NAT_EQ_143_143 () 153 | #define ML99_PRIV_NAT_EQ_144_144 () 154 | #define ML99_PRIV_NAT_EQ_145_145 () 155 | #define ML99_PRIV_NAT_EQ_146_146 () 156 | #define ML99_PRIV_NAT_EQ_147_147 () 157 | #define ML99_PRIV_NAT_EQ_148_148 () 158 | #define ML99_PRIV_NAT_EQ_149_149 () 159 | #define ML99_PRIV_NAT_EQ_150_150 () 160 | #define ML99_PRIV_NAT_EQ_151_151 () 161 | #define ML99_PRIV_NAT_EQ_152_152 () 162 | #define ML99_PRIV_NAT_EQ_153_153 () 163 | #define ML99_PRIV_NAT_EQ_154_154 () 164 | #define ML99_PRIV_NAT_EQ_155_155 () 165 | #define ML99_PRIV_NAT_EQ_156_156 () 166 | #define ML99_PRIV_NAT_EQ_157_157 () 167 | #define ML99_PRIV_NAT_EQ_158_158 () 168 | #define ML99_PRIV_NAT_EQ_159_159 () 169 | #define ML99_PRIV_NAT_EQ_160_160 () 170 | #define ML99_PRIV_NAT_EQ_161_161 () 171 | #define ML99_PRIV_NAT_EQ_162_162 () 172 | #define ML99_PRIV_NAT_EQ_163_163 () 173 | #define ML99_PRIV_NAT_EQ_164_164 () 174 | #define ML99_PRIV_NAT_EQ_165_165 () 175 | #define ML99_PRIV_NAT_EQ_166_166 () 176 | #define ML99_PRIV_NAT_EQ_167_167 () 177 | #define ML99_PRIV_NAT_EQ_168_168 () 178 | #define ML99_PRIV_NAT_EQ_169_169 () 179 | #define ML99_PRIV_NAT_EQ_170_170 () 180 | #define ML99_PRIV_NAT_EQ_171_171 () 181 | #define ML99_PRIV_NAT_EQ_172_172 () 182 | #define ML99_PRIV_NAT_EQ_173_173 () 183 | #define ML99_PRIV_NAT_EQ_174_174 () 184 | #define ML99_PRIV_NAT_EQ_175_175 () 185 | #define ML99_PRIV_NAT_EQ_176_176 () 186 | #define ML99_PRIV_NAT_EQ_177_177 () 187 | #define ML99_PRIV_NAT_EQ_178_178 () 188 | #define ML99_PRIV_NAT_EQ_179_179 () 189 | #define ML99_PRIV_NAT_EQ_180_180 () 190 | #define ML99_PRIV_NAT_EQ_181_181 () 191 | #define ML99_PRIV_NAT_EQ_182_182 () 192 | #define ML99_PRIV_NAT_EQ_183_183 () 193 | #define ML99_PRIV_NAT_EQ_184_184 () 194 | #define ML99_PRIV_NAT_EQ_185_185 () 195 | #define ML99_PRIV_NAT_EQ_186_186 () 196 | #define ML99_PRIV_NAT_EQ_187_187 () 197 | #define ML99_PRIV_NAT_EQ_188_188 () 198 | #define ML99_PRIV_NAT_EQ_189_189 () 199 | #define ML99_PRIV_NAT_EQ_190_190 () 200 | #define ML99_PRIV_NAT_EQ_191_191 () 201 | #define ML99_PRIV_NAT_EQ_192_192 () 202 | #define ML99_PRIV_NAT_EQ_193_193 () 203 | #define ML99_PRIV_NAT_EQ_194_194 () 204 | #define ML99_PRIV_NAT_EQ_195_195 () 205 | #define ML99_PRIV_NAT_EQ_196_196 () 206 | #define ML99_PRIV_NAT_EQ_197_197 () 207 | #define ML99_PRIV_NAT_EQ_198_198 () 208 | #define ML99_PRIV_NAT_EQ_199_199 () 209 | #define ML99_PRIV_NAT_EQ_200_200 () 210 | #define ML99_PRIV_NAT_EQ_201_201 () 211 | #define ML99_PRIV_NAT_EQ_202_202 () 212 | #define ML99_PRIV_NAT_EQ_203_203 () 213 | #define ML99_PRIV_NAT_EQ_204_204 () 214 | #define ML99_PRIV_NAT_EQ_205_205 () 215 | #define ML99_PRIV_NAT_EQ_206_206 () 216 | #define ML99_PRIV_NAT_EQ_207_207 () 217 | #define ML99_PRIV_NAT_EQ_208_208 () 218 | #define ML99_PRIV_NAT_EQ_209_209 () 219 | #define ML99_PRIV_NAT_EQ_210_210 () 220 | #define ML99_PRIV_NAT_EQ_211_211 () 221 | #define ML99_PRIV_NAT_EQ_212_212 () 222 | #define ML99_PRIV_NAT_EQ_213_213 () 223 | #define ML99_PRIV_NAT_EQ_214_214 () 224 | #define ML99_PRIV_NAT_EQ_215_215 () 225 | #define ML99_PRIV_NAT_EQ_216_216 () 226 | #define ML99_PRIV_NAT_EQ_217_217 () 227 | #define ML99_PRIV_NAT_EQ_218_218 () 228 | #define ML99_PRIV_NAT_EQ_219_219 () 229 | #define ML99_PRIV_NAT_EQ_220_220 () 230 | #define ML99_PRIV_NAT_EQ_221_221 () 231 | #define ML99_PRIV_NAT_EQ_222_222 () 232 | #define ML99_PRIV_NAT_EQ_223_223 () 233 | #define ML99_PRIV_NAT_EQ_224_224 () 234 | #define ML99_PRIV_NAT_EQ_225_225 () 235 | #define ML99_PRIV_NAT_EQ_226_226 () 236 | #define ML99_PRIV_NAT_EQ_227_227 () 237 | #define ML99_PRIV_NAT_EQ_228_228 () 238 | #define ML99_PRIV_NAT_EQ_229_229 () 239 | #define ML99_PRIV_NAT_EQ_230_230 () 240 | #define ML99_PRIV_NAT_EQ_231_231 () 241 | #define ML99_PRIV_NAT_EQ_232_232 () 242 | #define ML99_PRIV_NAT_EQ_233_233 () 243 | #define ML99_PRIV_NAT_EQ_234_234 () 244 | #define ML99_PRIV_NAT_EQ_235_235 () 245 | #define ML99_PRIV_NAT_EQ_236_236 () 246 | #define ML99_PRIV_NAT_EQ_237_237 () 247 | #define ML99_PRIV_NAT_EQ_238_238 () 248 | #define ML99_PRIV_NAT_EQ_239_239 () 249 | #define ML99_PRIV_NAT_EQ_240_240 () 250 | #define ML99_PRIV_NAT_EQ_241_241 () 251 | #define ML99_PRIV_NAT_EQ_242_242 () 252 | #define ML99_PRIV_NAT_EQ_243_243 () 253 | #define ML99_PRIV_NAT_EQ_244_244 () 254 | #define ML99_PRIV_NAT_EQ_245_245 () 255 | #define ML99_PRIV_NAT_EQ_246_246 () 256 | #define ML99_PRIV_NAT_EQ_247_247 () 257 | #define ML99_PRIV_NAT_EQ_248_248 () 258 | #define ML99_PRIV_NAT_EQ_249_249 () 259 | #define ML99_PRIV_NAT_EQ_250_250 () 260 | #define ML99_PRIV_NAT_EQ_251_251 () 261 | #define ML99_PRIV_NAT_EQ_252_252 () 262 | #define ML99_PRIV_NAT_EQ_253_253 () 263 | #define ML99_PRIV_NAT_EQ_254_254 () 264 | #define ML99_PRIV_NAT_EQ_255_255 () 265 | 266 | #endif // ML99_NAT_EQ_H 267 | -------------------------------------------------------------------------------- /include/metalang99/nat/inc.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_NAT_INC_H 2 | #define ML99_NAT_INC_H 3 | 4 | #define ML99_PRIV_INC(x) ML99_PRIV_INC_AUX(x) 5 | #define ML99_PRIV_INC_AUX(x) ML99_PRIV_INC_##x 6 | 7 | #define ML99_PRIV_INC_0 1 8 | #define ML99_PRIV_INC_1 2 9 | #define ML99_PRIV_INC_2 3 10 | #define ML99_PRIV_INC_3 4 11 | #define ML99_PRIV_INC_4 5 12 | #define ML99_PRIV_INC_5 6 13 | #define ML99_PRIV_INC_6 7 14 | #define ML99_PRIV_INC_7 8 15 | #define ML99_PRIV_INC_8 9 16 | #define ML99_PRIV_INC_9 10 17 | #define ML99_PRIV_INC_10 11 18 | #define ML99_PRIV_INC_11 12 19 | #define ML99_PRIV_INC_12 13 20 | #define ML99_PRIV_INC_13 14 21 | #define ML99_PRIV_INC_14 15 22 | #define ML99_PRIV_INC_15 16 23 | #define ML99_PRIV_INC_16 17 24 | #define ML99_PRIV_INC_17 18 25 | #define ML99_PRIV_INC_18 19 26 | #define ML99_PRIV_INC_19 20 27 | #define ML99_PRIV_INC_20 21 28 | #define ML99_PRIV_INC_21 22 29 | #define ML99_PRIV_INC_22 23 30 | #define ML99_PRIV_INC_23 24 31 | #define ML99_PRIV_INC_24 25 32 | #define ML99_PRIV_INC_25 26 33 | #define ML99_PRIV_INC_26 27 34 | #define ML99_PRIV_INC_27 28 35 | #define ML99_PRIV_INC_28 29 36 | #define ML99_PRIV_INC_29 30 37 | #define ML99_PRIV_INC_30 31 38 | #define ML99_PRIV_INC_31 32 39 | #define ML99_PRIV_INC_32 33 40 | #define ML99_PRIV_INC_33 34 41 | #define ML99_PRIV_INC_34 35 42 | #define ML99_PRIV_INC_35 36 43 | #define ML99_PRIV_INC_36 37 44 | #define ML99_PRIV_INC_37 38 45 | #define ML99_PRIV_INC_38 39 46 | #define ML99_PRIV_INC_39 40 47 | #define ML99_PRIV_INC_40 41 48 | #define ML99_PRIV_INC_41 42 49 | #define ML99_PRIV_INC_42 43 50 | #define ML99_PRIV_INC_43 44 51 | #define ML99_PRIV_INC_44 45 52 | #define ML99_PRIV_INC_45 46 53 | #define ML99_PRIV_INC_46 47 54 | #define ML99_PRIV_INC_47 48 55 | #define ML99_PRIV_INC_48 49 56 | #define ML99_PRIV_INC_49 50 57 | #define ML99_PRIV_INC_50 51 58 | #define ML99_PRIV_INC_51 52 59 | #define ML99_PRIV_INC_52 53 60 | #define ML99_PRIV_INC_53 54 61 | #define ML99_PRIV_INC_54 55 62 | #define ML99_PRIV_INC_55 56 63 | #define ML99_PRIV_INC_56 57 64 | #define ML99_PRIV_INC_57 58 65 | #define ML99_PRIV_INC_58 59 66 | #define ML99_PRIV_INC_59 60 67 | #define ML99_PRIV_INC_60 61 68 | #define ML99_PRIV_INC_61 62 69 | #define ML99_PRIV_INC_62 63 70 | #define ML99_PRIV_INC_63 64 71 | #define ML99_PRIV_INC_64 65 72 | #define ML99_PRIV_INC_65 66 73 | #define ML99_PRIV_INC_66 67 74 | #define ML99_PRIV_INC_67 68 75 | #define ML99_PRIV_INC_68 69 76 | #define ML99_PRIV_INC_69 70 77 | #define ML99_PRIV_INC_70 71 78 | #define ML99_PRIV_INC_71 72 79 | #define ML99_PRIV_INC_72 73 80 | #define ML99_PRIV_INC_73 74 81 | #define ML99_PRIV_INC_74 75 82 | #define ML99_PRIV_INC_75 76 83 | #define ML99_PRIV_INC_76 77 84 | #define ML99_PRIV_INC_77 78 85 | #define ML99_PRIV_INC_78 79 86 | #define ML99_PRIV_INC_79 80 87 | #define ML99_PRIV_INC_80 81 88 | #define ML99_PRIV_INC_81 82 89 | #define ML99_PRIV_INC_82 83 90 | #define ML99_PRIV_INC_83 84 91 | #define ML99_PRIV_INC_84 85 92 | #define ML99_PRIV_INC_85 86 93 | #define ML99_PRIV_INC_86 87 94 | #define ML99_PRIV_INC_87 88 95 | #define ML99_PRIV_INC_88 89 96 | #define ML99_PRIV_INC_89 90 97 | #define ML99_PRIV_INC_90 91 98 | #define ML99_PRIV_INC_91 92 99 | #define ML99_PRIV_INC_92 93 100 | #define ML99_PRIV_INC_93 94 101 | #define ML99_PRIV_INC_94 95 102 | #define ML99_PRIV_INC_95 96 103 | #define ML99_PRIV_INC_96 97 104 | #define ML99_PRIV_INC_97 98 105 | #define ML99_PRIV_INC_98 99 106 | #define ML99_PRIV_INC_99 100 107 | #define ML99_PRIV_INC_100 101 108 | #define ML99_PRIV_INC_101 102 109 | #define ML99_PRIV_INC_102 103 110 | #define ML99_PRIV_INC_103 104 111 | #define ML99_PRIV_INC_104 105 112 | #define ML99_PRIV_INC_105 106 113 | #define ML99_PRIV_INC_106 107 114 | #define ML99_PRIV_INC_107 108 115 | #define ML99_PRIV_INC_108 109 116 | #define ML99_PRIV_INC_109 110 117 | #define ML99_PRIV_INC_110 111 118 | #define ML99_PRIV_INC_111 112 119 | #define ML99_PRIV_INC_112 113 120 | #define ML99_PRIV_INC_113 114 121 | #define ML99_PRIV_INC_114 115 122 | #define ML99_PRIV_INC_115 116 123 | #define ML99_PRIV_INC_116 117 124 | #define ML99_PRIV_INC_117 118 125 | #define ML99_PRIV_INC_118 119 126 | #define ML99_PRIV_INC_119 120 127 | #define ML99_PRIV_INC_120 121 128 | #define ML99_PRIV_INC_121 122 129 | #define ML99_PRIV_INC_122 123 130 | #define ML99_PRIV_INC_123 124 131 | #define ML99_PRIV_INC_124 125 132 | #define ML99_PRIV_INC_125 126 133 | #define ML99_PRIV_INC_126 127 134 | #define ML99_PRIV_INC_127 128 135 | #define ML99_PRIV_INC_128 129 136 | #define ML99_PRIV_INC_129 130 137 | #define ML99_PRIV_INC_130 131 138 | #define ML99_PRIV_INC_131 132 139 | #define ML99_PRIV_INC_132 133 140 | #define ML99_PRIV_INC_133 134 141 | #define ML99_PRIV_INC_134 135 142 | #define ML99_PRIV_INC_135 136 143 | #define ML99_PRIV_INC_136 137 144 | #define ML99_PRIV_INC_137 138 145 | #define ML99_PRIV_INC_138 139 146 | #define ML99_PRIV_INC_139 140 147 | #define ML99_PRIV_INC_140 141 148 | #define ML99_PRIV_INC_141 142 149 | #define ML99_PRIV_INC_142 143 150 | #define ML99_PRIV_INC_143 144 151 | #define ML99_PRIV_INC_144 145 152 | #define ML99_PRIV_INC_145 146 153 | #define ML99_PRIV_INC_146 147 154 | #define ML99_PRIV_INC_147 148 155 | #define ML99_PRIV_INC_148 149 156 | #define ML99_PRIV_INC_149 150 157 | #define ML99_PRIV_INC_150 151 158 | #define ML99_PRIV_INC_151 152 159 | #define ML99_PRIV_INC_152 153 160 | #define ML99_PRIV_INC_153 154 161 | #define ML99_PRIV_INC_154 155 162 | #define ML99_PRIV_INC_155 156 163 | #define ML99_PRIV_INC_156 157 164 | #define ML99_PRIV_INC_157 158 165 | #define ML99_PRIV_INC_158 159 166 | #define ML99_PRIV_INC_159 160 167 | #define ML99_PRIV_INC_160 161 168 | #define ML99_PRIV_INC_161 162 169 | #define ML99_PRIV_INC_162 163 170 | #define ML99_PRIV_INC_163 164 171 | #define ML99_PRIV_INC_164 165 172 | #define ML99_PRIV_INC_165 166 173 | #define ML99_PRIV_INC_166 167 174 | #define ML99_PRIV_INC_167 168 175 | #define ML99_PRIV_INC_168 169 176 | #define ML99_PRIV_INC_169 170 177 | #define ML99_PRIV_INC_170 171 178 | #define ML99_PRIV_INC_171 172 179 | #define ML99_PRIV_INC_172 173 180 | #define ML99_PRIV_INC_173 174 181 | #define ML99_PRIV_INC_174 175 182 | #define ML99_PRIV_INC_175 176 183 | #define ML99_PRIV_INC_176 177 184 | #define ML99_PRIV_INC_177 178 185 | #define ML99_PRIV_INC_178 179 186 | #define ML99_PRIV_INC_179 180 187 | #define ML99_PRIV_INC_180 181 188 | #define ML99_PRIV_INC_181 182 189 | #define ML99_PRIV_INC_182 183 190 | #define ML99_PRIV_INC_183 184 191 | #define ML99_PRIV_INC_184 185 192 | #define ML99_PRIV_INC_185 186 193 | #define ML99_PRIV_INC_186 187 194 | #define ML99_PRIV_INC_187 188 195 | #define ML99_PRIV_INC_188 189 196 | #define ML99_PRIV_INC_189 190 197 | #define ML99_PRIV_INC_190 191 198 | #define ML99_PRIV_INC_191 192 199 | #define ML99_PRIV_INC_192 193 200 | #define ML99_PRIV_INC_193 194 201 | #define ML99_PRIV_INC_194 195 202 | #define ML99_PRIV_INC_195 196 203 | #define ML99_PRIV_INC_196 197 204 | #define ML99_PRIV_INC_197 198 205 | #define ML99_PRIV_INC_198 199 206 | #define ML99_PRIV_INC_199 200 207 | #define ML99_PRIV_INC_200 201 208 | #define ML99_PRIV_INC_201 202 209 | #define ML99_PRIV_INC_202 203 210 | #define ML99_PRIV_INC_203 204 211 | #define ML99_PRIV_INC_204 205 212 | #define ML99_PRIV_INC_205 206 213 | #define ML99_PRIV_INC_206 207 214 | #define ML99_PRIV_INC_207 208 215 | #define ML99_PRIV_INC_208 209 216 | #define ML99_PRIV_INC_209 210 217 | #define ML99_PRIV_INC_210 211 218 | #define ML99_PRIV_INC_211 212 219 | #define ML99_PRIV_INC_212 213 220 | #define ML99_PRIV_INC_213 214 221 | #define ML99_PRIV_INC_214 215 222 | #define ML99_PRIV_INC_215 216 223 | #define ML99_PRIV_INC_216 217 224 | #define ML99_PRIV_INC_217 218 225 | #define ML99_PRIV_INC_218 219 226 | #define ML99_PRIV_INC_219 220 227 | #define ML99_PRIV_INC_220 221 228 | #define ML99_PRIV_INC_221 222 229 | #define ML99_PRIV_INC_222 223 230 | #define ML99_PRIV_INC_223 224 231 | #define ML99_PRIV_INC_224 225 232 | #define ML99_PRIV_INC_225 226 233 | #define ML99_PRIV_INC_226 227 234 | #define ML99_PRIV_INC_227 228 235 | #define ML99_PRIV_INC_228 229 236 | #define ML99_PRIV_INC_229 230 237 | #define ML99_PRIV_INC_230 231 238 | #define ML99_PRIV_INC_231 232 239 | #define ML99_PRIV_INC_232 233 240 | #define ML99_PRIV_INC_233 234 241 | #define ML99_PRIV_INC_234 235 242 | #define ML99_PRIV_INC_235 236 243 | #define ML99_PRIV_INC_236 237 244 | #define ML99_PRIV_INC_237 238 245 | #define ML99_PRIV_INC_238 239 246 | #define ML99_PRIV_INC_239 240 247 | #define ML99_PRIV_INC_240 241 248 | #define ML99_PRIV_INC_241 242 249 | #define ML99_PRIV_INC_242 243 250 | #define ML99_PRIV_INC_243 244 251 | #define ML99_PRIV_INC_244 245 252 | #define ML99_PRIV_INC_245 246 253 | #define ML99_PRIV_INC_246 247 254 | #define ML99_PRIV_INC_247 248 255 | #define ML99_PRIV_INC_248 249 256 | #define ML99_PRIV_INC_249 250 257 | #define ML99_PRIV_INC_250 251 258 | #define ML99_PRIV_INC_251 252 259 | #define ML99_PRIV_INC_252 253 260 | #define ML99_PRIV_INC_253 254 261 | #define ML99_PRIV_INC_254 255 262 | #define ML99_PRIV_INC_255 0 263 | 264 | #endif // ML99_NAT_INC_H 265 | -------------------------------------------------------------------------------- /include/metalang99/priv/bool.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_PRIV_BOOL_H 2 | #define ML99_PRIV_BOOL_H 3 | 4 | #define ML99_PRIV_TRUE(...) 1 5 | #define ML99_PRIV_FALSE(...) 0 6 | 7 | #define ML99_PRIV_NOT(b) ML99_PRIV_LOGICAL_OVERLOAD_SINGLE(ML99_PRIV_NOT_, b) 8 | #define ML99_PRIV_NOT_0 1 9 | #define ML99_PRIV_NOT_1 0 10 | 11 | #define ML99_PRIV_AND(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_AND_, x, y) 12 | #define ML99_PRIV_AND_00 0 13 | #define ML99_PRIV_AND_01 0 14 | #define ML99_PRIV_AND_10 0 15 | #define ML99_PRIV_AND_11 1 16 | 17 | #define ML99_PRIV_OR(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_OR_, x, y) 18 | #define ML99_PRIV_OR_00 0 19 | #define ML99_PRIV_OR_01 1 20 | #define ML99_PRIV_OR_10 1 21 | #define ML99_PRIV_OR_11 1 22 | 23 | #define ML99_PRIV_OR3(a, b, c) ML99_PRIV_OR(a, ML99_PRIV_OR(b, c)) 24 | #define ML99_PRIV_OR4(a, b, c, d) ML99_PRIV_OR3(a, b, ML99_PRIV_OR(c, d)) 25 | 26 | #define ML99_PRIV_XOR(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_XOR_, x, y) 27 | #define ML99_PRIV_XOR_00 0 28 | #define ML99_PRIV_XOR_01 1 29 | #define ML99_PRIV_XOR_10 1 30 | #define ML99_PRIV_XOR_11 0 31 | 32 | #define ML99_PRIV_BOOL_EQ(x, y) ML99_PRIV_LOGICAL_OVERLOAD(ML99_PRIV_BOOL_EQ_, x, y) 33 | #define ML99_PRIV_BOOL_EQ_00 1 34 | #define ML99_PRIV_BOOL_EQ_01 0 35 | #define ML99_PRIV_BOOL_EQ_10 0 36 | #define ML99_PRIV_BOOL_EQ_11 1 37 | 38 | #define ML99_PRIV_LOGICAL_OVERLOAD(op, x, y) op##x##y 39 | #define ML99_PRIV_LOGICAL_OVERLOAD_SINGLE(op, b) op##b 40 | 41 | #define ML99_PRIV_IF(cond, x, y) ML99_PRIV_IF_OVERLOAD(cond)(x, y) 42 | #define ML99_PRIV_IF_OVERLOAD(cond) ML99_PRIV_IF_##cond 43 | #define ML99_PRIV_IF_0(_x, y) y 44 | #define ML99_PRIV_IF_1(x, _y) x 45 | 46 | #endif // ML99_PRIV_BOOL_H 47 | -------------------------------------------------------------------------------- /include/metalang99/priv/compiler_specific.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_PRIV_COMPILER_SPECIFIC_H 2 | #define ML99_PRIV_COMPILER_SPECIFIC_H 3 | 4 | #define ML99_PRIV_C11_VERSION 201112L 5 | 6 | // GCC 4.6 Release Series: . 7 | #define ML99_PRIV_IS_GCC_4_6_OR_HIGHER ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ >= 5)) 8 | 9 | #ifdef __GNUC__ 10 | #define ML99_PRIV_COMPILER_ATTR_UNUSED __attribute__((unused)) 11 | #else 12 | #define ML99_PRIV_COMPILER_ATTR_UNUSED 13 | #endif 14 | 15 | // ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE { 16 | 17 | #if __STDC__ && __STDC_VERSION__ >= ML99_PRIV_C11_VERSION 18 | 19 | #define ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE 20 | 21 | /* 22 | * On MSVC, `__STDC__` expands to 0 if the `\Za` option was not specified, but the thing is that it 23 | * nevertheless supports C11's `_Static_assert`. 24 | * 25 | * MSVC Standard predefined macros: 26 | * . 27 | */ 28 | #elif defined(_MSC_VER) && __STDC_VERSION__ >= ML99_PRIV_C11_VERSION 29 | #define ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE 30 | #endif 31 | // } (ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE) 32 | 33 | // ML99_PRIV_EMIT_ERROR { 34 | 35 | #ifdef ML99_PRIV_C11_STATIC_ASSERT_AVAILABLE 36 | #define ML99_PRIV_EMIT_ERROR ML99_PRIV_STATIC_ASSERT_ERROR 37 | #elif defined(__clang__) 38 | 39 | #if __has_extension(c_static_assert) 40 | #define ML99_PRIV_EMIT_ERROR ML99_PRIV_STATIC_ASSERT_ERROR 41 | #endif 42 | 43 | #elif defined(__GNUC__) 44 | 45 | #if ML99_PRIV_IS_GCC_4_6_OR_HIGHER 46 | #define ML99_PRIV_EMIT_ERROR ML99_PRIV_STATIC_ASSERT_ERROR 47 | #else 48 | 49 | // GCC Common Function Attributes: 50 | // . 51 | #define ML99_PRIV_EMIT_ERROR(message) \ 52 | void __attribute__((constructor, error(message))) ML99_CAT(ml99_error_, __LINE__)(void) { \ 53 | ML99_CAT(ml99_error_, __LINE__)(); \ 54 | } 55 | 56 | #endif 57 | 58 | #endif 59 | 60 | #if !defined(ML99_PRIV_EMIT_ERROR) && !defined(ML99_ALLOW_POOR_DIAGNOSTICS) 61 | #error Your compiler doesn't support decent diagnostic messages. \ 62 | You'll have to search for Metalang99 errors in a preprocessed-only file (-E) by yourself. \ 63 | Define ML99_ALLOW_POOR_DIAGNOSTICS to suppress this error. 64 | #endif 65 | 66 | #define ML99_PRIV_STATIC_ASSERT_ERROR(message) _Static_assert(0, message) 67 | // } (ML99_PRIV_EMIT_ERROR) 68 | 69 | #endif // ML99_PRIV_COMPILER_SPECIFIC_H 70 | -------------------------------------------------------------------------------- /include/metalang99/priv/tuple.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_PRIV_TUPLE_H 2 | #define ML99_PRIV_TUPLE_H 3 | 4 | #include 5 | #include 6 | 7 | #define ML99_PRIV_IS_TUPLE(x) ML99_PRIV_NOT(ML99_PRIV_IS_UNTUPLE(x)) 8 | #define ML99_PRIV_IS_TUPLE_FAST(x) ML99_PRIV_NOT(ML99_PRIV_IS_UNTUPLE_FAST(x)) 9 | 10 | #define ML99_PRIV_IS_UNTUPLE(x) \ 11 | ML99_PRIV_IF( \ 12 | ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(x), \ 13 | ML99_PRIV_TRUE, \ 14 | ML99_PRIV_IS_UNTUPLE_FAST) \ 15 | (x) 16 | 17 | #define ML99_PRIV_IS_UNTUPLE_FAST(x) ML99_PRIV_SND(ML99_PRIV_IS_UNTUPLE_FAST_TEST x, 1) 18 | #define ML99_PRIV_IS_UNTUPLE_FAST_TEST(...) ~, 0 19 | 20 | #define ML99_PRIV_UNTUPLE(x) ML99_PRIV_EXPAND x 21 | 22 | /** 23 | * Checks whether @p x takes the form `(...) (...) ...`. 24 | * 25 | * This often happens when you miss a comma between items: 26 | * - `v(123) v(456)` 27 | * - `(Foo, int) (Bar, int)` (as in Datatype99) 28 | * - etc. 29 | */ 30 | #define ML99_PRIV_IS_DOUBLE_TUPLE_BEGINNING(x) \ 31 | ML99_PRIV_CONTAINS_COMMA(ML99_PRIV_EXPAND(ML99_PRIV_COMMA ML99_PRIV_EMPTY x)) 32 | 33 | #endif // ML99_PRIV_TUPLE_H 34 | -------------------------------------------------------------------------------- /include/metalang99/priv/util.h: -------------------------------------------------------------------------------- 1 | #ifndef ML99_PRIV_UTIL_H 2 | #define ML99_PRIV_UTIL_H 3 | 4 | #define ML99_PRIV_CAT(x, y) ML99_PRIV_PRIMITIVE_CAT(x, y) 5 | #define ML99_PRIV_PRIMITIVE_CAT(x, y) x##y 6 | 7 | #define ML99_PRIV_CAT3(x, y, z) ML99_PRIV_PRIMITIVE_CAT3(x, y, z) 8 | #define ML99_PRIV_PRIMITIVE_CAT3(x, y, z) x##y##z 9 | 10 | #define ML99_PRIV_EXPAND(...) __VA_ARGS__ 11 | #define ML99_PRIV_EMPTY(...) 12 | #define ML99_PRIV_COMMA(...) , 13 | 14 | #define ML99_PRIV_HEAD(...) ML99_PRIV_HEAD_AUX(__VA_ARGS__, ~) 15 | #define ML99_PRIV_HEAD_AUX(x, ...) x 16 | 17 | #define ML99_PRIV_TAIL(...) ML99_PRIV_TAIL_AUX(__VA_ARGS__) 18 | #define ML99_PRIV_TAIL_AUX(_x, ...) __VA_ARGS__ 19 | 20 | #define ML99_PRIV_SND(...) ML99_PRIV_SND_AUX(__VA_ARGS__, ~) 21 | #define ML99_PRIV_SND_AUX(_x, y, ...) y 22 | 23 | #define ML99_PRIV_CONTAINS_COMMA(...) ML99_PRIV_X_AS_COMMA(__VA_ARGS__, ML99_PRIV_COMMA(), ~) 24 | #define ML99_PRIV_X_AS_COMMA(_head, x, ...) ML99_PRIV_CONTAINS_COMMA_RESULT(x, 0, 1, ~) 25 | #define ML99_PRIV_CONTAINS_COMMA_RESULT(x, _, result, ...) result 26 | 27 | #endif // ML99_PRIV_UTIL_H 28 | -------------------------------------------------------------------------------- /include/metalang99/seq.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Sequences: `(x)(y)(z)`. 4 | * 5 | * A sequence is represented as `(...) (...) ...`. For example, these are sequences: 6 | * - `(~, ~, ~)` 7 | * - `(1)(2)(3)` 8 | * - `(+, -, *, /)(123)(~)` 9 | * 10 | * Sequences can represent syntax like `X(...) Y(...) Z(...)`, where `X`, `Y`, and `Z` expand to a 11 | * [tuple](tuple.html), thereby forming a sequence. A perfect example is 12 | * [Interface99](https://github.com/hirrolot/interface99), which allows a user to define a software 13 | * interface via a number of `vfunc(...)` macro invocations: 14 | * 15 | * @code 16 | * #define Shape_IFACE \ 17 | * vfunc( int, perim, const VSelf) \ 18 | * vfunc(void, scale, VSelf, int factor) 19 | * 20 | * interface(Shape); 21 | * @endcode 22 | * 23 | * With `vfunc` being defined as follows (simplified): 24 | * 25 | * @code 26 | * #define vfunc(ret_ty, name, ...) (ret_ty, name, __VA_ARGS__) 27 | * @endcode 28 | * 29 | * @note Sequences are more time and space-efficient than lists, but export less functionality; if a 30 | * needed function is missed, invoking #ML99_listFromSeq and then manipulating with the resulting 31 | * Cons-list might be helpful. 32 | */ 33 | 34 | #ifndef ML99_SEQ_H 35 | #define ML99_SEQ_H 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | 43 | /** 44 | * True iff @p seq contains no elements (which means an empty preprocessing lexeme). 45 | * 46 | * # Examples 47 | * 48 | * @code 49 | * #include 50 | * 51 | * // 1 52 | * ML99_seqIsEmpty(v()) 53 | * 54 | * // 0 55 | * ML99_seqIsEmpty(v((~)(~)(~))) 56 | * @endcode 57 | */ 58 | #define ML99_seqIsEmpty(seq) ML99_call(ML99_seqIsEmpty, seq) 59 | 60 | /** 61 | * Expands to a metafunction extracting the @p i -indexed element of @p seq. 62 | * 63 | * @p i can range from 0 to 7, inclusively. 64 | * 65 | * # Examples 66 | * 67 | * @code 68 | * #include 69 | * 70 | * // 2 71 | * ML99_seqGet(1)(v((1)(2)(3))) 72 | * @endcode 73 | */ 74 | #define ML99_seqGet(i) ML99_PRIV_CAT(ML99_PRIV_seqGet_, i) 75 | 76 | /** 77 | * Extracts the tail of @p seq. 78 | * 79 | * @p seq must contain at least one element. If @p seq contains **only** one element, the result is 80 | * `ML99_empty()`. 81 | * 82 | * # Examples 83 | * 84 | * @code 85 | * #include 86 | * 87 | * // (2)(3) 88 | * ML99_seqTail(v((1)(2)(3))) 89 | * @endcode 90 | */ 91 | #define ML99_seqTail(seq) ML99_call(ML99_seqTail, seq) 92 | 93 | /** 94 | * Applies @p f to each element in @p seq. 95 | * 96 | * The result is `ML99_appl(f, x1) ... ML99_appl(f, xN)`. 97 | * 98 | * # Examples 99 | * 100 | * @code 101 | * #include 102 | * 103 | * #define F_IMPL(x) v(@x) 104 | * #define F_ARITY 1 105 | * 106 | * // @x @y @z 107 | * ML99_seqForEach(v(F), v((x)(y)(z))) 108 | * @endcode 109 | */ 110 | #define ML99_seqForEach(f, seq) ML99_call(ML99_seqForEach, f, seq) 111 | 112 | /** 113 | * Applies @p f to each element in @p seq with an index. 114 | * 115 | * The result is `ML99_appl2(f, 0, x1) ... ML99_appl2(f, N - 1, xN)`. 116 | * 117 | * @code 118 | * #include 119 | * 120 | * #define F_IMPL(i, x) v(@x##i) 121 | * #define F_ARITY 2 122 | * 123 | * // @x0 @y1 @z2 124 | * ML99_seqForEachI(v(F), v((x)(y)(z))) 125 | * @endcode 126 | */ 127 | #define ML99_seqForEachI(f, seq) ML99_call(ML99_seqForEachI, f, seq) 128 | 129 | #define ML99_SEQ_IS_EMPTY(seq) ML99_PRIV_NOT(ML99_PRIV_CONTAINS_COMMA(ML99_PRIV_COMMA seq)) 130 | #define ML99_SEQ_GET(i) ML99_PRIV_CAT(ML99_PRIV_SEQ_GET_, i) 131 | #define ML99_SEQ_TAIL(seq) ML99_PRIV_TAIL(ML99_PRIV_COMMA seq) 132 | 133 | #ifndef DOXYGEN_IGNORE 134 | 135 | #define ML99_seqIsEmpty_IMPL(seq) v(ML99_SEQ_IS_EMPTY(seq)) 136 | 137 | #define ML99_PRIV_seqGet_0(seq) ML99_call(ML99_PRIV_seqGet_0, seq) 138 | #define ML99_PRIV_seqGet_1(seq) ML99_call(ML99_PRIV_seqGet_1, seq) 139 | #define ML99_PRIV_seqGet_2(seq) ML99_call(ML99_PRIV_seqGet_2, seq) 140 | #define ML99_PRIV_seqGet_3(seq) ML99_call(ML99_PRIV_seqGet_3, seq) 141 | #define ML99_PRIV_seqGet_4(seq) ML99_call(ML99_PRIV_seqGet_4, seq) 142 | #define ML99_PRIV_seqGet_5(seq) ML99_call(ML99_PRIV_seqGet_5, seq) 143 | #define ML99_PRIV_seqGet_6(seq) ML99_call(ML99_PRIV_seqGet_6, seq) 144 | #define ML99_PRIV_seqGet_7(seq) ML99_call(ML99_PRIV_seqGet_7, seq) 145 | 146 | #define ML99_PRIV_seqGet_0_IMPL(seq) v(ML99_SEQ_GET(0)(seq)) 147 | #define ML99_PRIV_seqGet_1_IMPL(seq) v(ML99_SEQ_GET(1)(seq)) 148 | #define ML99_PRIV_seqGet_2_IMPL(seq) v(ML99_SEQ_GET(2)(seq)) 149 | #define ML99_PRIV_seqGet_3_IMPL(seq) v(ML99_SEQ_GET(3)(seq)) 150 | #define ML99_PRIV_seqGet_4_IMPL(seq) v(ML99_SEQ_GET(4)(seq)) 151 | #define ML99_PRIV_seqGet_5_IMPL(seq) v(ML99_SEQ_GET(5)(seq)) 152 | #define ML99_PRIV_seqGet_6_IMPL(seq) v(ML99_SEQ_GET(6)(seq)) 153 | #define ML99_PRIV_seqGet_7_IMPL(seq) v(ML99_SEQ_GET(7)(seq)) 154 | 155 | #define ML99_PRIV_SEQ_GET_0(seq) ML99_PRIV_UNTUPLE(ML99_PRIV_HEAD(ML99_PRIV_SEQ_SEPARATE seq)) 156 | #define ML99_PRIV_SEQ_GET_1(seq) ML99_PRIV_SEQ_GET_0(ML99_SEQ_TAIL(seq)) 157 | #define ML99_PRIV_SEQ_GET_2(seq) ML99_PRIV_SEQ_GET_1(ML99_SEQ_TAIL(seq)) 158 | #define ML99_PRIV_SEQ_GET_3(seq) ML99_PRIV_SEQ_GET_2(ML99_SEQ_TAIL(seq)) 159 | #define ML99_PRIV_SEQ_GET_4(seq) ML99_PRIV_SEQ_GET_3(ML99_SEQ_TAIL(seq)) 160 | #define ML99_PRIV_SEQ_GET_5(seq) ML99_PRIV_SEQ_GET_4(ML99_SEQ_TAIL(seq)) 161 | #define ML99_PRIV_SEQ_GET_6(seq) ML99_PRIV_SEQ_GET_5(ML99_SEQ_TAIL(seq)) 162 | #define ML99_PRIV_SEQ_GET_7(seq) ML99_PRIV_SEQ_GET_6(ML99_SEQ_TAIL(seq)) 163 | 164 | #define ML99_PRIV_SEQ_SEPARATE(...) (__VA_ARGS__), 165 | 166 | #define ML99_seqTail_IMPL(seq) v(ML99_SEQ_TAIL(seq)) 167 | 168 | #define ML99_seqForEach_IMPL(f, seq) \ 169 | ML99_PRIV_CAT(ML99_PRIV_seqForEach_, ML99_SEQ_IS_EMPTY(seq))(f, seq) 170 | #define ML99_PRIV_seqForEach_1(...) v(ML99_PRIV_EMPTY()) 171 | #define ML99_PRIV_seqForEach_0(f, seq) \ 172 | ML99_TERMS( \ 173 | ML99_appl_IMPL(f, ML99_SEQ_GET(0)(seq)), \ 174 | ML99_callUneval(ML99_seqForEach, f, ML99_SEQ_TAIL(seq))) 175 | 176 | #define ML99_seqForEachI_IMPL(f, seq) ML99_PRIV_seqForEachIAux_IMPL(f, 0, seq) 177 | #define ML99_PRIV_seqForEachIAux_IMPL(f, i, seq) \ 178 | ML99_PRIV_CAT(ML99_PRIV_seqForEachI_, ML99_SEQ_IS_EMPTY(seq))(f, i, seq) 179 | #define ML99_PRIV_seqForEachI_1(...) v(ML99_PRIV_EMPTY()) 180 | #define ML99_PRIV_seqForEachI_0(f, i, seq) \ 181 | ML99_TERMS( \ 182 | ML99_appl2_IMPL(f, i, ML99_SEQ_GET(0)(seq)), \ 183 | ML99_callUneval(ML99_PRIV_seqForEachIAux, f, ML99_PRIV_INC(i), ML99_SEQ_TAIL(seq))) 184 | 185 | // Arity specifiers { 186 | 187 | #define ML99_seqIsEmpty_ARITY 1 188 | #define ML99_seqTail_ARITY 1 189 | #define ML99_seqForEach_ARITY 2 190 | #define ML99_seqForEachI_ARITY 2 191 | 192 | #define ML99_PRIV_seqGet_0_ARITY 1 193 | #define ML99_PRIV_seqGet_1_ARITY 1 194 | #define ML99_PRIV_seqGet_2_ARITY 1 195 | #define ML99_PRIV_seqGet_3_ARITY 1 196 | #define ML99_PRIV_seqGet_4_ARITY 1 197 | #define ML99_PRIV_seqGet_5_ARITY 1 198 | #define ML99_PRIV_seqGet_6_ARITY 1 199 | #define ML99_PRIV_seqGet_7_ARITY 1 200 | // } (Arity specifiers) 201 | 202 | #endif // DOXYGEN_IGNORE 203 | 204 | #endif // ML99_SEQ_H 205 | -------------------------------------------------------------------------------- /include/metalang99/stmt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Statement chaining. 4 | * 5 | * This module exports a bunch of so-called _statement chaining macros_: they expect a statement 6 | * right after their invocation, and moreover, an invocation of such a macro with a statement 7 | * afterwards altogether form a single statement. 8 | * 9 | * How can this be helpful? Imagine you are writing a macro with the following syntax: 10 | * 11 | * @code 12 | * MY_MACRO(...) { bla bla bla } 13 | * @endcode 14 | * 15 | * Then `MY_MACRO` must expand to a _statement prefix_, i.e., something that expects a statement 16 | * after itself. One possible solution is to make `MY_MACRO` expand to a sequence of statement 17 | * chaining macros like this: 18 | * 19 | * @code 20 | * #define MY_MACRO(...) \ 21 | * ML99_INTRODUCE_VAR_TO_STMT(int x = 5) \ 22 | * ML99_CHAIN_EXPR_STMT(printf("%d\n", x)) \ 23 | * // and so on... 24 | * @endcode 25 | * 26 | * Here #ML99_INTRODUCE_VAR_TO_STMT accepts the statement formed by #ML99_CHAIN_EXPR_STMT, which, in 27 | * turn, accepts the next statement and so on, until a caller of `MY_MACRO` specifies the final 28 | * statement, thus completing the chain. 29 | * 30 | * @see https://www.chiark.greenend.org.uk/~sgtatham/mp/ for a more involved explanation. 31 | */ 32 | 33 | #ifndef ML99_STMT_H 34 | #define ML99_STMT_H 35 | 36 | #include 37 | 38 | /** 39 | * A statement chaining macro that introduces several variable definitions to a statement right 40 | * after its invocation. 41 | * 42 | * Variable definitions must be specified as in the first clause of the for-loop. 43 | * 44 | * Top-level `break`/`continue` inside a user-provided statement are prohibited. 45 | * 46 | * # Example 47 | * 48 | * @code 49 | * #include 50 | * 51 | * for (int i = 0; i < 10; i++) 52 | * ML99_INTRODUCE_VAR_TO_STMT(double x = 5.0, y = 7.0) 53 | * if (i % 2 == 0) 54 | * printf("i = %d, x = %f, y = %f\n", i, x, y); 55 | * @endcode 56 | */ 57 | #define ML99_INTRODUCE_VAR_TO_STMT(...) ML99_PRIV_INTRODUCE_VAR_TO_STMT_INNER(__VA_ARGS__) 58 | 59 | /** 60 | * The same as #ML99_INTRODUCE_VAR_TO_STMT but deals with a single non-`NULL` pointer. 61 | * 62 | * In comparison with #ML99_INTRODUCE_VAR_TO_STMT, this macro generates a little less code. It 63 | * introduces a pointer to @p ty identified by @p name and initialized to @p init. 64 | * 65 | * Top-level `break`/`continue` inside a user-provided statement are prohibited. 66 | * 67 | * # Example 68 | * 69 | * @code 70 | * #include 71 | * 72 | * double x = 5.0, y = 7.0; 73 | * 74 | * for (int i = 0; i < 10; i++) 75 | * ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(double, x_ptr, &x) 76 | * ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(double, y_ptr, &y) 77 | * printf("i = %d, x = %f, y = %f\n", i, *x_ptr, *y_ptr); 78 | * @endcode 79 | * 80 | * @note Unlike #ML99_INTRODUCE_VAR_TO_STMT, the generated pointer is guaranteed to be used at least 81 | * once, meaning that you do not need to suppress the unused variable warning. 82 | * @note @p init is guaranteed to be executed only once. 83 | */ 84 | #define ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(ty, name, init) \ 85 | ML99_PRIV_SHADOWS(for (ty *name = (init); name != 0; name = 0)) 86 | 87 | /** 88 | * A statement chaining macro that executes an expression statement derived from @p expr right 89 | * before the next statement. 90 | * 91 | * Top-level `break`/`continue` inside a user-provided statement are prohibited. 92 | * 93 | * # Example 94 | * 95 | * @code 96 | * #include 97 | * 98 | * int x; 99 | * 100 | * for(;;) 101 | * ML99_CHAIN_EXPR_STMT(x = 5) 102 | * ML99_CHAIN_EXPR_STMT(printf("%d\n", x)) 103 | * puts("abc"); 104 | * @endcode 105 | */ 106 | #define ML99_CHAIN_EXPR_STMT(expr) \ 107 | ML99_PRIV_SHADOWS(for (int ml99_priv_expr_stmt_break = ((expr), 0); \ 108 | ml99_priv_expr_stmt_break != 1; \ 109 | ml99_priv_expr_stmt_break = 1)) 110 | 111 | /** 112 | * The same as #ML99_CHAIN_EXPR_STMT but executes @p expr **after** the next statement. 113 | */ 114 | #define ML99_CHAIN_EXPR_STMT_AFTER(expr) \ 115 | ML99_PRIV_SHADOWS(for (int ml99_priv_expr_stmt_after_break = 0; \ 116 | ml99_priv_expr_stmt_after_break != 1; \ 117 | ((expr), ml99_priv_expr_stmt_after_break = 1))) 118 | 119 | /** 120 | * A statement chaining macro that suppresses the "unused X" warning right before a statement after 121 | * its invocation. 122 | * 123 | * Top-level `break`/`continue` inside a user-provided statement are prohibited. 124 | * 125 | * # Example 126 | * 127 | * @code 128 | * #include 129 | * 130 | * int x, y; 131 | * 132 | * for(;;) 133 | * ML99_SUPPRESS_UNUSED_BEFORE_STMT(x) 134 | * ML99_SUPPRESS_UNUSED_BEFORE_STMT(y) 135 | * puts("abc"); 136 | * @endcode 137 | * 138 | * @deprecated Use `ML99_CHAIN_EXPR_STMT((void)expr)` instead. 139 | */ 140 | #define ML99_SUPPRESS_UNUSED_BEFORE_STMT(expr) ML99_CHAIN_EXPR_STMT((void)expr) 141 | 142 | #ifndef DOXYGEN_IGNORE 143 | 144 | // See . 145 | #ifdef __cplusplus 146 | #define ML99_PRIV_INTRODUCE_VAR_TO_STMT_INNER(...) \ 147 | ML99_PRIV_SHADOWS(for (__VA_ARGS__, \ 148 | *ml99_priv_break_arr[] = {0, 0}, \ 149 | **ml99_priv_break = &ml99_priv_break_arr[0]; \ 150 | ml99_priv_break == &ml99_priv_break_arr[0]; \ 151 | ml99_priv_break++)) 152 | #else 153 | #define ML99_PRIV_INTRODUCE_VAR_TO_STMT_INNER(...) \ 154 | ML99_PRIV_SHADOWS(for (__VA_ARGS__, *ml99_priv_break = (void *)0; \ 155 | ml99_priv_break != (void *)1; \ 156 | ml99_priv_break = (void *)1)) 157 | #endif 158 | 159 | #define ML99_PRIV_SHADOWS(...) \ 160 | ML99_CLANG_PRAGMA("clang diagnostic push") \ 161 | ML99_CLANG_PRAGMA("clang diagnostic ignored \"-Wshadow\"") \ 162 | __VA_ARGS__ \ 163 | ML99_CLANG_PRAGMA("clang diagnostic pop") 164 | 165 | #endif // DOXYGEN_IGNORE 166 | 167 | #endif // ML99_STMT_H 168 | -------------------------------------------------------------------------------- /include/metalang99/variadics.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * Variadic arguments: `x, y, z`. 4 | * 5 | * @note Variadics are more time and space-efficient than lists, but export less functionality; if a 6 | * needed function is missed, invoking #ML99_list and then manipulating with the resulting Cons-list 7 | * might be helpful. 8 | */ 9 | 10 | #ifndef ML99_VARIADICS_H 11 | #define ML99_VARIADICS_H 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | /** 19 | * Computes a count of its arguments. 20 | * 21 | * At most 63 arguments are acceptable. 22 | * 23 | * # Examples 24 | * 25 | * @code 26 | * #include 27 | * 28 | * // 3 29 | * ML99_variadicsCount(v(~, ~, ~)) 30 | * 31 | * // 1 32 | * ML99_variadicsCount() 33 | * @endcode 34 | */ 35 | #define ML99_variadicsCount(...) ML99_call(ML99_variadicsCount, __VA_ARGS__) 36 | 37 | /** 38 | * Tells if it received only one argument or not. 39 | * 40 | * # Examples 41 | * 42 | * @code 43 | * #include 44 | * 45 | * // 1 46 | * ML99_variadicsIsSingle(v(~)) 47 | * 48 | * // 0 49 | * ML99_variadicsIsSingle(v(~, ~, ~)) 50 | * @endcode 51 | */ 52 | #define ML99_variadicsIsSingle(...) ML99_call(ML99_variadicsIsSingle, __VA_ARGS__) 53 | 54 | /** 55 | * Expands to a metafunction extracting the @p i -indexed argument. 56 | * 57 | * @p i can range from 0 to 7, inclusively. 58 | * 59 | * # Examples 60 | * 61 | * @code 62 | * #include 63 | * 64 | * // 2 65 | * ML99_variadicsGet(1)(v(1, 2, 3)) 66 | * @endcode 67 | */ 68 | #define ML99_variadicsGet(i) ML99_PRIV_CAT(ML99_PRIV_variadicsGet_, i) 69 | 70 | /** 71 | * Extracts the tail of its arguments. 72 | * 73 | * At least two arguments must be specified. 74 | * 75 | * # Examples 76 | * 77 | * @code 78 | * #include 79 | * 80 | * // 2, 3 81 | * ML99_variadicsTail(v(1, 2, 3)) 82 | * @endcode 83 | */ 84 | #define ML99_variadicsTail(...) ML99_call(ML99_variadicsTail, __VA_ARGS__) 85 | 86 | /** 87 | * Applies @p f to each argument. 88 | * 89 | * The result is `ML99_appl(f, x1) ... ML99_appl(f, xN)`. 90 | * 91 | * # Examples 92 | * 93 | * @code 94 | * #include 95 | * 96 | * #define F_IMPL(x) v(@x) 97 | * #define F_ARITY 1 98 | * 99 | * // @x @y @z 100 | * ML99_variadicsForEach(v(F), v(x, y, z)) 101 | * @endcode 102 | */ 103 | #define ML99_variadicsForEach(f, ...) ML99_call(ML99_variadicsForEach, f, __VA_ARGS__) 104 | 105 | /** 106 | * Applies @p f to each argument with an index. 107 | * 108 | * The result is `ML99_appl2(f, x1, 0) ... ML99_appl2(f, xN, N - 1)`. 109 | * 110 | * @code 111 | * #include 112 | * 113 | * #define F_IMPL(x, i) v(@x##i) 114 | * #define F_ARITY 2 115 | * 116 | * // @x0 @y1 @z2 117 | * ML99_variadicsForEachI(v(F), v(x, y, z)) 118 | * @endcode 119 | */ 120 | #define ML99_variadicsForEachI(f, ...) ML99_call(ML99_variadicsForEachI, f, __VA_ARGS__) 121 | 122 | /** 123 | * Overloads @p f on a number of arguments. 124 | * 125 | * This function counts the number of provided arguments, appends it to @p f and calls the resulting 126 | * macro identifier with provided arguments. 127 | * 128 | * At most 63 variadic arguments are acceptable. 129 | * 130 | * # Examples 131 | * 132 | * @code 133 | * #include 134 | * 135 | * #define X(...) ML99_OVERLOAD(X_, __VA_ARGS__) 136 | * #define X_1(a) Billie & a 137 | * #define X_2(a, b) Jean & a & b 138 | * 139 | * // Billie & 4 140 | * X(4) 141 | * 142 | * // Jean & 5 & 6 143 | * X(5, 6) 144 | * @endcode 145 | * 146 | * @note @p f need not be postfixed with `_IMPL`. It is literally invoked as `ML99_CAT(f, 147 | * ML99_VARIADICS_COUNT(...))(...)`. 148 | */ 149 | #define ML99_OVERLOAD(f, ...) ML99_PRIV_CAT(f, ML99_PRIV_VARIADICS_COUNT(__VA_ARGS__))(__VA_ARGS__) 150 | 151 | #define ML99_VARIADICS_COUNT(...) ML99_PRIV_VARIADICS_COUNT(__VA_ARGS__) 152 | #define ML99_VARIADICS_IS_SINGLE(...) ML99_PRIV_NOT(ML99_PRIV_CONTAINS_COMMA(__VA_ARGS__)) 153 | #define ML99_VARIADICS_GET(i) ML99_PRIV_CAT(ML99_PRIV_VARIADICS_GET_, i) 154 | #define ML99_VARIADICS_TAIL(...) ML99_PRIV_TAIL(__VA_ARGS__) 155 | 156 | #ifndef DOXYGEN_IGNORE 157 | 158 | #define ML99_variadicsCount_IMPL(...) v(ML99_VARIADICS_COUNT(__VA_ARGS__)) 159 | #define ML99_variadicsIsSingle_IMPL(...) v(ML99_VARIADICS_IS_SINGLE(__VA_ARGS__)) 160 | 161 | #define ML99_PRIV_variadicsGet_0(...) ML99_call(ML99_PRIV_variadicsGet_0, __VA_ARGS__) 162 | #define ML99_PRIV_variadicsGet_1(...) ML99_call(ML99_PRIV_variadicsGet_1, __VA_ARGS__) 163 | #define ML99_PRIV_variadicsGet_2(...) ML99_call(ML99_PRIV_variadicsGet_2, __VA_ARGS__) 164 | #define ML99_PRIV_variadicsGet_3(...) ML99_call(ML99_PRIV_variadicsGet_3, __VA_ARGS__) 165 | #define ML99_PRIV_variadicsGet_4(...) ML99_call(ML99_PRIV_variadicsGet_4, __VA_ARGS__) 166 | #define ML99_PRIV_variadicsGet_5(...) ML99_call(ML99_PRIV_variadicsGet_5, __VA_ARGS__) 167 | #define ML99_PRIV_variadicsGet_6(...) ML99_call(ML99_PRIV_variadicsGet_6, __VA_ARGS__) 168 | #define ML99_PRIV_variadicsGet_7(...) ML99_call(ML99_PRIV_variadicsGet_7, __VA_ARGS__) 169 | 170 | #define ML99_PRIV_variadicsGet_0_IMPL(...) v(ML99_VARIADICS_GET(0)(__VA_ARGS__)) 171 | #define ML99_PRIV_variadicsGet_1_IMPL(...) v(ML99_VARIADICS_GET(1)(__VA_ARGS__)) 172 | #define ML99_PRIV_variadicsGet_2_IMPL(...) v(ML99_VARIADICS_GET(2)(__VA_ARGS__)) 173 | #define ML99_PRIV_variadicsGet_3_IMPL(...) v(ML99_VARIADICS_GET(3)(__VA_ARGS__)) 174 | #define ML99_PRIV_variadicsGet_4_IMPL(...) v(ML99_VARIADICS_GET(4)(__VA_ARGS__)) 175 | #define ML99_PRIV_variadicsGet_5_IMPL(...) v(ML99_VARIADICS_GET(5)(__VA_ARGS__)) 176 | #define ML99_PRIV_variadicsGet_6_IMPL(...) v(ML99_VARIADICS_GET(6)(__VA_ARGS__)) 177 | #define ML99_PRIV_variadicsGet_7_IMPL(...) v(ML99_VARIADICS_GET(7)(__VA_ARGS__)) 178 | 179 | #define ML99_PRIV_VARIADICS_GET_0(...) ML99_PRIV_VARIADICS_GET_AUX_0(__VA_ARGS__, ~) 180 | #define ML99_PRIV_VARIADICS_GET_1(...) ML99_PRIV_VARIADICS_GET_AUX_1(__VA_ARGS__, ~) 181 | #define ML99_PRIV_VARIADICS_GET_2(...) ML99_PRIV_VARIADICS_GET_AUX_2(__VA_ARGS__, ~) 182 | #define ML99_PRIV_VARIADICS_GET_3(...) ML99_PRIV_VARIADICS_GET_AUX_3(__VA_ARGS__, ~) 183 | #define ML99_PRIV_VARIADICS_GET_4(...) ML99_PRIV_VARIADICS_GET_AUX_4(__VA_ARGS__, ~) 184 | #define ML99_PRIV_VARIADICS_GET_5(...) ML99_PRIV_VARIADICS_GET_AUX_5(__VA_ARGS__, ~) 185 | #define ML99_PRIV_VARIADICS_GET_6(...) ML99_PRIV_VARIADICS_GET_AUX_6(__VA_ARGS__, ~) 186 | #define ML99_PRIV_VARIADICS_GET_7(...) ML99_PRIV_VARIADICS_GET_AUX_7(__VA_ARGS__, ~) 187 | 188 | #define ML99_PRIV_VARIADICS_GET_AUX_0(a, ...) a 189 | #define ML99_PRIV_VARIADICS_GET_AUX_1(_a, b, ...) b 190 | #define ML99_PRIV_VARIADICS_GET_AUX_2(_a, _b, c, ...) c 191 | #define ML99_PRIV_VARIADICS_GET_AUX_3(_a, _b, _c, d, ...) d 192 | #define ML99_PRIV_VARIADICS_GET_AUX_4(_a, _b, _c, _d, e, ...) e 193 | #define ML99_PRIV_VARIADICS_GET_AUX_5(_a, _b, _c, _d, _e, f, ...) f 194 | #define ML99_PRIV_VARIADICS_GET_AUX_6(_a, _b, _c, _d, _e, _f, g, ...) g 195 | #define ML99_PRIV_VARIADICS_GET_AUX_7(_a, _b, _c, _d, _e, _f, _g, h, ...) h 196 | 197 | #define ML99_variadicsTail_IMPL(...) v(ML99_VARIADICS_TAIL(__VA_ARGS__)) 198 | 199 | // ML99_variadicsForEach_IMPL { 200 | 201 | #define ML99_variadicsForEach_IMPL(f, ...) \ 202 | ML99_PRIV_CAT(ML99_PRIV_variadicsForEach_, ML99_VARIADICS_IS_SINGLE(__VA_ARGS__)) \ 203 | (f, __VA_ARGS__) 204 | #define ML99_PRIV_variadicsForEach_1(f, x) ML99_appl_IMPL(f, x) 205 | #define ML99_PRIV_variadicsForEach_0(f, x, ...) \ 206 | ML99_TERMS(ML99_appl_IMPL(f, x), ML99_callUneval(ML99_variadicsForEach, f, __VA_ARGS__)) 207 | // } (ML99_variadicsForEach_IMPL) 208 | 209 | // ML99_variadicsForEachI_IMPL { 210 | 211 | #define ML99_variadicsForEachI_IMPL(f, ...) ML99_PRIV_variadicsForEachIAux_IMPL(f, 0, __VA_ARGS__) 212 | 213 | #define ML99_PRIV_variadicsForEachIAux_IMPL(f, i, ...) \ 214 | ML99_PRIV_CAT(ML99_PRIV_variadicsForEachI_, ML99_VARIADICS_IS_SINGLE(__VA_ARGS__)) \ 215 | (f, i, __VA_ARGS__) 216 | 217 | #define ML99_PRIV_variadicsForEachI_1(f, i, x) ML99_appl2_IMPL(f, x, i) 218 | #define ML99_PRIV_variadicsForEachI_0(f, i, x, ...) \ 219 | ML99_TERMS( \ 220 | ML99_appl2_IMPL(f, x, i), \ 221 | ML99_callUneval(ML99_PRIV_variadicsForEachIAux, f, ML99_PRIV_INC(i), __VA_ARGS__)) 222 | // } (ML99_variadicsForEachI_IMPL) 223 | 224 | /* 225 | * The StackOverflow solution: . 226 | * 227 | * This macro supports at most 63 arguments because C99 allows implementations to handle only 127 228 | * parameters/arguments per macro definition/invocation (C99 | 5.2.4 Environmental limits), and 229 | * `ML99_PRIV_VARIADICS_COUNT_AUX` already accepts 64 arguments. 230 | */ 231 | // clang-format off 232 | #define ML99_PRIV_VARIADICS_COUNT(...) \ 233 | ML99_PRIV_VARIADICS_COUNT_AUX( \ 234 | __VA_ARGS__, \ 235 | 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, \ 236 | 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, \ 237 | 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, \ 238 | 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, \ 239 | 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, \ 240 | 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, \ 241 | 3, 2, 1, ~) 242 | 243 | #define ML99_PRIV_VARIADICS_COUNT_AUX( \ 244 | _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ 245 | _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ 246 | _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ 247 | _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ 248 | _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ 249 | _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ 250 | _61, _62, _63, x, ...) \ 251 | x 252 | // clang-format on 253 | 254 | // Arity specifiers { 255 | 256 | #define ML99_variadicsCount_ARITY 1 257 | #define ML99_variadicsIsSingle_ARITY 1 258 | #define ML99_variadicsTail_ARITY 1 259 | #define ML99_variadicsForEach_ARITY 2 260 | #define ML99_variadicsForEachI_ARITY 2 261 | 262 | #define ML99_PRIV_variadicsGet_0_ARITY 1 263 | #define ML99_PRIV_variadicsGet_1_ARITY 1 264 | #define ML99_PRIV_variadicsGet_2_ARITY 1 265 | #define ML99_PRIV_variadicsGet_3_ARITY 1 266 | #define ML99_PRIV_variadicsGet_4_ARITY 1 267 | #define ML99_PRIV_variadicsGet_5_ARITY 1 268 | #define ML99_PRIV_variadicsGet_6_ARITY 1 269 | #define ML99_PRIV_variadicsGet_7_ARITY 1 270 | // } (Arity specifiers) 271 | 272 | #endif // DOXYGEN_IGNORE 273 | 274 | #endif // ML99_VARIADICS_H 275 | -------------------------------------------------------------------------------- /optimization_tips.md: -------------------------------------------------------------------------------- 1 | # Optimization tips 2 | 3 | _This document describes a few optimization tips when using Metalang99._ 4 | 5 | Generally speaking, the fewer reduction steps you perform, the faster you become. A reduction step is a concept defined formally by the [specification]. Here is its informal (and imprecise) description: 6 | 7 | - Every `v(...)` is a reduction step. 8 | - Every `ML99_call(op, ...)` induces as many reduction steps as required to evaluate `op` and `...`. 9 | 10 | To perform fewer reduction steps, you can: 11 | 12 | - use `ML99_callUneval`, 13 | - use plain macros (e.g., `ML99_CAT` instead of `ML99_cat`), 14 | - use optimized versions (e.g., `ML99_listMapInPlace`), 15 | - use tuples/variadics instead of lists, 16 | - call a macro as `_IMPL(...)`, if all the arguments are already evaluated. 17 | 18 |
19 | Be careful with the last trick! 20 | 21 | I strongly recommend to use the last trick only if `X` is defined locally to a caller so that you can control the correctness of expansion. For example, `X` can become painted blue, it can emit unexpected commas, the `#` and `##` operators can block expansion of parameters, and a plenty of other nasty things. 22 |
23 | 24 | [specification]: spec/spec.pdf 25 | -------------------------------------------------------------------------------- /scripts/bench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | bench() { 6 | echo $1 7 | time gcc bench/$1 -ftrack-macro-expansion=0 -Iinclude -E -P >/dev/null 8 | echo "" 9 | } 10 | 11 | bench "compare_25_items.c" 12 | bench "list_of_63_items.c" 13 | bench "100_v.c" 14 | bench "100_call.c" 15 | bench "many_call_in_arg_pos.c" 16 | bench "filter_map.c" 17 | -------------------------------------------------------------------------------- /scripts/check-arities.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Make sure that arity specifiers of public metafunctions are consistent with their signatures. 4 | 5 | import os 6 | import re 7 | import xml.etree.ElementTree as ET 8 | import subprocess 9 | 10 | subprocess.call("doxygen > /dev/null 2> /dev/null", shell=True) 11 | 12 | 13 | def check_module(module): 14 | print(f"Checking {module}.h ...") 15 | 16 | tree = ET.parse(f"xml/{module}_8h.xml") 17 | root = tree.getroot() 18 | 19 | arity_specifiers = gather_arity_specifiers(root) 20 | 21 | for metafunction_name, arity in gather_metafunctions(root).items(): 22 | expected_arity = int(arity) 23 | actual_arity = int(arity_specifiers[metafunction_name]) 24 | assert expected_arity == actual_arity 25 | 26 | 27 | def gather_metafunctions(root): 28 | metafunctions = {} 29 | 30 | for definition in root.findall("./compounddef/sectiondef/memberdef"): 31 | macro_name = definition.find("name").text 32 | is_metalang99_compliant = re.search("ML99_[a-z]", macro_name) 33 | 34 | exceptions = { 35 | "ML99_call", "ML99_callUneval", "ML99_fatal", "ML99_abort", "ML99_tupleGet", "ML99_variadicsGet", "ML99_seqGet"} 36 | is_exceptional = macro_name in exceptions 37 | 38 | if (is_metalang99_compliant and not is_exceptional): 39 | arity = len(list(definition.findall("param"))) 40 | metafunctions[macro_name] = arity 41 | 42 | return metafunctions 43 | 44 | 45 | def gather_arity_specifiers(root): 46 | arity_specifiers = {} 47 | 48 | for definition in root.findall("./compounddef/programlisting/codeline/highlight[@class='preprocessor']"): 49 | m = re.match(r"#define(\w+)_ARITY(\d)", "".join(definition.itertext())) 50 | if m is not None: 51 | metafunction_name = m.groups()[0] 52 | arity = m.groups()[1] 53 | arity_specifiers[metafunction_name] = arity 54 | 55 | return arity_specifiers 56 | 57 | 58 | for path in os.listdir("include/metalang99"): 59 | if path.endswith(".h"): 60 | module = path.replace(".h", "") 61 | check_module(module) 62 | -------------------------------------------------------------------------------- /scripts/check-fmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./run-clang-format/run-clang-format.py \ 4 | --exclude examples/build \ 5 | --exclude tests/build \ 6 | -r include tests examples bench 7 | -------------------------------------------------------------------------------- /scripts/docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sphinx-build -b html docs _build/html 4 | -------------------------------------------------------------------------------- /scripts/fmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find include tests examples bench \ 4 | \( -path examples/build -o -path tests/build \) -prune -false -o \ 5 | \( -iname "*.h" \) -or \( -iname "*.c" \) | xargs clang-format -i 6 | -------------------------------------------------------------------------------- /scripts/open-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | xdg-open _build/html/index.html 4 | -------------------------------------------------------------------------------- /scripts/open-spec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | xdg-open spec/spec.pdf 4 | -------------------------------------------------------------------------------- /scripts/spec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd spec 6 | 7 | pdflatex -shell-escape spec.tex 8 | biber spec 9 | pdflatex -shell-escape spec.tex 10 | pdflatex -shell-escape spec.tex 11 | 12 | cd .. 13 | -------------------------------------------------------------------------------- /scripts/test-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | ./scripts/test.sh 6 | ./scripts/test-examples.sh 7 | -------------------------------------------------------------------------------- /scripts/test-examples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | mkdir -p examples/build 6 | cd examples/build 7 | cmake .. 8 | cmake --build . 9 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | mkdir -p tests/build 6 | cd tests/build 7 | cmake .. 8 | cmake --build . 9 | 10 | if [[ "$OSTYPE" == "linux-gnu" ]]; then 11 | echo "Testing ./gen ..." 12 | ./gen 13 | 14 | echo "Testing ./stmt ..." 15 | ./stmt 16 | fi 17 | -------------------------------------------------------------------------------- /spec/.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.lof 4 | *.log 5 | *.lot 6 | *.fls 7 | *.out 8 | *.toc 9 | *.fmt 10 | *.fot 11 | *.cb 12 | *.cb2 13 | .*.lb 14 | 15 | ## Intermediate documents: 16 | *.dvi 17 | *.xdv 18 | *-converted-to.* 19 | # these rules might exclude image files for figures etc. 20 | # *.ps 21 | # *.eps 22 | # *.pdf 23 | 24 | ## Generated if empty string is given at "Please type another file name for output:" 25 | .pdf 26 | 27 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 28 | *.bbl 29 | *.bcf 30 | *.blg 31 | *-blx.aux 32 | *-blx.bib 33 | *.run.xml 34 | 35 | ## Build tool auxiliary files: 36 | *.fdb_latexmk 37 | *.synctex 38 | *.synctex(busy) 39 | *.synctex.gz 40 | *.synctex.gz(busy) 41 | *.pdfsync 42 | 43 | ## Build tool directories for auxiliary files 44 | # latexrun 45 | latex.out/ 46 | 47 | ## Auxiliary and intermediate files from other packages: 48 | # algorithms 49 | *.alg 50 | *.loa 51 | 52 | # achemso 53 | acs-*.bib 54 | 55 | # amsthm 56 | *.thm 57 | 58 | # beamer 59 | *.nav 60 | *.pre 61 | *.snm 62 | *.vrb 63 | 64 | # changes 65 | *.soc 66 | 67 | # comment 68 | *.cut 69 | 70 | # cprotect 71 | *.cpt 72 | 73 | # elsarticle (documentclass of Elsevier journals) 74 | *.spl 75 | 76 | # endnotes 77 | *.ent 78 | 79 | # fixme 80 | *.lox 81 | 82 | # feynmf/feynmp 83 | *.mf 84 | *.mp 85 | *.t[1-9] 86 | *.t[1-9][0-9] 87 | *.tfm 88 | 89 | #(r)(e)ledmac/(r)(e)ledpar 90 | *.end 91 | *.?end 92 | *.[1-9] 93 | *.[1-9][0-9] 94 | *.[1-9][0-9][0-9] 95 | *.[1-9]R 96 | *.[1-9][0-9]R 97 | *.[1-9][0-9][0-9]R 98 | *.eledsec[1-9] 99 | *.eledsec[1-9]R 100 | *.eledsec[1-9][0-9] 101 | *.eledsec[1-9][0-9]R 102 | *.eledsec[1-9][0-9][0-9] 103 | *.eledsec[1-9][0-9][0-9]R 104 | 105 | # glossaries 106 | *.acn 107 | *.acr 108 | *.glg 109 | *.glo 110 | *.gls 111 | *.glsdefs 112 | *.lzo 113 | *.lzs 114 | 115 | # uncomment this for glossaries-extra (will ignore makeindex's style files!) 116 | # *.ist 117 | 118 | # gnuplottex 119 | *-gnuplottex-* 120 | 121 | # gregoriotex 122 | *.gaux 123 | *.gtex 124 | 125 | # htlatex 126 | *.4ct 127 | *.4tc 128 | *.idv 129 | *.lg 130 | *.trc 131 | *.xref 132 | 133 | # hyperref 134 | *.brf 135 | 136 | # knitr 137 | *-concordance.tex 138 | # TODO Comment the next line if you want to keep your tikz graphics files 139 | *.tikz 140 | *-tikzDictionary 141 | 142 | # listings 143 | *.lol 144 | 145 | # luatexja-ruby 146 | *.ltjruby 147 | 148 | # makeidx 149 | *.idx 150 | *.ilg 151 | *.ind 152 | 153 | # minitoc 154 | *.maf 155 | *.mlf 156 | *.mlt 157 | *.mtc[0-9]* 158 | *.slf[0-9]* 159 | *.slt[0-9]* 160 | *.stc[0-9]* 161 | 162 | # minted 163 | _minted* 164 | *.pyg 165 | 166 | # morewrites 167 | *.mw 168 | 169 | # nomencl 170 | *.nlg 171 | *.nlo 172 | *.nls 173 | 174 | # pax 175 | *.pax 176 | 177 | # pdfpcnotes 178 | *.pdfpc 179 | 180 | # sagetex 181 | *.sagetex.sage 182 | *.sagetex.py 183 | *.sagetex.scmd 184 | 185 | # scrwfile 186 | *.wrt 187 | 188 | # sympy 189 | *.sout 190 | *.sympy 191 | sympy-plots-for-*.tex/ 192 | 193 | # pdfcomment 194 | *.upa 195 | *.upb 196 | 197 | # pythontex 198 | *.pytxcode 199 | pythontex-files-*/ 200 | 201 | # tcolorbox 202 | *.listing 203 | 204 | # thmtools 205 | *.loe 206 | 207 | # TikZ & PGF 208 | *.dpth 209 | *.md5 210 | *.auxlock 211 | 212 | # todonotes 213 | *.tdo 214 | 215 | # vhistory 216 | *.hst 217 | *.ver 218 | 219 | # easy-todo 220 | *.lod 221 | 222 | # xcolor 223 | *.xcp 224 | 225 | # xmpincl 226 | *.xmpi 227 | 228 | # xindy 229 | *.xdy 230 | 231 | # xypic precompiled matrices and outlines 232 | *.xyc 233 | *.xyd 234 | 235 | # endfloat 236 | *.ttt 237 | *.fff 238 | 239 | # Latexian 240 | TSWLatexianTemp* 241 | 242 | ## Editors: 243 | # WinEdt 244 | *.bak 245 | *.sav 246 | 247 | # Texpad 248 | .texpadtmp 249 | 250 | # LyX 251 | *.lyx~ 252 | 253 | # Kile 254 | *.backup 255 | 256 | # gummi 257 | .*.swp 258 | 259 | # KBibTeX 260 | *~[0-9]* 261 | 262 | # TeXnicCenter 263 | *.tps 264 | 265 | # auto folder when using emacs and auctex 266 | ./auto/* 267 | *.el 268 | 269 | # expex forward references with \gathertags 270 | *-tags.tex 271 | 272 | # standalone packages 273 | *.sta 274 | 275 | # Makeindex log files 276 | *.lpz 277 | -------------------------------------------------------------------------------- /spec/references.bib: -------------------------------------------------------------------------------- 1 | @online{Metalang99, 2 | author = "hirrolot", 3 | title = "Full-blown preprocessor metaprogramming", 4 | url = "https://github.com/hirrolot/metalang99", 5 | } 6 | 7 | @online{ApplicativeEvaluationStrategy, 8 | author = "Wikipedia", 9 | title = "Applicative order", 10 | url = "https://en.wikipedia.org/wiki/Evaluation_strategy#Applicative_order", 11 | } 12 | 13 | @online{Bluepainting, 14 | author = "", 15 | title = "C99 draft, section 6.10.3.4, paragraph 2 -- Rescanning and further replacement", 16 | url = "http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf", 17 | } 18 | -------------------------------------------------------------------------------- /spec/spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hirrolot/metalang99/5337c43d869a1985eb3aef4e316b728b7a9ac916/spec/spec.pdf -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(test LANGUAGES C) 3 | 4 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 5 | add_compile_options(-Wall -Wextra -pedantic -std=c99 6 | -ftrack-macro-expansion=0) 7 | elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang") 8 | add_compile_options("-fmacro-backtrace-limit=1") 9 | elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 10 | # Enable a standard-conforming C99/C11 preprocessor. 11 | add_compile_options("/std:c11") 12 | elseif(CMAKE_C_COMPILER_ID STREQUAL "TinyCC") 13 | add_compile_definitions(ML99_ALLOW_POOR_DIAGNOSTICS) 14 | endif() 15 | 16 | include_directories(../include) 17 | 18 | add_executable(metalang99 metalang99.c) 19 | add_executable(assert assert.c) 20 | add_executable(choice choice.c) 21 | add_executable(either either.c) 22 | add_executable(gen gen.c) 23 | add_executable(stmt stmt.c) 24 | add_executable(lang lang.c) 25 | add_executable(list list.c) 26 | add_executable(bool bool.c) 27 | add_executable(maybe maybe.c) 28 | add_executable(nat nat.c) 29 | add_executable(ident ident.c) 30 | add_executable(tuple tuple.c) 31 | add_executable(util util.c) 32 | add_executable(variadics variadics.c) 33 | add_executable(seq seq.c) 34 | add_executable(rec eval/rec.c) 35 | 36 | foreach(TARGET ${BUILDSYSTEM_TARGETS}) 37 | set_target_properties(TARGET PROPERTIES C_STANDARD 99 C_STANDARD_REQUIRED ON) 38 | endforeach() 39 | -------------------------------------------------------------------------------- /tests/assert.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This is used to check that `1 == 1` is put into parentheses automatically. 4 | #define COND 1 == 1 5 | 6 | ML99_EVAL(ML99_assert(v(COND))); 7 | ML99_EVAL(ML99_assertEq(v(COND), v(COND))); 8 | 9 | ML99_ASSERT(v(COND)); 10 | ML99_ASSERT_EQ(v(COND), v(COND)); 11 | 12 | ML99_ASSERT_UNEVAL(COND); 13 | 14 | #undef COND 15 | 16 | ML99_ASSERT_EMPTY(v()); 17 | ML99_ASSERT_EMPTY_UNEVAL(); 18 | 19 | int main(void) {} 20 | -------------------------------------------------------------------------------- /tests/bool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | // ML99_true, ML99_false 7 | { 8 | ML99_ASSERT_EQ(ML99_true(), v(1)); 9 | ML99_ASSERT_EQ(ML99_true(~, ~, ~), v(1)); 10 | 11 | ML99_ASSERT_EQ(ML99_false(), v(0)); 12 | ML99_ASSERT_EQ(ML99_false(~, ~, ~), v(0)); 13 | } 14 | 15 | // ML99_not 16 | { 17 | ML99_ASSERT_EQ(ML99_not(v(0)), v(1)); 18 | ML99_ASSERT_EQ(ML99_not(v(1)), v(0)); 19 | } 20 | 21 | // ML99_and 22 | { 23 | ML99_ASSERT_EQ(ML99_and(v(0), v(0)), v(0)); 24 | ML99_ASSERT_EQ(ML99_and(v(0), v(1)), v(0)); 25 | ML99_ASSERT_EQ(ML99_and(v(1), v(0)), v(0)); 26 | ML99_ASSERT_EQ(ML99_and(v(1), v(1)), v(1)); 27 | } 28 | 29 | // ML99_or 30 | { 31 | ML99_ASSERT_EQ(ML99_or(v(0), v(0)), v(0)); 32 | ML99_ASSERT_EQ(ML99_or(v(0), v(1)), v(1)); 33 | ML99_ASSERT_EQ(ML99_or(v(1), v(0)), v(1)); 34 | ML99_ASSERT_EQ(ML99_or(v(1), v(1)), v(1)); 35 | } 36 | 37 | // ML99_xor 38 | { 39 | ML99_ASSERT_EQ(ML99_xor(v(0), v(0)), v(0)); 40 | ML99_ASSERT_EQ(ML99_xor(v(0), v(1)), v(1)); 41 | ML99_ASSERT_EQ(ML99_xor(v(1), v(0)), v(1)); 42 | ML99_ASSERT_EQ(ML99_xor(v(1), v(1)), v(0)); 43 | } 44 | 45 | // ML99_boolEq 46 | { 47 | ML99_ASSERT_EQ(ML99_boolEq(v(0), v(0)), v(1)); 48 | ML99_ASSERT_EQ(ML99_boolEq(v(0), v(1)), v(0)); 49 | ML99_ASSERT_EQ(ML99_boolEq(v(1), v(0)), v(0)); 50 | ML99_ASSERT_EQ(ML99_boolEq(v(1), v(1)), v(1)); 51 | } 52 | 53 | #define MATCH_1_IMPL(...) v(12) // `...` due to the TCC's bug. 54 | #define MATCH_0_IMPL(...) v(9) 55 | 56 | // ML99_boolMatch 57 | { 58 | ML99_ASSERT_EQ(ML99_boolMatch(v(1), v(MATCH_)), v(12)); 59 | ML99_ASSERT_EQ(ML99_boolMatch(v(0), v(MATCH_)), v(9)); 60 | } 61 | 62 | #undef MATCH_1_IMPL 63 | #undef MATCH_0_IMPL 64 | 65 | #define MATCH_1_IMPL(x, y, z) v(ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3)) 66 | #define MATCH_0_IMPL(x, y, z) v(ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3)) 67 | 68 | // ML99_boolMatchWithArgs 69 | { 70 | ML99_EVAL(ML99_boolMatchWithArgs(v(1), v(MATCH_), v(1, 2, 3))); 71 | ML99_EVAL(ML99_boolMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3))); 72 | } 73 | 74 | #undef MATCH_1_IMPL 75 | #undef MATCH_0_IMPL 76 | 77 | // ML99_if 78 | { 79 | ML99_ASSERT_EQ(ML99_if(ML99_true(), v(24), v(848)), v(24)); 80 | ML99_ASSERT_EQ(ML99_if(ML99_true(), v(1549), v(1678)), v(1549)); 81 | 82 | ML99_ASSERT_EQ(ML99_if(ML99_false(), v(516), v(115)), v(115)); 83 | ML99_ASSERT_EQ(ML99_if(ML99_false(), v(10), v(6)), v(6)); 84 | } 85 | 86 | #define CHECK(...) CHECK_AUX(__VA_ARGS__) 87 | #define CHECK_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3) 88 | 89 | #define X 1, 2, 3 90 | 91 | // ML99_IF 92 | { 93 | ML99_ASSERT_UNEVAL(ML99_IF(ML99_TRUE(), 24, 848) == 24); 94 | ML99_ASSERT_UNEVAL(ML99_IF(ML99_FALSE(), 516, 115) == 115); 95 | 96 | // Ensure that a branch can expand to multiple commas (`X`). 97 | CHECK(ML99_IF(ML99_TRUE(), X, ~)); 98 | CHECK(ML99_IF(ML99_FALSE(), ~, X)); 99 | } 100 | 101 | #undef CHECK 102 | #undef CHECK_AUX 103 | #undef X 104 | 105 | // Plain macros 106 | { 107 | ML99_ASSERT_UNEVAL(ML99_TRUE()); 108 | ML99_ASSERT_UNEVAL(ML99_TRUE(~, ~, ~)); 109 | 110 | ML99_ASSERT_UNEVAL(!ML99_FALSE()); 111 | ML99_ASSERT_UNEVAL(!ML99_FALSE(~, ~, ~)); 112 | 113 | ML99_ASSERT_UNEVAL(ML99_NOT(0) == 1); 114 | ML99_ASSERT_UNEVAL(ML99_NOT(1) == 0); 115 | 116 | ML99_ASSERT_UNEVAL(ML99_AND(0, 1) == 0); 117 | ML99_ASSERT_UNEVAL(ML99_OR(0, 1) == 1); 118 | ML99_ASSERT_UNEVAL(ML99_XOR(0, 1) == 1); 119 | ML99_ASSERT_UNEVAL(ML99_BOOL_EQ(0, 1) == 0); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /tests/choice.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | #define MATCH_IMPL(foo) ML99_match(v(foo), v(MATCH_)) 7 | #define MATCH_FooA_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 19)) 8 | #define MATCH_FooB_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 1756)) 9 | #define MATCH_FooC_IMPL(_) v(ML99_ASSERT_UNEVAL(1)) 10 | 11 | // ML99_match 12 | { 13 | ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooA), v(19)))); 14 | ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooB), v(1756)))); 15 | ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooC), v(~)))); 16 | } 17 | 18 | #undef MATCH_IMPL 19 | #undef MATCH_FooA_IMPL 20 | #undef MATCH_FooB_IMPL 21 | #undef MATCH_FooC_IMPL 22 | 23 | #define MATCH_IMPL(foo) ML99_matchWithArgs(v(foo), v(MATCH_), v(3, 8)) 24 | #define MATCH_FooA_IMPL(x, _3, _8) v(ML99_ASSERT_UNEVAL(x == 19 && _3 == 3 && _8 == 8)) 25 | #define MATCH_FooB_IMPL(x, _3, _8) v(ML99_ASSERT_UNEVAL(x == 1756 && _3 == 3 && _8 == 8)) 26 | #define MATCH_FooC_IMPL(_, _3, _8) v(ML99_ASSERT_UNEVAL(_3 == 3 && _8 == 8)) 27 | 28 | // ML99_matchWithArgs 29 | { 30 | ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooA), v(19)))); 31 | ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooB), v(1756)))); 32 | ML99_EVAL(ML99_call(MATCH, ML99_choice(v(FooC), v(~)))); 33 | } 34 | 35 | #undef MATCH_IMPL 36 | #undef MATCH_FooA_IMPL 37 | #undef MATCH_FooB_IMPL 38 | #undef MATCH_FooC_IMPL 39 | 40 | #define CHECK(x, y, z) ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3) 41 | #define CHECK_EXPAND(args) CHECK(args) 42 | 43 | // ML99_choiceTag, ML99_choiceData 44 | { 45 | ML99_ASSERT_EQ(ML99_choiceTag(ML99_choice(v(5), v(1, 2, 3))), v(5)); 46 | CHECK_EXPAND(ML99_EVAL(ML99_choiceData(ML99_choice(v(5), v(1, 2, 3))))); 47 | } 48 | 49 | // ML99_CHOICE, ML99_CHOICE_TAG, ML99_CHOICE_DATA 50 | { 51 | ML99_ASSERT_UNEVAL(ML99_CHOICE_TAG(ML99_CHOICE(5, 1, 2, 3)) == 5); 52 | CHECK_EXPAND(ML99_CHOICE_DATA(ML99_CHOICE(5, 1, 2, 3))); 53 | } 54 | 55 | #undef CHECK 56 | #undef CHECK_EXPAND 57 | 58 | #define CHECK(tag, x, y, z) tag == 5 && x == 1 && y == 2 && z == 3 59 | 60 | // Representation 61 | { ML99_ASSERT_UNEVAL(CHECK ML99_CHOICE(5, 1, 2, 3)); } 62 | 63 | #undef CHECK 64 | } 65 | -------------------------------------------------------------------------------- /tests/either.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) { 6 | 7 | #define MATCH_IMPL(either) ML99_match(v(either), v(MATCH_)) 8 | #define MATCH_left_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 18)) 9 | #define MATCH_right_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 4)) 10 | 11 | // Pattern matching 12 | { 13 | ML99_EVAL(ML99_call(MATCH, ML99_left(v(18)))); 14 | ML99_EVAL(ML99_call(MATCH, ML99_right(v(4)))); 15 | } 16 | 17 | #undef MATCH_IMPL 18 | #undef MATCH_left_IMPL 19 | #undef MATCH_right_IMPL 20 | 21 | #define VAL v(abc ? +-148 % "hello world") 22 | 23 | // ML99_isLeft 24 | { 25 | ML99_ASSERT(ML99_isLeft(ML99_left(VAL))); 26 | ML99_ASSERT(ML99_not(ML99_isLeft(ML99_right(VAL)))); 27 | } 28 | 29 | // ML99_IS_LEFT 30 | { 31 | ML99_ASSERT_UNEVAL(ML99_IS_LEFT(ML99_LEFT(VAL))); 32 | ML99_ASSERT_UNEVAL(!ML99_IS_LEFT(ML99_RIGHT(VAL))); 33 | } 34 | 35 | // ML99_isRight 36 | { 37 | ML99_ASSERT(ML99_isRight(ML99_right(VAL))); 38 | ML99_ASSERT(ML99_not(ML99_isRight(ML99_left(VAL)))); 39 | } 40 | 41 | // ML99_IS_RIGHT 42 | { 43 | ML99_ASSERT_UNEVAL(ML99_IS_RIGHT(ML99_RIGHT(VAL))); 44 | ML99_ASSERT_UNEVAL(!ML99_IS_RIGHT(ML99_LEFT(VAL))); 45 | } 46 | 47 | // ML99_eitherEq 48 | { 49 | ML99_ASSERT(ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_left(v(123)))); 50 | ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_left(v(18)), ML99_left(v(123))))); 51 | 52 | ML99_ASSERT(ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_right(v(123)))); 53 | ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_right(v(18)), ML99_right(v(123))))); 54 | 55 | ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_right(v(123))))); 56 | ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_left(v(123)), ML99_right(v(4))))); 57 | ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(123))))); 58 | ML99_ASSERT(ML99_not(ML99_eitherEq(v(ML99_natEq), ML99_right(v(123)), ML99_left(v(4))))); 59 | } 60 | 61 | // ML99_unwrapLeft 62 | { ML99_ASSERT_EQ(ML99_unwrapLeft(ML99_left(v(123))), v(123)); } 63 | 64 | // ML99_unwrapRight 65 | { ML99_ASSERT_EQ(ML99_unwrapRight(ML99_right(v(123))), v(123)); } 66 | } 67 | -------------------------------------------------------------------------------- /tests/eval/rec.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define F(acc, i) ML99_PRIV_IF(ML99_PRIV_NAT_EQ(i, 10), F_DONE, F_PROGRESS)(acc, i) 11 | #define F_DONE(acc, _i) ML99_PRIV_REC_CONTINUE(ML99_PRIV_REC_STOP)(~, acc) 12 | #define F_PROGRESS(acc, i) ML99_PRIV_REC_CONTINUE(F)(acc##X, ML99_PRIV_INC(i)) 13 | #define F_HOOK() F 14 | 15 | #define XXXXXXXXXX 678 16 | 17 | ML99_ASSERT_UNEVAL(ML99_PRIV_REC_UNROLL(F(, 0)) == 678); 18 | 19 | #undef F 20 | #undef F_DONE 21 | #undef F_PROGRESS 22 | #undef F_HOOK 23 | #undef XXXXXXXXXX 24 | 25 | int main(void) {} 26 | -------------------------------------------------------------------------------- /tests/gen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | // clang-format off 10 | static void 11 | test_indexed_params ML99_EVAL(ML99_indexedParams(ML99_list(v(int, long long, const char *)))) 12 | // clang-format on 13 | { 14 | int i = _0; 15 | long long ll = _1; 16 | const char *str = _2; 17 | 18 | (void)i; 19 | (void)ll; 20 | (void)str; 21 | } 22 | 23 | static int test_fn_ptr(const char *str, long long x) { 24 | (void)str; 25 | (void)x; 26 | return 123; 27 | } 28 | 29 | int main(void) { 30 | 31 | // ML99_braced 32 | { struct TestBraced ML99_EVAL(ML99_braced(v(int a, b, c;))); } 33 | 34 | // ML99_semicoloned 35 | { 36 | ML99_EVAL(ML99_semicoloned(v(struct TestSemicoloned { int a, b, c; }))); 37 | } 38 | 39 | // ML99_assign(Stmt) 40 | { 41 | int x = 0; 42 | 43 | ML99_EVAL(ML99_assign(v(x), v(5))); 44 | assert(5 == x); 45 | 46 | ML99_EVAL(ML99_assignStmt(v(x), v(7))) 47 | assert(7 == x); 48 | } 49 | 50 | // ML99_assignInitializerList(Stmt) 51 | { 52 | typedef struct { 53 | int x, y; 54 | } Point; 55 | 56 | ML99_EVAL(ML99_assignInitializerList(v(Point p1), v(.x = 2, .y = 3))); 57 | assert(2 == p1.x); 58 | assert(3 == p1.y); 59 | 60 | ML99_EVAL(ML99_assignInitializerListStmt(v(Point p2), v(.x = 5, .y = 7))) 61 | assert(5 == p2.x); 62 | assert(7 == p2.y); 63 | } 64 | 65 | #define F(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3) 66 | 67 | // ML99_invoke(Stmt) 68 | { 69 | ML99_EVAL(ML99_invoke(v(F), v(1, 2, 3))); 70 | ML99_EVAL(ML99_invokeStmt(v(F), v(1, 2, 3))) 71 | } 72 | 73 | #undef F 74 | 75 | // ML99_prefixedBlock 76 | { 77 | 78 | ML99_EVAL(ML99_prefixedBlock(v(if (1)), v(goto end_prefixed_block;))) 79 | 80 | // Unreachable code. 81 | assert(0); 82 | 83 | end_prefixed_block:; 84 | } 85 | 86 | // ML99_typedef 87 | { 88 | 89 | ML99_EVAL(ML99_typedef(v(Point), v(struct { int x, y; }))); 90 | 91 | Point point = {5, 7}; 92 | point.x = 1; 93 | point.y = 2; 94 | 95 | (void)point; 96 | } 97 | 98 | // ML99_struct 99 | { 100 | 101 | ML99_EVAL(ML99_struct(v(Point), v(int x, y;))); 102 | 103 | struct Point point = {5, 7}; 104 | point.x = 1; 105 | point.y = 2; 106 | 107 | (void)point; 108 | } 109 | 110 | // ML99_anonStruct 111 | { 112 | typedef ML99_EVAL(ML99_anonStruct(v(int x, y;))) 113 | Point; 114 | 115 | Point point = {5, 7}; 116 | point.x = 1; 117 | point.y = 2; 118 | 119 | (void)point; 120 | } 121 | 122 | // ML99_union 123 | { 124 | ML99_EVAL(ML99_union(v(Point), v(int x, y;))); 125 | 126 | union Point point; 127 | point.x = 1; 128 | point.y = 2; 129 | 130 | (void)point; 131 | } 132 | 133 | // ML99_anonUnion 134 | { 135 | typedef ML99_EVAL(ML99_anonUnion(v(int x, y;))) 136 | Point; 137 | 138 | Point point; 139 | point.x = 1; 140 | point.y = 2; 141 | 142 | (void)point; 143 | } 144 | 145 | // ML99_enum 146 | { 147 | ML99_EVAL(ML99_enum(v(MyEnum), v(Foo, Bar))); 148 | 149 | enum MyEnum foo = Foo, bar = Bar; 150 | (void)foo; 151 | (void)bar; 152 | } 153 | 154 | // ML99_anonEnum 155 | { 156 | typedef ML99_EVAL(ML99_anonEnum(v(Foo, Bar))) 157 | MyEnum; 158 | 159 | MyEnum foo = Foo, bar = Bar; 160 | (void)foo; 161 | (void)bar; 162 | } 163 | 164 | // ML99_fnPtr(Stmt) 165 | { 166 | { 167 | ML99_EVAL(ML99_fnPtr(v(int), v(ptr), v(const char *str), v(long long x))) 168 | = test_fn_ptr; 169 | assert(test_fn_ptr == ptr); 170 | } 171 | 172 | { 173 | ML99_EVAL(ML99_fnPtrStmt(v(int), v(ptr), v(const char *str), v(long long x))) 174 | ptr = test_fn_ptr; 175 | (void)ptr; 176 | } 177 | } 178 | 179 | #define CHECK_EXPAND(args) CHECK(args) 180 | 181 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 0 && y == 1 && z == 2) 182 | #define F_IMPL(x) v(, x) 183 | #define F_ARITY 1 184 | 185 | // ML99_repeat 186 | { CHECK_EXPAND(ML99_EVAL(ML99_repeat(v(3), v(F)))); } 187 | 188 | #undef CHECK 189 | #undef F_IMPL 190 | #undef F_ARITY 191 | 192 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 5 && y == 5 && z == 5) 193 | 194 | // ML99_times 195 | { CHECK_EXPAND(ML99_EVAL(ML99_times(v(3), v(, 5)))); } 196 | 197 | #undef CHECK 198 | 199 | #undef CHECK_EXPAND 200 | 201 | // ML99_indexedParams 202 | { 203 | ML99_ASSERT_UNEVAL(ML99_IDENT_EQ( 204 | ML99_C_KEYWORD_DETECTOR, 205 | void, 206 | ML99_EVAL(ML99_untuple(ML99_indexedParams(ML99_nil()))))); 207 | 208 | (void)test_indexed_params; 209 | } 210 | 211 | // ML99_indexedFields 212 | { 213 | ML99_ASSERT_EMPTY(ML99_indexedFields(ML99_nil())); 214 | 215 | struct { 216 | ML99_EVAL(ML99_indexedFields(ML99_list(v(int, long long, const char *)))) 217 | } data = {0}; 218 | 219 | int i = data._0; 220 | long long ll = data._1; 221 | const char *str = data._2; 222 | 223 | (void)i; 224 | (void)ll; 225 | (void)str; 226 | } 227 | 228 | // clang-format off 229 | 230 | // ML99_indexedInitializerList 231 | { 232 | // When N=0. 233 | { 234 | const struct { 235 | int _0; 236 | long long _1; 237 | const char *_2; 238 | } test = ML99_EVAL(ML99_indexedInitializerList(v(0))); 239 | 240 | assert(0 == test._0); 241 | assert(0 == test._1); 242 | assert(0 == test._2); 243 | } 244 | 245 | // When N>0. 246 | { 247 | int _0 = 123; 248 | long long _1 = 149494456; 249 | const char *_2 = "abc"; 250 | 251 | struct { 252 | int i; 253 | long long ll; 254 | const char *str; 255 | } data = ML99_EVAL(ML99_indexedInitializerList(v(3))); 256 | 257 | (void)data; 258 | } 259 | } 260 | 261 | // ML99_indexedArgs 262 | { 263 | ML99_ASSERT_EMPTY(ML99_indexedArgs(v(0))); 264 | 265 | int _0 = 123; 266 | long long _1 = 149494456; 267 | const char *_2 = "abc"; 268 | 269 | const struct { 270 | int i; 271 | long long ll; 272 | const char *str; 273 | } test = { ML99_EVAL(ML99_indexedArgs(v(3))) }; 274 | 275 | assert(test.i == _0); 276 | assert(test.ll == _1); 277 | assert(test.str == _2); 278 | } 279 | 280 | // clang-format on 281 | 282 | return 0; 283 | } 284 | -------------------------------------------------------------------------------- /tests/lang.c: -------------------------------------------------------------------------------- 1 | // `...` is sometimes used to workaround a TCC bug, see 2 | // . 3 | 4 | #include 5 | #include 6 | 7 | int main(void) { 8 | 9 | ML99_ASSERT_EMPTY_UNEVAL(ML99_EVAL(v())); 10 | 11 | #ifndef __TINYC__ 12 | #define F_IMPL() v(123) 13 | #else 14 | #define F_IMPL(...) v(123) // `...` due to the TCC's bug. 15 | #endif 16 | 17 | // A function with zero arguments 18 | { 19 | ML99_ASSERT_EQ(ML99_call(F, v()), v(123)); 20 | ML99_ASSERT_EQ(ML99_call(v(F), v()), v(123)); 21 | ML99_ASSERT_EQ(ML99_callUneval(F, ), v(123)); 22 | } 23 | 24 | #undef F_IMPL 25 | 26 | #define F_IMPL(x, y, z) v(x##y##z) 27 | #define BAR_IMPL(x, y) v(x + y) 28 | 29 | // Regular usage of the metalanguage 30 | { 31 | ML99_ASSERT_EQ(ML99_call(BAR, v(5), v(7)), v(5 + 7)); 32 | ML99_ASSERT_EQ(ML99_call(ML99_call(F, v(B), v(A), v(R)), v(6), v(11)), v(6 + 11)); 33 | 34 | ML99_ASSERT_EQ(ML99_call(BAR, v(5, 7)), v(5 + 7)); 35 | ML99_ASSERT_EQ(ML99_call(ML99_call(F, v(B, A, R)), v(6, 11)), v(6 + 11)); 36 | 37 | ML99_ASSERT_EQ(ML99_callUneval(BAR, 5, 7), v(5 + 7)); 38 | } 39 | 40 | #undef F_IMPL 41 | #undef BAR_IMPL 42 | 43 | // Even if a term in the argument position evaluates to more than one terms, they should be appended 44 | // to each other but not interspersed with a comma. 45 | #define F_IMPL(...) ML99_TERMS(v(1), v(2), v(3)) // `...` due to the TCC's bug. 46 | #define BAR_IMPL(x) v() 47 | 48 | ML99_EVAL(ML99_call(BAR, ML99_call(F, v()))) 49 | 50 | #undef F_IMPL 51 | #undef BAR_IMPL 52 | 53 | // Recursion might arise from a higher-order macro, if `op` invokes `F`, but nonetheless the 54 | // second call to `F` must be performed as expected. 55 | #define F_IMPL(op) ML99_call(op, v(123)) 56 | #define OP_IMPL(x) ML99_call(F, v(ID)) 57 | #define ID_IMPL(x) v(x) 58 | 59 | ML99_ASSERT_EQ(ML99_call(F, v(OP)), v(123)); 60 | 61 | #undef F_IMPL 62 | #undef OP_IMPL 63 | #undef ID_IMPL 64 | 65 | // ML99_abort 66 | { 67 | ML99_ASSERT_EMPTY(ML99_abort(v())); 68 | ML99_ASSERT_EQ(ML99_abort(v(815057)), v(815057)); 69 | ML99_ASSERT_UNEVAL(ML99_EVAL(v(~), ML99_abort(v(123)), v(~)) == 123); 70 | 71 | // Ensure that `ML99_abort` also works correctly after some evaluations. 72 | #define F_IMPL(...) ML99_call(G, v(1, 2), ML99_call(H, v(123))) // `...` due to the TCC's bug. 73 | #define G_IMPL(_1, _2, _123_plus_1) \ 74 | ML99_abort(v(ML99_ASSERT_UNEVAL(_1 == 1 && _2 == 2 && _123_plus_1 == 123 + 1))) 75 | #define H_IMPL(a) v(a + 1) 76 | 77 | ML99_EVAL(ML99_call(F, v())); 78 | 79 | #undef F_IMPL 80 | #undef G_IMPL 81 | #undef H_IMPL 82 | 83 | // Ensure that `ML99_abort` immediately aborts interpretation even in an argument position. 84 | ML99_ASSERT_EQ(ML99_call(NonExistingF, ML99_abort(v(123))), v(123)); 85 | } 86 | 87 | // Partial application 88 | { 89 | 90 | #ifndef __TINYC__ 91 | #define F_IMPL() v(123) 92 | #else 93 | #define F_IMPL(...) v(123) // // `...` due to the TCC's bug. 94 | #endif 95 | 96 | #define F_ARITY 1 97 | 98 | // The arity of a function with zero arguments must be 1 99 | { ML99_ASSERT_EQ(ML99_appl(v(F), v()), v(123)); } 100 | 101 | #undef F_IMPL 102 | #undef F_ARITY 103 | 104 | #define F_IMPL(a, b, c, d) v(a##b##c##d) 105 | #define F_ARITY 4 106 | 107 | // Regular usage of partial application 108 | { 109 | ML99_ASSERT_EQ( 110 | ML99_appl(ML99_appl(ML99_appl(ML99_appl(v(F), v(10)), v(5)), v(7)), v(8)), 111 | v(10578)); 112 | ML99_ASSERT_EQ( 113 | ML99_appl(ML99_appl(ML99_appl2(v(F), v(10), v(5)), v(7)), v(8)), 114 | v(10578)); 115 | ML99_ASSERT_EQ(ML99_appl(ML99_appl3(v(F), v(10), v(5), v(7)), v(8)), v(10578)); 116 | ML99_ASSERT_EQ(ML99_appl4(v(F), v(10), v(5), v(7), v(8)), v(10578)); 117 | } 118 | 119 | #undef F_IMPL 120 | #undef F_ARITY 121 | 122 | #define F_ARITY 255 123 | 124 | // The maximum arity 125 | { 126 | ML99_EVAL(ML99_empty(ML99_appl(v(F), v(~)))) 127 | ML99_EVAL(ML99_empty(ML99_appl2(v(F), v(~), v(~)))) 128 | ML99_EVAL(ML99_empty(ML99_appl3(v(F), v(~), v(~), v(~)))) 129 | } 130 | 131 | #undef F_ARITY 132 | } 133 | 134 | #define F_IMPL(x) v((x + 1)) 135 | #define G_IMPL(x) v((x * 8)) 136 | 137 | #define F_ARITY 1 138 | #define G_ARITY 1 139 | 140 | // ML99_compose 141 | { ML99_ASSERT_EQ(ML99_appl(ML99_compose(v(F), v(G)), v(3)), v((3 * 8) + 1)); } 142 | 143 | #undef F_IMPL 144 | #undef G_IMPL 145 | 146 | #undef F_ARITY 147 | #undef G_ARITY 148 | 149 | #define F_IMPL(x) v(x) 150 | 151 | #define PROG ML99_TERMS(v(1), v(, ), v(2), v(, ), ML99_call(F, v(7))) 152 | 153 | #define CHECK(...) CHECK_AUX(__VA_ARGS__) 154 | #define CHECK_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 7) 155 | 156 | // ML99_QUOTE 157 | { CHECK(ML99_EVAL(ML99_EVAL(ML99_QUOTE(PROG)))); } 158 | 159 | #undef F_IMPL 160 | 161 | #undef PROG 162 | 163 | #undef CHECK 164 | #undef CHECK_AUX 165 | } 166 | -------------------------------------------------------------------------------- /tests/maybe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(void) { 6 | 7 | #define MATCH_IMPL(maybe) ML99_match(v(maybe), v(MATCH_)) 8 | #define MATCH_just_IMPL(x) v(ML99_ASSERT_UNEVAL(x == 87)) 9 | #define MATCH_nothing_IMPL(_) v(ML99_ASSERT_UNEVAL(1)) 10 | 11 | // Pattern matching 12 | { 13 | ML99_EVAL(ML99_call(MATCH, ML99_just(v(87)))); 14 | ML99_EVAL(ML99_call(MATCH, ML99_nothing(~, ~, ~))); 15 | } 16 | 17 | #undef MATCH_IMPL 18 | #undef MATCH_just_IMPL 19 | #undef MATCH_nothing_IMPL 20 | 21 | #define VAL v(abc ? +-148 % "hello world") 22 | 23 | // ML99_isJust 24 | { 25 | ML99_ASSERT(ML99_isJust(ML99_just(VAL))); 26 | ML99_ASSERT(ML99_not(ML99_isJust(ML99_nothing()))); 27 | } 28 | 29 | // ML99_IS_JUST 30 | { 31 | ML99_ASSERT_UNEVAL(ML99_IS_JUST(ML99_JUST(VAL))); 32 | ML99_ASSERT_UNEVAL(!ML99_IS_JUST(ML99_NOTHING())); 33 | } 34 | 35 | // ML99_isNothing 36 | { 37 | ML99_ASSERT(ML99_isNothing(ML99_nothing())); 38 | ML99_ASSERT(ML99_not(ML99_isNothing(ML99_just(VAL)))); 39 | } 40 | 41 | // ML99_IS_NOTHING 42 | { 43 | ML99_ASSERT_UNEVAL(ML99_IS_NOTHING(ML99_NOTHING())); 44 | ML99_ASSERT_UNEVAL(!ML99_IS_NOTHING(ML99_JUST(VAL))); 45 | } 46 | 47 | // ML99_maybeEq 48 | { 49 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_just(v(123)))); 50 | 51 | ML99_ASSERT(ML99_not(ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_just(v(4))))); 52 | ML99_ASSERT(ML99_not(ML99_maybeEq(v(ML99_natEq), ML99_just(v(123)), ML99_nothing()))); 53 | ML99_ASSERT(ML99_not(ML99_maybeEq(v(ML99_natEq), ML99_nothing(), ML99_just(v(123))))); 54 | } 55 | 56 | // ML99_maybeUnwrap 57 | { ML99_ASSERT_EQ(ML99_maybeUnwrap(ML99_just(v(123))), v(123)); } 58 | } 59 | -------------------------------------------------------------------------------- /tests/metalang99.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | #undef ML99_MAJOR 7 | #undef ML99_MINOR 8 | #undef ML99_PATCH 9 | 10 | #define ML99_MAJOR 1 11 | #define ML99_MINOR 2 12 | #define ML99_PATCH 3 13 | 14 | // ML99_VERSION_COMPATIBLE 15 | { 16 | 17 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 0, 0)); 18 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 1, 0)); 19 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 1, 1)); 20 | 21 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 0)); 22 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 1)); 23 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 2)); 24 | ML99_ASSERT_UNEVAL(ML99_VERSION_COMPATIBLE(1, 2, 3)); 25 | 26 | // Major-incompatible. 27 | ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(2, 0, 0)); 28 | ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(7, 1, 2)); 29 | 30 | // Minor-incompatible. 31 | ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 3, 0)); 32 | ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 4, 9)); 33 | 34 | // Patch-incompatible. 35 | ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 2, 4)); 36 | ML99_ASSERT_UNEVAL(!ML99_VERSION_COMPATIBLE(1, 2, 5)); 37 | } 38 | 39 | // ML99_VERSION_EQ 40 | { 41 | ML99_ASSERT_UNEVAL(ML99_VERSION_EQ(1, 2, 3)); 42 | 43 | ML99_ASSERT_UNEVAL(!ML99_VERSION_EQ(1, 2, 7)); 44 | ML99_ASSERT_UNEVAL(!ML99_VERSION_EQ(1, 7, 3)); 45 | ML99_ASSERT_UNEVAL(!ML99_VERSION_EQ(7, 2, 3)); 46 | } 47 | 48 | #undef ML99_MAJOR 49 | #undef ML99_MINOR 50 | #undef ML99_PATCH 51 | } 52 | -------------------------------------------------------------------------------- /tests/nat.c: -------------------------------------------------------------------------------- 1 | // `...` is sometimes used to workaround a TCC bug, see 2 | // . 3 | 4 | #include 5 | #include 6 | 7 | int main(void) { 8 | 9 | #define MATCH_Z_IMPL(...) v(88) // `...` due to the TCC's bug. 10 | #define MATCH_S_IMPL(x) v(x) 11 | 12 | // ML99_natMatch 13 | { 14 | ML99_ASSERT_EQ(ML99_natMatch(v(0), v(MATCH_)), v(88)); 15 | ML99_ASSERT_EQ(ML99_natMatch(v(123), v(MATCH_)), v(122)); 16 | } 17 | 18 | #undef MATCH_Z_IMPL 19 | #undef MATCH_S_IMPL 20 | 21 | #define MATCH_Z_IMPL(x, y, z) v(ML99_ASSERT_UNEVAL(x == 1 && y == 2 && z == 3)) 22 | #define MATCH_S_IMPL(n, x, y, z) v(ML99_ASSERT_UNEVAL(n == 122 && x == 1 && y == 2 && z == 3)) 23 | 24 | // ML99_natMatchWithArgs 25 | { 26 | ML99_EVAL(ML99_natMatchWithArgs(v(0), v(MATCH_), v(1, 2, 3))); 27 | ML99_EVAL(ML99_natMatchWithArgs(v(123), v(MATCH_), v(1, 2, 3))); 28 | } 29 | 30 | #undef MATCH_Z_IMPL 31 | #undef MATCH_S_IMPL 32 | 33 | // ML99_inc 34 | { 35 | ML99_ASSERT_EQ(ML99_inc(v(0)), v(1)); 36 | ML99_ASSERT_EQ(ML99_inc(v(15)), v(16)); 37 | ML99_ASSERT_EQ(ML99_inc(v(198)), v(199)); 38 | ML99_ASSERT_EQ(ML99_inc(v(254)), v(ML99_NAT_MAX)); 39 | ML99_ASSERT_EQ(ML99_inc(v(ML99_NAT_MAX)), v(0)); 40 | } 41 | 42 | // ML99_INC 43 | { 44 | ML99_ASSERT_UNEVAL(ML99_INC(0) == 1); 45 | ML99_ASSERT_UNEVAL(ML99_INC(15) == 16); 46 | ML99_ASSERT_UNEVAL(ML99_INC(254) == ML99_NAT_MAX); 47 | } 48 | 49 | // ML99_dec 50 | { 51 | ML99_ASSERT_EQ(ML99_dec(v(0)), v(ML99_NAT_MAX)); 52 | ML99_ASSERT_EQ(ML99_dec(v(1)), v(0)); 53 | ML99_ASSERT_EQ(ML99_dec(v(71)), v(70)); 54 | ML99_ASSERT_EQ(ML99_dec(v(201)), v(200)); 55 | ML99_ASSERT_EQ(ML99_dec(v(ML99_NAT_MAX)), v(254)); 56 | } 57 | 58 | // ML99_DEC 59 | { 60 | ML99_ASSERT_UNEVAL(ML99_DEC(0) == ML99_NAT_MAX); 61 | ML99_ASSERT_UNEVAL(ML99_DEC(1) == 0); 62 | ML99_ASSERT_UNEVAL(ML99_DEC(ML99_NAT_MAX) == 254); 63 | } 64 | 65 | // ML99_natEq 66 | { 67 | ML99_ASSERT(ML99_natEq(v(0), v(0))); 68 | ML99_ASSERT(ML99_natEq(v(18), v(18))); 69 | ML99_ASSERT(ML99_natEq(v(183), v(183))); 70 | ML99_ASSERT(ML99_natEq(v(ML99_NAT_MAX), v(ML99_NAT_MAX))); 71 | 72 | ML99_ASSERT(ML99_not(ML99_natEq(v(0), v(1)))); 73 | ML99_ASSERT(ML99_not(ML99_natEq(v(198), v(91)))); 74 | } 75 | 76 | // ML99_NAT_EQ 77 | { 78 | ML99_ASSERT_UNEVAL(ML99_NAT_EQ(18, 18)); 79 | ML99_ASSERT_UNEVAL(!ML99_NAT_EQ(198, 91)); 80 | } 81 | 82 | // ML99_natNeq 83 | { 84 | ML99_ASSERT(ML99_natNeq(v(0), v(1))); 85 | ML99_ASSERT(ML99_natNeq(v(0), v(168))); 86 | ML99_ASSERT(ML99_natNeq(v(1), v(34))); 87 | ML99_ASSERT(ML99_natNeq(v(184), v(381))); 88 | ML99_ASSERT(ML99_natNeq(v(3), v(101))); 89 | 90 | ML99_ASSERT(ML99_not(ML99_natNeq(v(0), v(0)))); 91 | ML99_ASSERT(ML99_not(ML99_natNeq(v(101), v(101)))); 92 | } 93 | 94 | // ML99_NAT_NEQ 95 | { 96 | ML99_ASSERT_UNEVAL(ML99_NAT_NEQ(0, 168)); 97 | ML99_ASSERT_UNEVAL(!ML99_NAT_NEQ(101, 101)); 98 | } 99 | 100 | // ML99_greater 101 | { 102 | ML99_ASSERT(ML99_greater(v(1), v(0))); 103 | ML99_ASSERT(ML99_greater(v(ML99_NAT_MAX), v(0))); 104 | ML99_ASSERT(ML99_greater(v(5), v(4))); 105 | ML99_ASSERT(ML99_greater(v(147), v(80))); 106 | ML99_ASSERT(ML99_greater(v(217), v(209))); 107 | 108 | ML99_ASSERT(ML99_not(ML99_greater(v(0), v(13)))); 109 | ML99_ASSERT(ML99_not(ML99_greater(v(17), v(120)))); 110 | } 111 | 112 | // ML99_lesser 113 | { 114 | ML99_ASSERT(ML99_lesser(v(0), v(1))); 115 | ML99_ASSERT(ML99_lesser(v(0), v(ML99_NAT_MAX))); 116 | ML99_ASSERT(ML99_lesser(v(19), v(25))); 117 | ML99_ASSERT(ML99_lesser(v(109), v(110))); 118 | ML99_ASSERT(ML99_lesser(v(10), v(208))); 119 | 120 | ML99_ASSERT(ML99_not(ML99_lesser(v(12), v(0)))); 121 | ML99_ASSERT(ML99_not(ML99_lesser(v(123), v(123)))); 122 | } 123 | 124 | // ML99_greaterEq 125 | { 126 | ML99_ASSERT(ML99_greaterEq(v(0), v(0))); 127 | ML99_ASSERT(ML99_greaterEq(v(18), v(18))); 128 | ML99_ASSERT(ML99_greaterEq(v(175), v(175))); 129 | ML99_ASSERT(ML99_greaterEq(v(ML99_NAT_MAX), v(ML99_NAT_MAX))); 130 | 131 | ML99_ASSERT(ML99_greaterEq(v(1), v(0))); 132 | ML99_ASSERT(ML99_greaterEq(v(ML99_NAT_MAX), v(0))); 133 | ML99_ASSERT(ML99_greaterEq(v(19), v(10))); 134 | ML99_ASSERT(ML99_greaterEq(v(178), v(177))); 135 | 136 | ML99_ASSERT(ML99_not(ML99_greaterEq(v(0), v(7)))); 137 | ML99_ASSERT(ML99_not(ML99_greaterEq(v(1), v(19)))); 138 | } 139 | 140 | // ML99_lesserEq 141 | { 142 | ML99_ASSERT(ML99_lesserEq(v(0), v(0))); 143 | ML99_ASSERT(ML99_lesserEq(v(2), v(2))); 144 | ML99_ASSERT(ML99_lesserEq(v(1), v(1))); 145 | ML99_ASSERT(ML99_lesserEq(v(25), v(25))); 146 | ML99_ASSERT(ML99_lesserEq(v(198), v(198))); 147 | 148 | ML99_ASSERT(ML99_lesserEq(v(0), v(1))); 149 | ML99_ASSERT(ML99_lesserEq(v(0), v(ML99_NAT_MAX))); 150 | ML99_ASSERT(ML99_lesserEq(v(18), v(27))); 151 | ML99_ASSERT(ML99_lesserEq(v(82), v(90))); 152 | ML99_ASSERT(ML99_lesserEq(v(145), v(146))); 153 | ML99_ASSERT(ML99_lesserEq(v(181), v(ML99_NAT_MAX))); 154 | 155 | ML99_ASSERT(ML99_not(ML99_lesserEq(v(7), v(0)))); 156 | ML99_ASSERT(ML99_not(ML99_lesserEq(v(182), v(181)))); 157 | } 158 | 159 | // ML99_add 160 | { 161 | ML99_ASSERT_EQ(ML99_add(v(0), v(0)), v(0)); 162 | ML99_ASSERT_EQ(ML99_add(v(19), v(83)), v(19 + 83)); 163 | ML99_ASSERT_EQ(ML99_add(v(8), v(4)), v(8 + 4)); 164 | ML99_ASSERT_EQ(ML99_add(v(1), v(254)), v(1 + 254)); 165 | } 166 | 167 | // ML99_sub 168 | { 169 | ML99_ASSERT_EQ(ML99_sub(v(1), v(1)), v(1 - 1)); 170 | ML99_ASSERT_EQ(ML99_sub(v(5), v(3)), v(5 - 3)); 171 | ML99_ASSERT_EQ(ML99_sub(v(105), v(19)), v(105 - 19)); 172 | ML99_ASSERT_EQ(ML99_sub(v(ML99_NAT_MAX), v(40)), v(ML99_NAT_MAX - 40)); 173 | } 174 | 175 | // ML99_mul 176 | { 177 | ML99_ASSERT_EQ(ML99_mul(v(11), v(0)), v(0)); 178 | ML99_ASSERT_EQ(ML99_mul(v(0), v(11)), v(0)); 179 | ML99_ASSERT_EQ(ML99_mul(v(15), v(8)), v(15 * 8)); 180 | ML99_ASSERT_EQ(ML99_mul(v(ML99_NAT_MAX), v(1)), v(ML99_NAT_MAX * 1)); 181 | } 182 | 183 | // ML99_div 184 | { 185 | ML99_ASSERT_EQ(ML99_div(v(15), v(1)), v(15)); 186 | ML99_ASSERT_EQ(ML99_div(v(15), v(15)), v(1)); 187 | ML99_ASSERT_EQ(ML99_div(v(45), v(3)), v(45 / 3)); 188 | ML99_ASSERT_EQ(ML99_div(v(ML99_NAT_MAX), v(5)), v(ML99_NAT_MAX / 5)); 189 | } 190 | 191 | // ML99_divChecked 192 | { 193 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(15), v(1)), ML99_just(v(15)))); 194 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(15), v(15)), ML99_just(v(1)))); 195 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(45), v(3)), ML99_just(v(15)))); 196 | ML99_ASSERT( 197 | ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(ML99_NAT_MAX), v(5)), ML99_just(v(51)))); 198 | 199 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(4), v(0)), ML99_nothing())); 200 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(3), v(27)), ML99_nothing())); 201 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(166), v(9)), ML99_nothing())); 202 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), ML99_divChecked(v(0), v(11)), ML99_nothing())); 203 | } 204 | 205 | // ML99_DIV_CHECKED 206 | { 207 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), v(ML99_DIV_CHECKED(15, 1)), ML99_just(v(15)))); 208 | ML99_ASSERT(ML99_maybeEq(v(ML99_natEq), v(ML99_DIV_CHECKED(4, 0)), ML99_nothing())); 209 | } 210 | 211 | // ML99_mod 212 | { 213 | ML99_ASSERT_EQ(ML99_mod(v(0), v(1)), v(0 % 1)); 214 | ML99_ASSERT_EQ(ML99_mod(v(0), v(123)), v(0 % 123)); 215 | 216 | ML99_ASSERT_EQ(ML99_mod(v(1), v(28)), v(1 % 28)); 217 | ML99_ASSERT_EQ(ML99_mod(v(1), v(123)), v(1 % 123)); 218 | 219 | ML99_ASSERT_EQ(ML99_mod(v(1), v(1)), v(0)); 220 | ML99_ASSERT_EQ(ML99_mod(v(16), v(4)), v(0)); 221 | ML99_ASSERT_EQ(ML99_mod(v(ML99_NAT_MAX), v(ML99_NAT_MAX)), v(0)); 222 | 223 | ML99_ASSERT_EQ(ML99_mod(v(8), v(3)), v(8 % 3)); 224 | ML99_ASSERT_EQ(ML99_mod(v(10), v(4)), v(10 % 4)); 225 | ML99_ASSERT_EQ(ML99_mod(v(101), v(7)), v(101 % 7)); 226 | 227 | ML99_ASSERT_EQ(ML99_mod(v(13), v(14)), v(13 % 14)); 228 | ML99_ASSERT_EQ(ML99_mod(v(20), v(36)), v(20 % 36)); 229 | ML99_ASSERT_EQ(ML99_mod(v(16), v(ML99_NAT_MAX)), v(16 % ML99_NAT_MAX)); 230 | } 231 | 232 | // ML99_add3, ML99_sub3, ML99_mul3, ML99_div3 233 | { 234 | ML99_ASSERT_EQ(ML99_add3(v(8), v(2), v(4)), v(8 + 2 + 4)); 235 | ML99_ASSERT_EQ(ML99_sub3(v(14), v(1), v(7)), v(14 - 1 - 7)); 236 | ML99_ASSERT_EQ(ML99_mul3(v(3), v(2), v(6)), v(3 * 2 * 6)); 237 | ML99_ASSERT_EQ(ML99_div3(v(30), v(2), v(3)), v(30 / 2 / 3)); 238 | } 239 | 240 | // ML99_min 241 | { 242 | ML99_ASSERT_EQ(ML99_min(v(0), v(1)), v(0)); 243 | ML99_ASSERT_EQ(ML99_min(v(5), v(7)), v(5)); 244 | ML99_ASSERT_EQ(ML99_min(v(200), v(ML99_NAT_MAX)), v(200)); 245 | } 246 | 247 | // ML99_max 248 | { 249 | ML99_ASSERT_EQ(ML99_max(v(0), v(1)), v(1)); 250 | ML99_ASSERT_EQ(ML99_max(v(5), v(7)), v(7)); 251 | ML99_ASSERT_EQ(ML99_max(v(200), v(ML99_NAT_MAX)), v(ML99_NAT_MAX)); 252 | } 253 | 254 | // ML99_assertIsNat 255 | { 256 | ML99_EVAL(ML99_assertIsNat(v(0))) 257 | ML99_EVAL(ML99_assertIsNat(v(13))) 258 | ML99_EVAL(ML99_assertIsNat(v(255))) 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /tests/seq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | // ML99_seqGet 7 | { 8 | ML99_ASSERT_EQ(ML99_seqGet(0)(v((19))), v(19)); 9 | ML99_ASSERT_EQ(ML99_seqGet(0)(v((19)(8))), v(19)); 10 | ML99_ASSERT_EQ(ML99_seqGet(0)(v((19)(8)(7378))), v(19)); 11 | 12 | ML99_ASSERT_EQ(ML99_seqGet(1)(v((19)(8))), v(8)); 13 | ML99_ASSERT_EQ(ML99_seqGet(2)(v((19)(8)(7378))), v(7378)); 14 | ML99_ASSERT_EQ(ML99_seqGet(3)(v((19)(8)(7378)(10))), v(10)); 15 | ML99_ASSERT_EQ(ML99_seqGet(4)(v((19)(8)(7378)(10)(121))), v(121)); 16 | ML99_ASSERT_EQ(ML99_seqGet(5)(v((19)(8)(7378)(10)(121)(1))), v(1)); 17 | ML99_ASSERT_EQ(ML99_seqGet(6)(v((19)(8)(7378)(10)(121)(1)(80))), v(80)); 18 | ML99_ASSERT_EQ(ML99_seqGet(7)(v((19)(8)(7378)(10)(121)(1)(80)(23))), v(23)); 19 | } 20 | 21 | // ML99_SEQ_GET 22 | { 23 | ML99_ASSERT_UNEVAL(ML99_SEQ_GET(0)((19)) == 19); 24 | ML99_ASSERT_UNEVAL(ML99_SEQ_GET(0)((19)(8)) == 19); 25 | ML99_ASSERT_UNEVAL(ML99_SEQ_GET(0)((19)(8)(7378)) == 19); 26 | 27 | ML99_ASSERT_UNEVAL(ML99_SEQ_GET(1)((19)(8)) == 8); 28 | ML99_ASSERT_UNEVAL(ML99_SEQ_GET(1)((19)(8)(7378)) == 8); 29 | } 30 | 31 | #define CHECK_TAIL(a) a == 51 && CHECK_TAIL_AUX_0 32 | #define CHECK_TAIL_AUX_0(b) b == 3 && CHECK_TAIL_AUX_1 33 | #define CHECK_TAIL_AUX_1(c) c == 9 34 | 35 | // ML99_seqTail 36 | { 37 | ML99_ASSERT_UNEVAL(CHECK_TAIL ML99_EVAL(ML99_seqTail(v((9191)(51)(3)(9))))); 38 | ML99_ASSERT_EMPTY(ML99_seqTail(v((~, ~, ~)))); 39 | } 40 | 41 | // ML99_SEQ_TAIL 42 | { 43 | ML99_ASSERT_UNEVAL(CHECK_TAIL ML99_SEQ_TAIL((9191)(51)(3)(9))); 44 | ML99_ASSERT_EMPTY_UNEVAL(ML99_SEQ_TAIL((~, ~, ~))); 45 | } 46 | 47 | #undef CHECK_TAIL 48 | #undef CHECK_TAIL_AUX_0 49 | #undef CHECK_TAIL_AUX_1 50 | 51 | // ML99_seqIsEmpty 52 | { 53 | ML99_ASSERT(ML99_seqIsEmpty(v())); 54 | 55 | ML99_ASSERT(ML99_not(ML99_seqIsEmpty(v((~, ~, ~))))); 56 | ML99_ASSERT(ML99_not(ML99_seqIsEmpty(v((~)(~))))); 57 | ML99_ASSERT(ML99_not(ML99_seqIsEmpty(v((~)(~)(~))))); 58 | } 59 | 60 | // ML99_SEQ_IS_EMPTY 61 | { 62 | ML99_ASSERT_UNEVAL(ML99_SEQ_IS_EMPTY()); 63 | 64 | ML99_ASSERT_UNEVAL(ML99_NOT(ML99_SEQ_IS_EMPTY((~, ~, ~)))); 65 | ML99_ASSERT_UNEVAL(ML99_NOT(ML99_SEQ_IS_EMPTY((~)(~)))); 66 | ML99_ASSERT_UNEVAL(ML99_NOT(ML99_SEQ_IS_EMPTY((~)(~)(~)))); 67 | } 68 | 69 | #define CHECK_EXPAND(...) CHECK(__VA_ARGS__) 70 | 71 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 1987 && y == 2987 && z == 3987) 72 | #define F_IMPL(x) v(, x##987) 73 | #define F_ARITY 1 74 | 75 | // ML99_seqForEach 76 | { 77 | ML99_ASSERT_EMPTY(ML99_seqForEach(v(F), v())); 78 | CHECK_EXPAND(ML99_EVAL(ML99_seqForEach(v(F), v((1)(2)(3))))); 79 | } 80 | 81 | #undef CHECK 82 | #undef F_IMPL 83 | #undef F_ARITY 84 | 85 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 10 && y == 21 && z == 32) 86 | #define F_IMPL(i, x) v(, ), v(x##i) 87 | #define F_ARITY 2 88 | 89 | // ML99_seqForEachI 90 | { 91 | ML99_ASSERT_EMPTY(ML99_seqForEachI(v(F), v())); 92 | CHECK_EXPAND(ML99_EVAL(ML99_seqForEachI(v(F), v((1)(2)(3))))); 93 | } 94 | 95 | #undef CHECK 96 | #undef F_IMPL 97 | #undef F_ARITY 98 | 99 | #undef CHECK_EXPAND 100 | } 101 | -------------------------------------------------------------------------------- /tests/stmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main(void) { 6 | 7 | // ML99_INTRODUCE_VAR_TO_STMT 8 | { 9 | if (1) 10 | ML99_INTRODUCE_VAR_TO_STMT(int x = 5, y = 7) { 11 | assert(5 == x); 12 | assert(7 == y); 13 | } 14 | } 15 | 16 | // ML99_INTRODUCE_NON_NULL_PTR_TO_STMT 17 | { 18 | int x = 5, y = 7; 19 | 20 | // clang-format off 21 | if (1) 22 | ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(int, x_ptr, &x) 23 | ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(int, y_ptr, &y) { 24 | assert(x == *x_ptr); 25 | assert(y == *y_ptr); 26 | } 27 | // clang-format on 28 | } 29 | 30 | // ML99_CHAIN_EXPR_STMT 31 | { 32 | int x, y; 33 | 34 | // clang-format off 35 | if (1) 36 | ML99_CHAIN_EXPR_STMT(x = 1) 37 | ML99_CHAIN_EXPR_STMT(y = 2) { 38 | assert(1 == x); 39 | assert(2 == y); 40 | } 41 | // clang-format on 42 | 43 | // Test -Wunused suppression via ML99_CHAIN_EXPR_STMT. 44 | int z; 45 | 46 | if (1) 47 | ML99_CHAIN_EXPR_STMT((void)z); 48 | } 49 | 50 | // ML99_CHAIN_EXPR_STMT_AFTER 51 | { 52 | int x = 5, y = 7; 53 | 54 | if (1) { 55 | assert(5 == x); 56 | assert(7 == y); 57 | 58 | ML99_CHAIN_EXPR_STMT_AFTER(x = 1) { 59 | assert(5 == x); 60 | assert(7 == y); 61 | 62 | ML99_CHAIN_EXPR_STMT_AFTER(y = 2) { 63 | assert(5 == x); 64 | assert(7 == y); 65 | } 66 | 67 | assert(5 == x); 68 | assert(2 == y); 69 | } 70 | 71 | assert(1 == x); 72 | assert(2 == y); 73 | } 74 | } 75 | 76 | // ML99_SUPPRESS_UNUSED_BEFORE_STMT 77 | { 78 | int x, y; 79 | 80 | // clang-format off 81 | if (1) 82 | ML99_SUPPRESS_UNUSED_BEFORE_STMT(x) 83 | ML99_SUPPRESS_UNUSED_BEFORE_STMT(y) 84 | ; 85 | // clang-format on 86 | } 87 | 88 | // Clang-Format breaks with the following sequence of statements so they are put into a macro. 89 | // clang-format off 90 | 91 | #define STMT_CHAINING \ 92 | ML99_INTRODUCE_VAR_TO_STMT(int x = 5) \ 93 | ML99_INTRODUCE_NON_NULL_PTR_TO_STMT(int, x_ptr, &x) { \ 94 | assert(x == *x_ptr); \ 95 | \ 96 | ML99_CHAIN_EXPR_STMT(x = 7) \ 97 | ML99_INTRODUCE_VAR_TO_STMT(int y = 5) \ 98 | ML99_SUPPRESS_UNUSED_BEFORE_STMT(y) { \ 99 | ML99_CHAIN_EXPR_STMT_AFTER(x = 123) { \ 100 | assert(7 == x); \ 101 | } \ 102 | \ 103 | assert(123 == x); \ 104 | } \ 105 | } 106 | 107 | // clang-format on 108 | 109 | { STMT_CHAINING } 110 | 111 | #undef STMT_CHAINING 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /tests/tuple.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | #define CHECK(x, y) ML99_ASSERT_UNEVAL(x == 518 && y == 1910) 7 | #define CHECK_EXPAND(args) CHECK args 8 | 9 | // ML99_tuple 10 | { CHECK_EXPAND(ML99_EVAL(ML99_tuple(v(518, 1910)))); } 11 | 12 | // ML99_TUPLE 13 | { CHECK_EXPAND(ML99_TUPLE(518, 1910)); } 14 | 15 | #undef CHECK 16 | #undef CHECK_EXPAND 17 | 18 | // ML99_untupleEval 19 | { ML99_ASSERT_EQ(ML99_untupleEval(v((v(198)))), v(198)); } 20 | 21 | // ML99_untuple(Checked) 22 | { 23 | ML99_ASSERT_EQ(ML99_untuple(v((198))), v(198)); 24 | ML99_ASSERT_EQ(ML99_untupleChecked(v((198))), v(198)); 25 | } 26 | 27 | // ML99_UNTUPLE 28 | { ML99_ASSERT_UNEVAL(ML99_UNTUPLE((198)) == 198); } 29 | 30 | // ML99_tupleEval + ML99_untupleEval 31 | { ML99_ASSERT_EQ(ML99_untupleEval(ML99_tupleEval(v(187))), v(187)); } 32 | 33 | // ML99_tuple + ML99_untuple 34 | { ML99_ASSERT_EQ(ML99_untuple(ML99_tuple(v(187))), v(187)); } 35 | 36 | // ML99_isTuple 37 | { 38 | ML99_ASSERT(ML99_isTuple(v((1, 2, 3)))); 39 | ML99_ASSERT(ML99_not(ML99_isTuple(v(123)))); 40 | } 41 | 42 | // ML99_IS_TUPLE 43 | { 44 | ML99_ASSERT_UNEVAL(ML99_IS_TUPLE((1, 2, 3))); 45 | ML99_ASSERT_UNEVAL(!ML99_IS_TUPLE(123)); 46 | } 47 | 48 | // ML99_isUntuple 49 | { 50 | ML99_ASSERT(ML99_not(ML99_isUntuple(v((1, 2, 3))))); 51 | 52 | ML99_ASSERT(ML99_isUntuple(v(123))); 53 | ML99_ASSERT(ML99_isUntuple(v(123()))); 54 | ML99_ASSERT(ML99_isUntuple(v(123(~)))); 55 | ML99_ASSERT(ML99_isUntuple(v(123(~, ~, ~)))); 56 | 57 | ML99_ASSERT(ML99_isUntuple(v(()()))); 58 | ML99_ASSERT(ML99_isUntuple(v(()() ~))); 59 | 60 | ML99_ASSERT(ML99_isUntuple(v((~)(~)))); 61 | ML99_ASSERT(ML99_isUntuple(v((~)(~) ~))); 62 | 63 | ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~)))); 64 | ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~) ~))); 65 | 66 | ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~)(~, ~, ~)))); 67 | ML99_ASSERT(ML99_isUntuple(v((~, ~, ~)(~, ~, ~)(~, ~, ~) ~))); 68 | } 69 | 70 | // ML99_IS_UNTUPLE 71 | { 72 | ML99_ASSERT_UNEVAL(!ML99_IS_UNTUPLE((1, 2, 3))); 73 | ML99_ASSERT_UNEVAL(ML99_IS_UNTUPLE(123)); 74 | ML99_ASSERT_UNEVAL(ML99_IS_UNTUPLE((~)(~))); 75 | } 76 | 77 | // ML99_tupleCount 78 | { 79 | ML99_ASSERT_EQ(ML99_tupleCount(v((1, 2, 3))), v(3)); 80 | ML99_ASSERT_EQ(ML99_tupleCount(v((*))), v(1)); 81 | } 82 | 83 | // ML99_TUPLE_COUNT 84 | { 85 | ML99_ASSERT_UNEVAL(ML99_TUPLE_COUNT((1, 2, 3)) == 3); 86 | ML99_ASSERT_UNEVAL(ML99_TUPLE_COUNT((*)) == 1); 87 | } 88 | 89 | // ML99_tupleIsSingle 90 | { 91 | ML99_ASSERT(ML99_not(ML99_tupleIsSingle(v((1, 2, 3))))); 92 | ML99_ASSERT(ML99_tupleIsSingle(v((*)))); 93 | } 94 | 95 | // ML99_TUPLE_IS_SINGLE 96 | { 97 | ML99_ASSERT_UNEVAL(!ML99_TUPLE_IS_SINGLE((1, 2, 3))); 98 | ML99_ASSERT_UNEVAL(ML99_TUPLE_IS_SINGLE((*))); 99 | } 100 | 101 | // ML99_tupleGet 102 | { 103 | ML99_ASSERT_EMPTY(ML99_tupleGet(0)(v(()))); 104 | ML99_ASSERT_EQ(ML99_tupleGet(0)(v((19))), v(19)); 105 | ML99_ASSERT_EQ(ML99_tupleGet(0)(v((19, 8))), v(19)); 106 | ML99_ASSERT_EQ(ML99_tupleGet(0)(v((19, 8, 7378))), v(19)); 107 | 108 | ML99_ASSERT_EQ(ML99_tupleGet(1)(v((19, 8))), v(8)); 109 | ML99_ASSERT_EQ(ML99_tupleGet(2)(v((19, 8, 7378))), v(7378)); 110 | ML99_ASSERT_EQ(ML99_tupleGet(3)(v((19, 8, 7378, 10))), v(10)); 111 | ML99_ASSERT_EQ(ML99_tupleGet(4)(v((19, 8, 7378, 10, 121))), v(121)); 112 | ML99_ASSERT_EQ(ML99_tupleGet(5)(v((19, 8, 7378, 10, 121, 1))), v(1)); 113 | ML99_ASSERT_EQ(ML99_tupleGet(6)(v((19, 8, 7378, 10, 121, 1, 80))), v(80)); 114 | ML99_ASSERT_EQ(ML99_tupleGet(7)(v((19, 8, 7378, 10, 121, 1, 80, 23))), v(23)); 115 | } 116 | 117 | // ML99_TUPLE_GET 118 | { 119 | ML99_ASSERT_EMPTY_UNEVAL(ML99_TUPLE_GET(0)(())); 120 | 121 | ML99_ASSERT_UNEVAL(ML99_TUPLE_GET(0)((19)) == 19); 122 | ML99_ASSERT_UNEVAL(ML99_TUPLE_GET(0)((19, 8)) == 19); 123 | ML99_ASSERT_UNEVAL(ML99_TUPLE_GET(0)((19, 8, 7378)) == 19); 124 | } 125 | 126 | #define CHECK_TAIL(...) CHECK_TAIL_AUX(__VA_ARGS__) 127 | #define CHECK_TAIL_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 51 && b == 3 && c == 9) 128 | 129 | // ML99_tupleTail 130 | { CHECK_TAIL(ML99_EVAL(ML99_tupleTail(v((9191, 51, 3, 9))))); } 131 | 132 | // ML99_TUPLE_TAIL 133 | { CHECK_TAIL(ML99_TUPLE_TAIL((9191, 51, 3, 9))); } 134 | 135 | #undef CHECK_TAIL 136 | #undef CHECK_TAIL_AUX 137 | 138 | #define CHECK(a, b, c) ML99_ASSERT_UNEVAL(a == 1 && b == 2 && c == 3) 139 | #define CHECK_EXPAND(args) CHECK args 140 | 141 | // ML99_tuple(Append|Prepend) 142 | { 143 | CHECK_EXPAND(ML99_EVAL(ML99_tupleAppend(ML99_tuple(v(1)), v(2, 3)))); 144 | CHECK_EXPAND(ML99_EVAL(ML99_tuplePrepend(ML99_tuple(v(3)), v(1, 2)))); 145 | } 146 | 147 | // ML99_TUPLE(APPEND|PREPEND) 148 | { 149 | CHECK_EXPAND(ML99_TUPLE_APPEND((1), 2, 3)); 150 | CHECK_EXPAND(ML99_TUPLE_PREPEND((3), 1, 2)); 151 | } 152 | 153 | #undef CHECK 154 | #undef CHECK_EXPAND 155 | 156 | #define CHECK_EXPAND(...) CHECK(__VA_ARGS__) 157 | 158 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 1987 && y == 2987 && z == 3987) 159 | #define F_IMPL(x) v(, x##987) 160 | #define F_ARITY 1 161 | 162 | // ML99_tupleForEach 163 | { CHECK_EXPAND(ML99_EVAL(ML99_tupleForEach(v(F), v((1, 2, 3))))); } 164 | 165 | #undef CHECK 166 | #undef F_IMPL 167 | #undef F_ARITY 168 | 169 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 10 && y == 21 && z == 32) 170 | #define F_IMPL(x, i) v(, ), v(x##i) 171 | #define F_ARITY 2 172 | 173 | // ML99_tupleForEachI 174 | { CHECK_EXPAND(ML99_EVAL(ML99_tupleForEachI(v(F), v((1, 2, 3))))); } 175 | 176 | #undef CHECK 177 | #undef F_IMPL 178 | #undef F_ARITY 179 | 180 | #undef CHECK_EXPAND 181 | 182 | // ML99_assertIsTuple 183 | { ML99_EVAL(ML99_assertIsTuple(ML99_tuple(v(1, 2, 3)))); } 184 | } 185 | -------------------------------------------------------------------------------- /tests/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | // ML99_cat(Eval), ML99_cat(3|4) 7 | { 8 | ML99_ASSERT_EQ(ML99_cat(v(12), v(345)), v(12345)); 9 | ML99_ASSERT_EQ(ML99_cat3(v(12), v(3), v(45)), v(12345)); 10 | ML99_ASSERT_EQ(ML99_cat4(v(12), v(3), v(4), v(5)), v(12345)); 11 | 12 | #define ABC v(123) 13 | 14 | ML99_ASSERT_EQ(ML99_catEval(v(A), v(BC)), v(123)); 15 | 16 | #undef ABC 17 | } 18 | 19 | // ML99_CAT, ML99_CAT(3|4) 20 | { 21 | ML99_ASSERT_UNEVAL(ML99_CAT(12, 345) == 12345); 22 | ML99_ASSERT_UNEVAL(ML99_CAT3(12, 3, 45) == 12345); 23 | ML99_ASSERT_UNEVAL(ML99_CAT4(12, 3, 4, 5) == 12345); 24 | } 25 | 26 | #define CHECK(x, y) ML99_ASSERT_UNEVAL(x == 518 && y == 1910) 27 | #define CHECK_EXPAND(args) CHECK args 28 | 29 | // ML99_id 30 | { 31 | ML99_ASSERT_EMPTY(ML99_id(v())); 32 | CHECK_EXPAND(ML99_EVAL(ML99_id(v((518, 1910))))); 33 | ML99_ASSERT_EQ(ML99_appl(ML99_compose(v(ML99_id), v(ML99_id)), v(181)), v(181)); 34 | } 35 | 36 | #undef CHECK 37 | #undef CHECK_EXPAND 38 | 39 | // ML99_ID 40 | { 41 | ML99_ASSERT_EMPTY_UNEVAL(ML99_ID()); 42 | ML99_ASSERT_UNEVAL(ML99_ID(123) == 123); 43 | } 44 | 45 | // ML99_const 46 | { ML99_ASSERT_EQ(ML99_appl2(v(ML99_const), v(1810), v(~)), v(1810)); } 47 | 48 | #define ABC ML99_TRUE() 49 | 50 | // ML99_flip 51 | { ML99_ASSERT(ML99_appl2(ML99_flip(v(ML99_cat)), v(C), v(AB))); } 52 | 53 | #undef ABC 54 | 55 | // ML99_uncomma 56 | { 57 | ML99_ASSERT_EMPTY(ML99_uncomma(ML99_QUOTE(v()))); 58 | ML99_ASSERT_EQ(ML99_uncomma(ML99_QUOTE(v(1), v(+), v(2), v(+), v(3))), v(1 + 2 + 3)); 59 | } 60 | 61 | #define F(x, y, z) x + y + z 62 | 63 | // ML99_reify 64 | { ML99_ASSERT_EQ(ML99_appl(ML99_reify(v(F)), v(1, 2, 3)), v(1 + 2 + 3)); } 65 | 66 | #undef F 67 | 68 | // ML99_empty 69 | { 70 | ML99_ASSERT_EMPTY(ML99_empty(v())); 71 | ML99_ASSERT_EMPTY(ML99_empty(v(1, 2, 3))); 72 | } 73 | 74 | // ML99_EMPTY 75 | { 76 | ML99_ASSERT_EMPTY_UNEVAL(ML99_EMPTY()); 77 | ML99_ASSERT_EMPTY_UNEVAL(ML99_EMPTY(1, 2, 3)); 78 | } 79 | 80 | #define F 3 ML99_RPAREN(~, ~, ~) + G ML99_LPAREN(~, ~, ~) 1, 2, 81 | #define G(_1, _2, _3) _1##_2##_3 82 | 83 | // ML99_LPAREN, ML99_RPAREN 84 | { 85 | 86 | // G(1, 2, 3) + G(1, 2, 3) + G(1, 2, 3) + G(1, 2, 3) 87 | ML99_ASSERT_UNEVAL(ML99_ID(G ML99_LPAREN() 1, 2, F F F 3 ML99_RPAREN() == 123 * 4)); 88 | } 89 | 90 | #undef F 91 | #undef G 92 | 93 | #define CHECK(x, y, z) ML99_ASSERT_UNEVAL(x == 5 && y == 6 && z == 7) 94 | #define CHECK_EXPAND(args) CHECK(args) 95 | 96 | // ML99_COMMA 97 | { CHECK_EXPAND(5 ML99_COMMA() 6 ML99_COMMA(~, ~, ~) 7); } 98 | 99 | #undef CHECK 100 | #undef CHECK_EXPAND 101 | 102 | // ML99_GEN_SYM 103 | { 104 | 105 | #define TEST(...) TEST_NAMED(ML99_GEN_SYM(TEST_, x), __VA_ARGS__) 106 | #define TEST_NAMED(x_sym, ...) \ 107 | do { \ 108 | int x_sym = 5; \ 109 | (void)x_sym; \ 110 | __VA_ARGS__ \ 111 | } while (0) 112 | 113 | // `x` here will not conflict the the `x` inside `TEST`. 114 | TEST(int x = 123; (void)x;); 115 | 116 | #undef TEST 117 | #undef TEST_NAMED 118 | 119 | // Two identical calls to `ML99_GEN_SYM` must yield different identifiers. 120 | #define TEST(x1_sym, x2_sym) \ 121 | do { \ 122 | int x1_sym, x2_sym; \ 123 | (void)x1_sym; \ 124 | (void)x2_sym; \ 125 | } while (0) 126 | 127 | TEST(ML99_GEN_SYM(TEST_, x), ML99_GEN_SYM(TEST_, x)); 128 | 129 | #undef TEST 130 | } 131 | 132 | // ML99_TRAILING_SEMICOLON 133 | { 134 | ML99_TRAILING_SEMICOLON(); 135 | ML99_TRAILING_SEMICOLON(~, ~, ~); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /tests/variadics.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) { 5 | 6 | // ML99_variadicsGet 7 | { 8 | ML99_ASSERT_EMPTY(ML99_variadicsGet(0)(v())); 9 | ML99_ASSERT_EQ(ML99_variadicsGet(0)(v(19)), v(19)); 10 | ML99_ASSERT_EQ(ML99_variadicsGet(0)(v(19, 8)), v(19)); 11 | ML99_ASSERT_EQ(ML99_variadicsGet(0)(v(19, 8, 7378)), v(19)); 12 | 13 | ML99_ASSERT_EQ(ML99_variadicsGet(1)(v(19, 8)), v(8)); 14 | ML99_ASSERT_EQ(ML99_variadicsGet(2)(v(19, 8, 7378)), v(7378)); 15 | ML99_ASSERT_EQ(ML99_variadicsGet(3)(v(19, 8, 7378, 10)), v(10)); 16 | ML99_ASSERT_EQ(ML99_variadicsGet(4)(v(19, 8, 7378, 10, 121)), v(121)); 17 | ML99_ASSERT_EQ(ML99_variadicsGet(5)(v(19, 8, 7378, 10, 121, 1)), v(1)); 18 | ML99_ASSERT_EQ(ML99_variadicsGet(6)(v(19, 8, 7378, 10, 121, 1, 80)), v(80)); 19 | ML99_ASSERT_EQ(ML99_variadicsGet(7)(v(19, 8, 7378, 10, 121, 1, 80, 23)), v(23)); 20 | } 21 | 22 | // ML99_VARIADICS_GET 23 | { 24 | ML99_ASSERT_EMPTY_UNEVAL(ML99_VARIADICS_GET(0)()); 25 | 26 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(0)(19) == 19); 27 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(0)(19, 8) == 19); 28 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(0)(19, 8, 7378) == 19); 29 | 30 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(1)(19, 8) == 8); 31 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_GET(1)(19, 8, 7378) == 8); 32 | } 33 | 34 | #define CHECK_TAIL(...) CHECK_TAIL_AUX(__VA_ARGS__) 35 | #define CHECK_TAIL_AUX(a, b, c) ML99_ASSERT_UNEVAL(a == 51 && b == 3 && c == 9) 36 | 37 | // ML99_variadicsTail 38 | { CHECK_TAIL(ML99_EVAL(ML99_variadicsTail(v(9191, 51, 3, 9)))); } 39 | 40 | // ML99_VARIADICS_TAIL 41 | { CHECK_TAIL(ML99_VARIADICS_TAIL(9191, 51, 3, 9)); } 42 | 43 | #undef CHECK_TAIL 44 | #undef CHECK_TAIL_AUX 45 | 46 | #define _5_ARGS v(~, ~, ~, ~, ~) 47 | #define _10_ARGS _5_ARGS, _5_ARGS 48 | #define _50_ARGS _10_ARGS, _10_ARGS, _10_ARGS, _10_ARGS, _10_ARGS 49 | 50 | // ML99_variadicsCount 51 | { 52 | ML99_ASSERT_EQ(ML99_variadicsCount(v()), v(1)); 53 | ML99_ASSERT_EQ(ML99_variadicsCount(v(~)), v(1)); 54 | ML99_ASSERT_EQ(ML99_variadicsCount(v(~, ~)), v(2)); 55 | ML99_ASSERT_EQ(ML99_variadicsCount(v(~, ~, ~)), v(3)); 56 | ML99_ASSERT_EQ(ML99_variadicsCount(v(~, ~, ~, ~)), v(4)); 57 | ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS), v(5)); 58 | ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~)), v(6)); 59 | ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~, ~)), v(7)); 60 | ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~, ~, ~)), v(8)); 61 | ML99_ASSERT_EQ(ML99_variadicsCount(_5_ARGS, v(~, ~, ~, ~)), v(9)); 62 | ML99_ASSERT_EQ(ML99_variadicsCount(_10_ARGS), v(10)); 63 | ML99_ASSERT_EQ(ML99_variadicsCount(_10_ARGS, v(~)), v(11)); 64 | ML99_ASSERT_EQ(ML99_variadicsCount(_50_ARGS, _10_ARGS, v(~, ~, ~)), v(63)); 65 | } 66 | 67 | #define X(...) ML99_OVERLOAD(X_, __VA_ARGS__) 68 | #define X_1(a) ML99_ASSERT_UNEVAL(a == 123) 69 | #define X_2(a, b) ML99_ASSERT_UNEVAL(a == 93145 && b == 456) 70 | #define X_7(a, b, c, d, e, f, g) \ 71 | ML99_ASSERT_UNEVAL(a == 1516 && b == 1 && c == 9 && d == 111 && e == 119 && f == 677 && g == 62) 72 | 73 | // ML99_OVERLOAD 74 | { 75 | X(123); 76 | X(93145, 456); 77 | X(1516, 1, 9, 111, 119, 677, 62); 78 | } 79 | 80 | #undef X_IMPL 81 | #undef X_1_IMPL 82 | #undef X_2_IMPL 83 | #undef X_7_IMPL 84 | 85 | // ML99_VARIADICS_COUNT 86 | { 87 | ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT()), v(1)); 88 | ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT(~)), v(1)); 89 | ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT(~, ~)), v(2)); 90 | ML99_ASSERT_EQ(v(ML99_VARIADICS_COUNT(~, ~, ~)), v(3)); 91 | } 92 | 93 | #undef _5_ARGS 94 | #undef _10_ARGS 95 | #undef _50_ARGS 96 | #undef _100_ARGS 97 | 98 | // ML99_variadicsIsSingle 99 | { 100 | ML99_ASSERT(ML99_variadicsIsSingle(v())); 101 | ML99_ASSERT(ML99_variadicsIsSingle(v(~))); 102 | ML99_ASSERT(ML99_not(ML99_variadicsIsSingle(v(~, ~, ~)))); 103 | } 104 | 105 | // ML99_VARIADICS_IS_SINGLE 106 | { 107 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_IS_SINGLE()); 108 | ML99_ASSERT_UNEVAL(ML99_VARIADICS_IS_SINGLE(~)); 109 | ML99_ASSERT_UNEVAL(ML99_NOT(ML99_VARIADICS_IS_SINGLE(~, ~, ~))); 110 | } 111 | 112 | #define CHECK_EXPAND(...) CHECK(__VA_ARGS__) 113 | 114 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 1987 && y == 2987 && z == 3987) 115 | #define F_IMPL(x) v(, x##987) 116 | #define F_ARITY 1 117 | 118 | // ML99_variadicsForEach 119 | { CHECK_EXPAND(ML99_EVAL(ML99_variadicsForEach(v(F), v(1, 2, 3)))); } 120 | 121 | #undef CHECK 122 | #undef F_IMPL 123 | #undef F_ARITY 124 | 125 | #define CHECK(_, x, y, z) ML99_ASSERT_UNEVAL(x == 10 && y == 21 && z == 32) 126 | #define F_IMPL(x, i) v(, ), v(x##i) 127 | #define F_ARITY 2 128 | 129 | // ML99_variadicsForEachI 130 | { CHECK_EXPAND(ML99_EVAL(ML99_variadicsForEachI(v(F), v(1, 2, 3)))); } 131 | 132 | #undef CHECK 133 | #undef F_IMPL 134 | #undef F_ARITY 135 | 136 | #undef CHECK_EXPAND 137 | } 138 | --------------------------------------------------------------------------------