hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/README
blob: eea77c050de85353ceea8187b1718f62548deb99 (plain)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# sfinae

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 every program in examples/ and tutorial/
    make format     clang-format the sources
    make lint       clang-tidy naming check
    make clean
    make install    copy ./sfinae to PREFIX/bin, PREFIX defaults to /usr/local
    make uninstall

## 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.