Skip to content

Commit 5e8aa24

Browse files
committed
Add dependency on crystal-capnproto.
This will allow the Crystal-based Savi compiler to read the outputs of the self-hosted (Savi-based) Savi compiler stages.
1 parent 531764d commit 5e8aa24

25 files changed

+3584
-2
lines changed

Makefile

+15-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ example.compile: PHONY SAVI
9797
example.deps: PHONY SAVI
9898
echo && $(SAVI) deps update --cd "$(dir)" $(extra_args)
9999

100-
# Generate Savi source code from CapnProto definitions.
101-
gen.capnp: PHONY self-hosted.deps $(BUILD)/capnpc-savi
100+
# Generate Savi and Crystal source code from CapnProto definitions.
101+
gen.capnp: PHONY self-hosted.deps $(BUILD)/capnpc-savi $(BUILD)/capnpc-crystal
102102
capnp compile \
103103
-I"$(shell find self-hosted/deps/github:jemc-savi/CapnProto/* -name src | sort -r -V | head -n 1)/" \
104104
self-hosted/src/SaviProto/SaviProto.AST.capnp --output=- \
@@ -107,6 +107,14 @@ gen.capnp: PHONY self-hosted.deps $(BUILD)/capnpc-savi
107107
-I"$(shell find self-hosted/deps/github:jemc-savi/CapnProto/* -name src | sort -r -V | head -n 1)/" \
108108
self-hosted/src/SaviProto/SaviProto.Source.capnp --output=- \
109109
| $(BUILD)/capnpc-savi > self-hosted/src/SaviProto/SaviProto.Source.capnp.savi
110+
capnp compile \
111+
-I"$(shell find self-hosted/deps/github:jemc-savi/CapnProto/* -name src | sort -r -V | head -n 1)/" \
112+
self-hosted/src/SaviProto/SaviProto.AST.capnp --output=- \
113+
| $(BUILD)/capnpc-crystal > self-hosted/src/SaviProto/SaviProto.AST.capnp.cr
114+
capnp compile \
115+
-I"$(shell find self-hosted/deps/github:jemc-savi/CapnProto/* -name src | sort -r -V | head -n 1)/" \
116+
self-hosted/src/SaviProto/SaviProto.Source.capnp --output=- \
117+
| $(BUILD)/capnpc-crystal > self-hosted/src/SaviProto/SaviProto.Source.capnp.cr
110118
gen.capnp.check: gen.capnp
111119
git diff --exit-code self-hosted/src/SaviProto
112120

@@ -272,6 +280,11 @@ $(BUILD)/capnpc-savi: $(MAKE_VAR_CACHE)/CAPNPC_SAVI_DOWNLOAD_URL
272280
chmod a+x $@
273281
touch $@
274282

283+
# Build the CapnProto compiler plugin for Crystal code gen.
284+
# See github.com/jemc/crystal-capnproto for more info.
285+
$(BUILD)/capnpc-crystal: $(shell find lib/capnproto/src -name '*.cr')
286+
crystal build lib/capnproto/src/capnpc-crystal/main.cr -o $@
287+
275288
# Build the Crystal LLVM C bindings extensions as LLVM bitcode.
276289
# This bitcode needs to get linked into our Savi compiler executable.
277290
$(BUILD)/llvm_ext.bc: $(LLVM_PATH)

lib/.shards.info

+3
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ shards:
1313
clang:
1414
git: https://github.com/crystal-lang/clang.cr.git
1515
version: 0.3.0
16+
capnproto:
17+
git: https://github.com/jemc/crystal-capnproto.git
18+
version: 1.0.0+git.commit.61c3cf19167eb71398a1f36da2032c4560ebcdc9

lib/capnproto/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/bin

