-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.dnd
More file actions
203 lines (181 loc) · 6.27 KB
/
README.dnd
File metadata and controls
203 lines (181 loc) · 6.27 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
Table of Contents::md #noid
::toc
DrC::title
DrC is a C Preprocessor/Parser/Interpreter targeting C2y with a boatload of
[extensions | extensions]. It can interpret real C projects (including itself)
and has seamless interfacing with native dynamic libraries. `#include` a
header and `#pragma lib` it and you can call native C functions from your
interpreted C code.
A [REPL mode] is also offered.
After building, try it out with <code>Bin/drc <a href=Samples/hello.c>Samples/hello.c</a></code>
or peruse the other [Samples].
Major Features Include:
- [C Interpreter]
- [Bindings-Free FFI]
- [Native Threads]
- [REPL mode]
- [First Class Types]
- [Static If]
- [Procmacros]
- [Methods and FUCS]
- [Named Arguments]
- [Crazy Preprocessor]
- [Embeddable]
- [Self Hosting]
::links
extensions = EXTENSIONS.md
Samples = Samples
Samples/hello.c = Samples/hello.c
Building::md
Nobuild::details
This project uses a "nobuild" build system. Bootstrap the build system by
doing something like:
::pre.console
$ drc build.c -o build && ./build -b Bin && ./build tests
From then on, you can just build using the build program. If you edit it or
any of its deps, it will rebuild itself.
The build system remembers the previous flags, like <tt>-O</tt>. If you
change those or switch them off, it knows to rebuild any programs built
with those flags.
See [build.c] for more info.
::links
build.c = build.c
Makefile::details
If you like using make, the makefile will bootstrap the build system for
you.
build.bat::details
You can bootstrap the build system on windows using build.bat. This is
purely convenience.
Warning: windows is untested and probably doesn't compile.
Dependencies::details
Depends on libffi. Assumes you can just do `-lffi` and that just works. If
you are on windows, that sucks. It will work there but getting it so it
"just werks" on windows is not worth the hassle.
C Interpreter::md
C scripts, top level statements, no separate compile and run steps, no
intermediate files.
REPL mode::md
Run `Bin/drc` with `--repl` for a REPL experience, with interactive function calls etc.
::pre.console
$ Bin/drc --repl
cc> #include <stdio.h>
... int x = 3;
... for(int i = 0; i < 4; i++) printf("x = %d\n", x);
...
x = 3
x = 3
x = 3
x = 3
cc> ^D
Bindings-Free FFI::md
`#include` real C headers, `#pragma lib` to load them. Also supports `#pragma
pkg_config` to populate include paths, lib paths etc.
::pre.C
#pragma pkg_config "sdl2" // could ifdef for non-pkg-config systems
#pragma lib "SDL2" // load the library
#include <SDL2/SDL.h> <SDL.h> // extension, tries each in order
// top level statements
SDL_Init(SDL_INIT_VIDEO);
// Call SDL funcs from your scripts now!
Native Threads::md
Related to above, you can call actual system APIs to create threads with
interpreted code.
::pre.C
#include <stdio.h>
#include <pthread.h>
pthread_t t;
pthread_create(&t, NULL, void*(void* arg){
printf("Hello from a thread! %p\n", (void*)pthread_self());
return NULL;
}, NULL);
pthread_join(t, NULL);
This example also shows off our captureless-lambda extension.
First Class Types::md
`_Type T = int; printf("%s\n", T.name)`, etc. Pass them as values, reflect
over them, see the [json demo]
::links
json demo = Samples/Extensions/json_parse.c
Static If::md
Include or exclude statements/decls based on compile time expressions.
::pre.C
static if(__shell("date")[0] == 'W'){
enum {IT_IS_WEDNESDAY=1};
}
printf("IT_IS_WEDNESDAY: %d\n", IT_IS_WEDNESDAY); // only compiles on wednesday
More seriously:
::pre.C
#define S_(x) #x
#define S(x) S_(x)
// __ident produces a single identifier token
// from catted strings, even if it has non-identifier characters.
#define Optional(T) __ident("Optional." S(T))
#defblock OPTIONAL_DEF(T)
typedef struct Optional(T) Optional(T);
static if(T.is_pointer){
// use NULL as sentinel
struct Optional(T){
T value;
_Bool has_value(Optional(T)* self){ return self.value; }
};
}
else {
struct Optional(T){
T value;
_Bool _has_value;
_Bool has_value(Optional(T)* self){ return self._has_value; }
};
}
#endblock
OPTIONAL_DEF(const char*);
OPTIONAL_DEF(int);
_Static_assert(sizeof(Optional(const char*)) == sizeof(const char*));
_Static_assert(sizeof(Optional(int)) > sizeof(int));
Unlike `#if`, `static if` has access to C-level information without the boilerplate of a procmacro.
Procmacros::md
Register a C function as a macro, call it as a macro, outputs get turned into
pp-tokens, you can mix them into your source file for code generation and
other things.
Also, [power up preprocessor conditionals]:
::links
power up preprocessor conditionals = Samples/Extensions/procmacro-if.c
::pre.C
_Bool IS_POINTER(_Type T){ return T.is_pointer;}
#pragma procmacro IS_POINTER
#define T void*
#if IS_POINTER(T)
#pragma message T "is a pointer"
#else
#pragma message T "is not a pointer"
#endif
#undef T
#define T int
#if IS_POINTER(T)
#pragma message T "is a pointer"
#else
#pragma message T "is not a pointer"
#endif
Methods and FUCS::md
Define methods in struct body, auto deref, `.` and <code>-></code> merged,
FUCS: Function Uniform Call Syntax to have `.func` notation with free
functions.
Named Arguments::md
Same syntax as designated initializers.
::pre.C
int func_with_lotta_bools(_Bool jump, _Bool skip, _Bool hop);
func_with_lotta_bools(.hop = 1, .jump = 0, .skip = 1); // out of order
Numbered args are also supported, but honestly aren't that useful, but whatever.
Crazy Preprocessor::md
There's a bunch of cool preprocessor macros like `__mixin`, `__map`, `#defblock`.
There's also an API for registering your own builtin macros if you are embedding this
interpreter.
Embeddable::md
This will support being embedded. WIP. No global state.
Self Hosting::md
The C interpreter is able to run itself.
::pre.console
$ Bin/drc cc.c Samples/hello.c
Hello world
$ Bin/drc cc.c cc.c Samples/hello.c
Hello world
::css #import
README.css