-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprologue.ps
253 lines (241 loc) · 8.09 KB
/
prologue.ps
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
% generated by lua2ps
% lua2ps by Don Viszneki [email protected]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% BEGINNING OR PROLOGUE. A SORT OF RUNTIME LIB FOR LUA2PS %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%true % enable trace output
false % disable trace output
{{ == }} {{ pop }} ifelse /trace exch def
% Lua table keys are dynamically typed, so we don't need to worry about
% coercing keys to string or anything like that.
% But Lua tables also know their "array length," so we need to take care
% for that, and also avoid key collisions. Rather than bend over backward
% <dict-initial-size> luaTableNew <dict>
/luaTableNew {
dict
dup (luaLength) 0 put
} def
% <key> luaPrepareTableKey <key2> <isInteger>
% Prepends (__lua_key_) to a stringtype key, and also tells whether or
% not the key is an integertype.
/luaPrepareTableKey {
% stack: <key>
dup type (stringtype) eq {
(Found String Key) trace
% stack: <key>
% First we prefix the key
dup length % Get key string length
% stack: <key> keylen
% Create a new string to contain the concatenated result
10 add string
dup dup
% stack: <key> <key2> <key2> <key2>
0 (__lua_key_) putinterval 10 3 % strcat prefix
% stack: <key> <key2> <key2> 10 3
index
% stack: <key> <key2> <key2> 10 <key>
putinterval
% stack: <key> <key2>
exch
% stack: <key2> <key>
pop false
% stack: <key2> isInteger:false
} {
(Found non-String key) trace
% stack: <key2> % key is already key2
dup type (integertype) eq
% stack: <key2> isInteger:bool
}
% String key?
ifelse
% stack: <key2> isString:bool
} def
% <dict> <key> luaTableGet <null|value>
/luaTableGet {
% stack: <dict> <key>
luaPrepareTableKey
% stack: <dict> <key2> <isInteger>
pop
% stack: <dict> <key2>
1 index
1 index
% stack: <dict> <key2> <dict> <key2>
known % is <key2> in <dict> ?
% stack: <dict> <key2> isKnown
{
% stack: <dict> <key2> isKnown
get
% stack: <value>
} {
% stack: <dict> <key2> isKnown
pop pop null
% stack: <value:null>
}
% stack: <dict> <key2> isKnown
ifelse
% stack: <value>
} def
% <dict> <key> <value> luaTableSet -
/luaTableSet {
% stack: <dict> <key> <value>
exch % put <key> on top, to be consumed by luaPrepareTableKey
% stack: <dict> <value> <key>
luaPrepareTableKey
% stack: <dict> <value> <key2> <isInteger>
{
(Setting Integer Key) trace
% stack: <dict> <value> <key2>
2 index % push <dict>
% stack: <dict> <value> <key2> <dict>
(luaLength) get % fetch Lua "#table" from <dict>
% stack: <dict> <value> <key2> #table
1 add % calculate #table+1
% stack: <dict> <value> <key2> #table+1
1 index % push <key2> for comparison
% stack: <dict> <value> <key2> #table+1 <key2>
eq % perform comparison
% stack: <dict> <value> <key2> needIncrement:bool
{
(Incrementing!) trace
% stack: <dict> <value> <key2>
% we need to put a value into our dict, so
2 index % push <dict>
% stack: <dict> <value> <key2> <dict>
(luaLength) % push (luaLength)
% stack: <dict> <value> <key2> <dict> (luaLength)
2 index % push <key2>, which is also #table+1
% stack: <dict> <value> <key2> <dict> (luaLength) <key2>
put % update the table's #table
% stack: <dict> <value> <key2>
} {
(Not incrementing!) trace
% stack: <dict> <value> <key2>
}
% stack: <dict> <value> <key2> needIncrement:bool {trueproc} {falseproc}
ifelse % branch
% stack: <dict> <value> <key2>
} {
(Setting non-Integer Key) trace
% stack: <dict> <value> <key2>
}
% stack: <dict> <value> <key2> <isInteger>
ifelse
% stack: <dict> <value> <key2>
exch
% stack: <dict> <key2> <value>
put % set the table's key!
% stack: empty!
} def
% <dict> luaTableLength "#table"
/luaTableLength {
(luaLength) get
} def
% Some utils i guess TODO is there a better approach to this?
/luaFooBuf 1024 string def
% Implementation of Lua's automatic string coercion
/luaToString {
dup type (stringtype) ne {
% stack: any
luaFooBuf % stack: any str
cvs % stack: substr
dup % stack: substr substr
length % stack: substr #substr
string % stack: substr result
dup % stack: substr result result
3 1 roll % stack: result substr result
cvs % stack: result substr2
pop
} if
} def
% Implementation of Lua's string concatenation operator ("..")
/luaStrConcat {
% stack: s1 s2
dup length % stack: s1 s2 #s2
2 index length % stack: s1 s2 #s2 #s1
add string % stack: s1 s2 s3
% dest index string | putinterval | -
dup 0 % stack: s1 s2 s3 s3 0
4 index % stack: s1 s2 s3 s3 0 s1
putinterval % stack: s1 s2 s3
dup % stack: s1 s2 s3 s3
3 index length % stack: s1 s2 s3 s3 #s1
3 index % stack: s1 s2 s3 s3 #s1 s2
putinterval % stack: s1 s2 s3
3 1 roll % stack: s3 s1 s2
pop pop % stack: s3
} def
% coercion to Lua bool type (only falsy Lua values: false, nil)
/luaToBool { dup type (booleantype) ne { null ne } if } def
% These are magic functions which can be called by Lua, but which are implemented
% natively in PostScript! As such, they must respect the lua2ps calling conventions
% for Lua functions.
% TODO move these into the __lua_G_math dict once lua2ps supports more varieties of call expression
/luaGet1Args { counttomark -1 roll counttomark 1 add 1 roll cleartomark } def
/luaGet2Args { counttomark -2 roll counttomark 1 add 2 roll cleartomark } def
/__lua_G_math_abs {{ luaGet1Args abs mark exch }} def
/__lua_G_math_floor {{ luaGet1Args floor mark exch }} def
/__lua_G_math_fmod {{ luaGet2Args exch 1 index 1 index div truncate mul sub mark exch }} def
% math.min() is vararg, but this implementation assumes at least one argument
/__lua_G_math_min {{ { counttomark 1 eq { exch pop exit } if dup 2 index lt { exch } if pop } loop mark exch }} def
% TODO check string length? Lua returns nil if index is out of string's bounds
/__lua_G_string_byte {{ luaGet2Args exch 1 add get mark exch }} def
% TODO check argument count
/__lua_G_string_rep {{
luaGet2Args
(2 args:) == pstack
% stack: n str
dup % stack: n str str
length % stack: n str #str
dup % stack: n str #str #str
4 -1 roll % stack: str #str #str n
mul % stack: str #str #result
dup % stack: str #str #result #result
string % stack: str #str #result result
0 % stack: str #str #result result 0
4 2 roll % stack: str result 0 #str #result
(entering for loop:) == pstack
{
(in for loop:) == pstack
% stack: str result index
2 index % stack: str result index str
2 index % stack: str result index str result
3 1 roll % stack: str result result index str
putinterval % : str result
} for
exch % stack: mark result str
3 2 roll % stack: result str mark
pop pop % stack: result
mark exch
}} def
/luaPrintBuffer 1024 string def
/luaPrintHelper {
dup type (stringtype) eq {print}
{
dup type (nulltype) eq {pop (nil) print}
{
luaPrintBuffer cvs print
} ifelse
} ifelse
} def
/__lua_G_print { {
dup mark eq { pop }
{
luaPrintHelper
{
dup mark eq { pop exit } if
(\t) print luaPrintHelper
} loop
} ifelse
(\n) print
mark
} } def
% This is used by the PostScript emitter in the lua2ps translator to handle implicit
% local variables. A PostScript optimizer I am dreaming up will remove this automatically
% for us! (Hi Rickie)
/phony { } def
% This is used by the PostScript emitter to pop a mark where the calling convention actually
% requires that the callee clean up its own stack, and the mark along with it.
/kram { } def
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% END OF THE PROLOGUE. GENERATED CODE STARTS HERE! %%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%