hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-19 22:22:26 +0200
committerhachem <im@hachem.wtf>2026-09-19 22:22:26 +0200
commit4bcc54914d059e950cab79164fb13ed67376ee5d (patch)
treeca4df456c92247a950be7e5ebc5da49ff96b7b3d
parent2da2c56c72e7085bd9a52f848df90c6fc701de7f (diff)
docs: README + LICENSE
-rw-r--r--LICENSE20
-rw-r--r--README90
-rw-r--r--examples/xs.sfinae36
3 files changed, 107 insertions, 39 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6b20118
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+MIT License
+
+Copyright (c) 2026 hachem
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README b/README
index b7e376f..32e77c7 100644
--- a/README
+++ b/README
@@ -1,13 +1,13 @@
# sfinae
-Substitution Failure Is Not An Error. Everything else is.
-A toy language which takes' C++ template metaprogramming to another level.
+Substitution Failure Is Not An Error. everything else is.
+a toy language which takes' C++ template metaprogramming to another level.
## build
make release build, ./sfinae in the root, objects in bin/
make debug rebuild with address and undefined sanitizers
- make check run examples/ against their .expected files
+ make check run every program in examples/ and tutorial/
make format clang-format the sources
make lint clang-tidy naming check
make clean
@@ -15,3 +15,87 @@ A toy language which takes' C++ template metaprogramming to another level.
## run
./sfinae examples/hello.sfinae
+
+## learning it
+
+six lessons under tutorial/, each a program that runs and explains itself in
+its comments. read them in order:
+
+ 01_hello.sfinae there are no strings, a string is a tuple of characters
+ 02_numbers.sfinae there are no numbers, a number is the distance between two characters
+ 03_variables.sfinae a variable holds a type, and there is no assignment
+ 04_conditions.sfinae nothing is a condition until you say ::value
+ 05_loops.sfinae ::repeat, and counting with the undeclare dance
+ 06_functions.sfinae functions take types, return types, and see only their parameters
+
+examples/ has more, including fib(0) to fib(10).
+
+## the rules
+
+- every notion starts with `::` and every statement ends with `::commit;`.
+ nothing happens until it is committed
+- there are no numeric literals. a digit is a lexer error. the only way to get
+ a number is to subtract two characters: `::difference<'F', 'A'>` is 5
+- there are no strings. a string is a `::tuple` of `::integral_constant<::char, N>`
+ types, one per character, each its own distance from `'\0'`
+- names are lists of characters: `::name<'f', 'i', 'b'>`, at most 15 of them
+- a variable holds a type, and the type must be a `::decltype(...)` of a value or
+ it cannot be declared
+- reassignment does not exist. `::undeclare` it, then `::declare` it again
+- conditions are not conditions until you say `::value`
+- loop, if and function bodies are a `::sequence<...>` of committed statements,
+ separated by commas
+- functions take types, return types, and see nothing but their parameters
+- comments are `//` to the end of the line
+
+## statements
+
+ ::declare<NAME, TYPE>::commit;
+ ::undeclare<NAME>::commit;
+ ::emit<TYPE>::commit; prints what the type says, then a newline
+ ::repeat<VALUE, SEQUENCE>::commit;
+ ::enable_if_t<COND, SEQUENCE>::commit;
+ ::static_assert<COND>::commit; fails at runtime
+ ::define<NAME, ::parameters<NAME, ...>, SEQUENCE>::commit;
+ ::return<TYPE>::commit; only inside a function
+
+## types
+
+ ::void ::int32_t ::byte ::size_t ::char
+ ::remove_cv_t<TYPE> does nothing
+ ::array<TYPE, VALUE> an array type with an extent
+ ::conditional_t<COND, TYPE, TYPE>
+ ::decltype(VALUE) the only type that carries a value
+ ::integral_constant<::char, VALUE> a character
+ ::tuple<TYPE, ...> says what its elements say, in order
+ ::invoke_result_t<NAME, ::arguments<TYPE, ...>> a call
+
+## values
+
+ ::difference<'c', 'c'> the one and only literal
+ ::sum<V, V> ::product<V, V> ::quotient<V, V>
+ ::value_of<NAME>
+ ::extent<TYPE>::value an array's extent, 0 otherwise
+ ::tuple_size<TYPE>::value same thing, longer
+ ::integral_constant<::size_t, V>::value also does nothing
+ ::conditional<COND, V, V>
+ ::declval<TYPE>() the value inside a decltype
+
+## conditions
+
+ ::true_type::value ::false_type::value
+ ::is_same<TYPE, TYPE>::value
+ ::equal<V, V>::value ::less<V, V>::value
+
+## what emit prints
+
+ ::decltype(V) the number
+ ::integral_constant<::char, V> the character
+ ::tuple<...> its elements, glued together
+ ::array<T, N> array[N]
+ ::void nothing, not even a newline
+ anything else the type's name
+
+## license
+
+MIT, see LICENSE.
diff --git a/examples/xs.sfinae b/examples/xs.sfinae
deleted file mode 100644
index e140252..0000000
--- a/examples/xs.sfinae
+++ /dev/null
@@ -1,36 +0,0 @@
-::declare<
- ::name<'x', 's'>,
- ::conditional_t<
- ::true_type::value,
- ::decltype(
- ::extent<
- ::array<
- ::array<
- ::remove_cv_t<
- ::int32_t
- >,
- ::integral_constant<
- ::size_t,
- ::tuple_size<
- ::array<
- ::byte,
- ::difference<'Z', 'F'>
- >
- >::value
- >::value
- >,
- ::integral_constant<
- ::size_t,
- ::difference<'Z', 'F'>
- >::value
- >
- >::value
- ),
- ::void
- >
->::commit;
-
-::emit<::decltype(::value_of<::name<'x', 's'>>)>::commit;
-
-// an array type says its extent, a bare type says its name
-::emit<::array<::byte, ::value_of<::name<'x', 's'>>>>::commit;