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
|
# tinyvm and zc. `make` builds the tools, the interpreter, the microcore and the
# language server into bin/. nothing built is kept in the tree.
#
# make everything below that is a program
# make test the whole suite (tests/test.sh)
# make check the minimal suite, for iterating (tests/test.sh -q)
# make test JOBS=4 the same, four sections at a time
# make genome rebuild build/core/genome.h from src/ and check the fixpoint
# make lsp bin/zclsp, the language server
# make web src/web/zc.wasm (needs clang with the wasm32 target)
# make js build/js/genome.json and the vm, for the javascript vm
# make run PROG=examples/hello.zc
# compile one program into a run-only image on a memory
# map sized to it (src/tools/automap.sh) -> build/run/zymr
# make vsix the vscode extension, server and all
# make clean remove bin/ and build/ and the web build
#
# nothing built is kept in the tree: the genome, the javascript vm and its
# layout, and the packed editor server all land in build/ (the web build keeps
# its historical src/web/zc.wasm path because the page loads it by name).
#
# CC picks the compiler (cc by default; clang works too).
CC ?= cc
CFLAGS ?= -O2 -w -fwrapv
ifeq ($(OS),Windows_NT)
EXE := .exe
IO := src/core/io_win.c
PORT := src/micro/port_win.c
else
EXE :=
IO := src/core/io_linux.c
PORT := src/micro/port_linux.c
CFLAGS += -pthread
MICRO_THREADS := -DZY_THREADS
endif
BIN := bin
B := build
JS := $(B)/js
# the hand-written core headers, then the generated genome beside them
COREINC := -Isrc/core -I$(B)/core
# the sources the compiler genome is built from
ZC_SRC := src/runtime/rt.zc src/core/core.zc src/compiler/compiler.zc
TOOLS := $(BIN)/zc0$(EXE) $(BIN)/mkgenome$(EXE) $(BIN)/genmap$(EXE)
PROGS := $(BIN)/zy$(EXE) $(BIN)/zym$(EXE) $(BIN)/zclsp$(EXE)
all: $(TOOLS) $(PROGS)
$(BIN) $(B):
mkdir -p $@
$(BIN)/zc0$(EXE): src/tools/zc0.c src/core/memmap.h src/core/fops.h src/core/bops.h | $(BIN)
$(CC) -O1 -w -fwrapv src/tools/zc0.c -Isrc/core -o $@
$(BIN)/mkgenome$(EXE): src/tools/mkgenome.c src/core/memmap.h | $(BIN)
$(CC) -O1 -w -fwrapv src/tools/mkgenome.c -Isrc/core -o $@
$(BIN)/genmap$(EXE): src/tools/genmap.c | $(BIN)
$(CC) $(CFLAGS) src/tools/genmap.c -Isrc/core -o $@
# the interpreter: the vm core with the compiler genome inside
$(BIN)/zy$(EXE): src/core/core.c $(IO) $(B)/core/genome.h src/core/memmap.h src/core/fops.h src/core/bops.h src/core/stack.h | $(BIN)
$(CC) $(CFLAGS) -DJTYPE=int src/core/core.c $(IO) $(COREINC) -o $@
# the portable microcore
$(BIN)/zym$(EXE): src/micro/micro.c src/micro/micro_port.h $(PORT) $(B)/core/genome.h src/core/memmap.h src/core/fops.h src/core/bops.h src/core/stack.h | $(BIN)
$(CC) $(CFLAGS) $(MICRO_THREADS) src/micro/micro.c $(PORT) $(COREINC) -Isrc/micro -o $@
# the language server is the compiler in check mode plus src/lsp/server.zc, on a map
# sized to it
lsp: $(BIN)/zclsp$(EXE)
$(BIN)/zclsp$(EXE): src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/memmap.h src/runtime/rt.zc src/core/core.zc src/compiler/compiler.zc src/lsp/server.zc src/lib/std.zc src/lib/icon.zc src/tools/embed.sh src/tools/zc0.c src/tools/genmap.c src/tools/automap.sh src/tools/mklsp.sh | $(BIN)
CC="$(CC)" bash src/tools/mklsp.sh $(B)/lsp
cp $(B)/lsp/zclsp$(EXE) $@
src/compiler/compiler.zc: src/lib/std.zc src/lib/icon.zc src/tools/embed.sh
bash src/tools/embed.sh all
# bootstrap: zc0 compiles the compiler to g0, g0 compiles it to g1, g1 to g2.
# g1 and g2 must be identical (the fixpoint), and g1 becomes build/core/genome.h.
# run this by hand after editing a .zc source; `make check` reports a stale genome.
genome: $(BIN)/zc0$(EXE) $(BIN)/mkgenome$(EXE) src/compiler/compiler.zc | $(B)
mkdir -p $(B)/s0 $(B)/s1 $(B)/core
cp src/core/core.c $(IO) src/core/memmap.h src/core/fops.h src/core/bops.h src/core/stack.h $(B)/s0/
cp src/core/core.c $(IO) src/core/memmap.h src/core/fops.h src/core/bops.h src/core/stack.h $(B)/s1/
cat $(ZC_SRC) | $(BIN)/zc0$(EXE) > $(B)/s0/genome.h
$(CC) $(CFLAGS) -DJTYPE=int $(B)/s0/core.c $(B)/s0/$(notdir $(IO)) -o $(B)/zy0$(EXE)
(cat src/tools/build.zc; printf '`'; cat $(ZC_SRC)) | $(B)/zy0$(EXE) > $(B)/g1.bin
$(BIN)/mkgenome$(EXE) < $(B)/g1.bin > $(B)/s1/genome.h
$(CC) $(CFLAGS) -DJTYPE=int $(B)/s1/core.c $(B)/s1/$(notdir $(IO)) -o $(B)/zy1$(EXE)
(cat src/tools/build.zc; printf '`'; cat $(ZC_SRC)) | $(B)/zy1$(EXE) > $(B)/g2.bin
cmp $(B)/g1.bin $(B)/g2.bin
cp $(B)/s1/genome.h $(B)/core/genome.h
@echo "fixpoint: $$(( $$(wc -c < $(B)/g1.bin) / 8 )) words, $(B)/core/genome.h updated"
# a fresh clone has no genome, so bootstrap one on demand. it is deliberately
# not rebuilt from source dependencies: the fixpoint run is expensive, and
# `make genome` is the explicit way to refresh it after editing a .zc file.
$(B)/core/genome.h:
$(MAKE) genome
js: $(JS)/genome.json $(JS)/layout.js $(JS)/tinyvm.js
$(JS):
mkdir -p $@
$(JS)/genome.json: $(B)/core/genome.h src/core/memmap.h src/js/extract_genome.js src/js/mapvalues.js | $(JS)
node src/js/extract_genome.js
$(JS)/layout.ts $(JS)/layout.js: $(JS)/genome.json
@test -f $@ || node src/js/extract_genome.js
$(JS)/tinyvm.js: src/js/tinyvm.ts src/js/layout.d.ts | $(JS)
tsc src/js/tinyvm.ts --target es2020 --lib es2020,dom --module commonjs --outDir $(JS)
# the language server image for the javascript vm, and the wasm server
lspimage: $(JS)/lsp.json
$(JS)/lsp.json: $(BIN)/zclsp$(EXE) src/js/extract_lsp.js src/js/mapvalues.js | $(JS)
node src/js/extract_lsp.js
# the vscode extension, with the server and its image inside it
vsix: | $(B)
bash src/tools/mkvsix.sh
web: src/web/zc.wasm
src/web/zc.wasm: src/micro/micro.c src/micro/micro_port.h src/web/port_wasm.c src/web/build.sh $(B)/core/genome.h src/core/memmap.h src/core/fops.h src/core/bops.h src/core/stack.h
bash src/web/build.sh $@
# one program as a run-only image: the runtime, the program, and a map exactly
# big enough for them
run: | $(B)
@test -n "$(PROG)" || { echo "make run PROG=examples/hello.zc"; exit 2; }
bash src/tools/automap.sh run $(B)/run src/runtime/run.zc $(PROG)
cp src/micro/micro.c src/micro/micro_port.h $(PORT) src/core/fops.h src/core/bops.h src/core/stack.h $(B)/run/
$(CC) $(CFLAGS) $(MICRO_THREADS) $(B)/run/micro.c $(B)/run/$(notdir $(PORT)) -I$(B)/run -o $(B)/run/zymr$(EXE)
@echo "built $(B)/run/zymr$(EXE)"
# JOBS sets how many sections run at once: make test JOBS=4
test:
bash tests/test.sh -j $(or $(JOBS),1)
# the minimal suite: bootstrap, fixpoint, interpreter and lsp checks
check:
bash tests/test.sh -q -j $(or $(JOBS),2)
clean:
rm -rf $(BIN) $(B) src/web/zc.wasm
.PHONY: all lsp genome js lspimage vsix web run test check clean
|