lib/capnproto/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# crystal-capnproto
2+
3+
Library for reading [Cap'n Proto](https://capnproto.org/) serialized data structures in the [Crystal language](https://crystal-lang.org/).

lib/capnproto/lib

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
..

lib/capnproto/shard.yml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: capnproto
2+
version: 1.0.0
3+
4+
authors:
5+
- Joe Eli McIlvain <[email protected]>
6+
7+
crystal: '>= 1.10.1'
8+
9+
license: MIT
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
require "./spec_helper"
2+
3+
from_segment = ->(byte_offset : UInt32, bytes : Bytes) do
4+
segments = [] of CapnProto::Segment
5+
segment = CapnProto::Segment.new(segments, bytes)
6+
CapnProto::Pointer::StructList.parse_from(
7+
segment, byte_offset, segment.u64(byte_offset)
8+
)
9+
end
10+
11+
from_segments = ->(byte_offset : UInt32, chunks : Array(Bytes)) do
12+
segments = [] of CapnProto::Segment
13+
chunks.each { |chunk| CapnProto::Segment.new(segments, chunk) }
14+
segment = segments[0]
15+
CapnProto::Pointer::StructList.parse_from(
16+
segment, byte_offset, segment.u64(byte_offset)
17+
)
18+
end
19+
20+
describe CapnProto::Pointer::StructList do
21+
it "reads struct values from a struct list region" do
22+
p = from_segment.call(0_u32, Bytes[
23+
0x01, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00,
24+
0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
25+
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
26+
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
27+
0x25, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
28+
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
29+
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
30+
0x1d, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
31+
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
32+
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
33+
0x15, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
34+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
35+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
36+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
37+
'H'.ord, 'e'.ord, 'l'.ord, 'l'.ord, 'o'.ord, ' '.ord, 'A'.ord, 0x00,
38+
'H'.ord, 'e'.ord, 'l'.ord, 'l'.ord, 'o'.ord, ' '.ord, 'B'.ord, 0x00,
39+
'H'.ord, 'e'.ord, 'l'.ord, 'l'.ord, 'o'.ord, ' '.ord, 'C'.ord, 0x00,
40+
'L'.ord, 'o'.ord, 'n'.ord, 'e'.ord, 'l'.ord, 'y'.ord, ' '.ord, 'D'.ord,
41+
])
42+
43+
p0 = p[0].not_nil!
44+
p0.u64(0x0).should eq 0x1111111111111111_u64
45+
p0.u64(0x8).should eq 0x2222222222222222_u64
46+
p0.u64(0x10).should eq 0 # outside the data region
47+
p0.text(0).should eq "Hello A"
48+
p0.text(1).should eq "" # outside the pointers region
49+
50+
p1 = p[1].not_nil!
51+
p1.u64(0x0).should eq 0x3333333333333333_u64
52+
p1.u64(0x8).should eq 0x4444444444444444_u64
53+
p1.u64(0x10).should eq 0 # outside the data region
54+
p1.text(0).should eq "Hello B"
55+
p1.text(1).should eq "" # outside the pointers region
56+
57+
p2 = p[2].not_nil!
58+
p2.u64(0x0).should eq 0x5555555555555555_u64
59+
p2.u64(0x8).should eq 0x6666666666666666_u64
60+
p2.u64(0x10).should eq 0 # outside the data region
61+
p2.text(0).should eq "Hello C"
62+
p2.text(1).should eq "" # outside the pointers region
63+
64+
p[3].should eq nil # outside the list region
65+
66+
first_words = [] of UInt64
67+
p.each { |s| first_words << s.u64(0x0) }
68+
first_words.should eq [
69+
0x1111111111111111_u64,
70+
0x3333333333333333_u64,
71+
0x5555555555555555_u64,
72+
]
73+
end
74+
75+
it "can point to a struct list region via a far pointer" do
76+
p = from_segments.call(0_u32, [
77+
Bytes[
78+
0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
79+
],
80+
Bytes[
81+
'T'.ord, 'h'.ord, 'e'.ord, 'r'.ord, 'e'.ord, '\''.ord, 's'.ord, ' '.ord,
82+
'n'.ord, 'o'.ord, 't'.ord, 'h'.ord, 'i'.ord, 'n'.ord, 'g'.ord, ' '.ord,
83+
'm'.ord, 'e'.ord, 'a'.ord, 'n'.ord, 'i'.ord, 'n'.ord, 'g'.ord,
84+
'f'.ord, 'u'.ord, 'l'.ord, ' '.ord, 'i'.ord, 'n'.ord, ' '.ord,
85+
't'.ord, 'h'.ord, 'i'.ord, 's'.ord, ' '.ord,
86+
'm'.ord, 'i'.ord, 'd'.ord, 'd'.ord, 'l'.ord, 'e'.ord, ' '.ord,
87+
's'.ord, 'e'.ord, 'g'.ord, 'm'.ord, 'e'.ord, 'n'.ord, 't'.ord, '.'.ord,
88+
' '.ord, 'I'.ord, 't'.ord, '\''.ord, 's'.ord, ' '.ord,
89+
'j'.ord, 'u'.ord, 's'.ord, 't'.ord, ' '.ord, 'a'.ord, ' '.ord,
90+
'p'.ord, 'l'.ord, 'a'.ord, 'c'.ord, 'e'.ord,
91+
'h'.ord, 'o'.ord, 'l'.ord, 'd'.ord, 'e'.ord, 'r'.ord, ' '.ord,
92+
'i'.ord, 'n'.ord, ' '.ord, 'b'.ord, 'e'.ord, 't'.ord, 'w'.ord,
93+
'e'.ord, 'e'.ord, 'n'.ord, ' '.ord, 't'.ord, 'h'.ord, 'e'.ord, ' '.ord,
94+
'o'.ord, 't'.ord, 'h'.ord, 'e'.ord, 'r'.ord, ' '.ord,
95+
't'.ord, 'w'.ord, 'o'.ord, '.'.ord,
96+
],
97+
Bytes[
98+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
99+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
100+
0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
101+
0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
102+
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
103+
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
104+
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
105+
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
106+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
107+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
108+
]
109+
])
110+
111+
p[0].not_nil!.u64(0x0).should eq 0x1111111111111111_u64
112+
p[0].not_nil!.u64(0x8).should eq 0x2222222222222222_u64
113+
p[0].not_nil!.u64(0x10).should eq 0 # outside the data region
114+
p[1].not_nil!.u64(0x0).should eq 0x3333333333333333_u64
115+
p[1].not_nil!.u64(0x8).should eq 0x4444444444444444_u64
116+
p[1].not_nil!.u64(0x10).should eq 0 # outside the data region
117+
end
118+
119+
it "can point to a byte region via a double-far pointer" do
120+
p = from_segments.call(0_u32, [
121+
Bytes[
122+
0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
123+
],
124+
Bytes[
125+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
126+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
127+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
128+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
129+
0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
130+
0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
131+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
132+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
133+
],
134+
Bytes[
135+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
136+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
137+
0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
138+
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
139+
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
140+
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
141+
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
142+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
143+
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
144+
]
145+
])
146+
147+
p[0].not_nil!.u64(0x0).should eq 0x1111111111111111_u64
148+
p[0].not_nil!.u64(0x8).should eq 0x2222222222222222_u64
149+
p[0].not_nil!.u64(0x10).should eq 0 # outside the data region
150+
p[1].not_nil!.u64(0x0).should eq 0x3333333333333333_u64
151+
p[1].not_nil!.u64(0x8).should eq 0x4444444444444444_u64
152+
p[1].not_nil!.u64(0x10).should eq 0 # outside the data region
153+
end
154+
end

0 commit comments

Comments
 (0)