trac_lang 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/examples/term.trl ADDED
@@ -0,0 +1,129 @@
1
+
2
+ ANSI Escape Codes
3
+ -----------------
4
+
5
+ #(PS,Loading examples/term.trl...)'
6
+
7
+ Here are some basic ANSI escape codes for controlling text appearance.
8
+
9
+ First we define the codes for effects:
10
+
11
+ #(DS,define-effect,(
12
+ #(EQ,<number>,-END-,,(
13
+ #(DS,clr-#(CS,effect-list),<number>)
14
+ #(define-effect,#(CS,effect-list,-END-))
15
+ ))
16
+ ))
17
+ #(scrub,define-effect)
18
+ #(SS,define-effect,<number>)'
19
+
20
+ #(DS,effect-list,(
21
+ 0 reset
22
+ 1 bright
23
+ 2 dim
24
+ 4 underscore
25
+ 5 blink
26
+ 7 reverse
27
+ 8 hidden))'
28
+
29
+ #(SS,effect-list,( ),##(CL,return))'
30
+
31
+ Notice how I segment the effect-list by spaces and newlines. That makes it
32
+ easy to write readable lists in your code.
33
+
34
+ Discard first empty segment: #(CS,effect-list)'
35
+
36
+ #(define-effect,#(CS,effect-list))'
37
+
38
+ Next we define the codes for colors, foreground and background:
39
+
40
+ #(DS,define-color,(
41
+ #(EQ,<number>,-END-,,(
42
+ #(define-colors,#(CS,color-list),<number>)
43
+ #(define-color,#(CS,color-list,-END-))
44
+ ))
45
+ ))
46
+ #(scrub,define-color)
47
+ #(SS,define-color,<number>)'
48
+
49
+ #(DS,define-colors,(
50
+ #(DS,clr-<name>-fg,3<number>)
51
+ #(DS,clr-<name>-bg,4<number>)
52
+ ))
53
+ #(scrub,define-colors)
54
+ #(SS,define-colors,<name>,<number>)'
55
+
56
+ #(DS,color-list,(
57
+ 0 black
58
+ 1 red
59
+ 2 green
60
+ 3 yellow
61
+ 4 blue
62
+ 5 magenta
63
+ 6 cyan
64
+ 7 white))
65
+
66
+ #(SS,color-list,( ),##(CL,return))'
67
+
68
+ Discard first empty segment: #(CS,color-list)'
69
+
70
+ #(define-color,#(CS,color-list))'
71
+
72
+ #(DD,define-effect,define-color)'
73
+
74
+
75
+ Now we define our script that will translate the names above into actual escape
76
+ codes.
77
+
78
+ #(DS,color,(
79
+ #(DS,list,<list>)
80
+ #(SS,list,##(CL,space))
81
+ #(DS,read,(
82
+ #(clr-<s>)
83
+ #(next,#(CS,list,END))
84
+ ))
85
+ #(SS,read,<s>)
86
+ #(DS,next,(
87
+ #(EQ,<s>,END,,(;#(read,<s>)))
88
+ ))
89
+ #(SS,next,<s>)
90
+ #(escape)[#(read,#(CS,list,reset))m
91
+ #(DD,list,read,next)
92
+ ))
93
+ #(sss,color,<list>)'
94
+
95
+ Usage:
96
+ (
97
+ #(color,bright red-fg blue-bg)
98
+
99
+ Defaults to reset: #(color)
100
+
101
+ The escape codes need to be embedded in print commands to take effect, like
102
+ so:
103
+
104
+ #(PS,#(color,green-fg)I am green!#(color) I am not!)
105
+
106
+ Using these you can make templates for creating forms:
107
+
108
+ #(DS,template,(
109
+ *label*Name:** *field*<name>**
110
+ *label*Occupation:** *field*<job>**
111
+ *label*Age:** *field*<age>**
112
+ ))
113
+
114
+ #(SS,template,**,*label*,*field*)
115
+
116
+ #(DS,form,##(CL,template,#(color),#(color,bright),#(color,reverse)))
117
+
118
+ #(SS,form,<name>,<job>,<age>)
119
+
120
+ Now you can fill out the form multiple times, and it will print with the
121
+ format you decided on. Notice that I used a neutral call on the template
122
+ when defining the form to protect the newlines in it.
123
+
124
+ )
125
+
126
+
127
+ #(PS,(success!
128
+ ))'
129
+
data/examples/util.trl ADDED
@@ -0,0 +1,366 @@
1
+
2
+ Basic Utilities
3
+
4
+ #(PS,Loading examples/util.trl...)'
5
+
6
+ Scrub Whitespace
7
+ ----------------
8
+ A problem with TRAC definitions is they're strings, and so if you add
9
+ whitespace to make them readable, your definition ends up with a lot of
10
+ extraneous whitespace. Carriage return and line feed are normally ignored if
11
+ they aren't protected, so they don't need to be removed, but spaces and tabs
12
+ aren't. So here are some scripts to help out:
13
+
14
+ scrub-char
15
+ scrubs a single character out of your script
16
+
17
+ #(DS,scrub-char,(#(SS,<f>,(<c>))#(DS,<f>,##(CL,<f>))))
18
+ #(SS,scrub-char,<f>,<c>)'
19
+
20
+ scrub
21
+ scrubs spaces and tabs out of your script
22
+
23
+ #(DS,scrub,(#(scrub-char,<f>,( ))#(scrub-char,<f>,( ))))
24
+ #(SS,scrub,<f>)'
25
+
26
+ Call these scripts on your definitions before you call SS, otherwise your
27
+ arguments will get messed up. To make that easier to do:
28
+
29
+ sss scrubs your script and then segments according to the args you pass
30
+
31
+ #(DS,sss,(#(scrub,<f>)#(SS,<f>,<args>)))
32
+ #(SS,sss,<f>,<args>)'
33
+
34
+ If you use this for a script that has multiple arguments, protect the argument
35
+ list with parentheses, otherwise TRAC will think your arguments are extra
36
+ arguments for sss, instead of for SS. Remember TRAC is only passing around
37
+ strings, not data structures.
38
+
39
+
40
+ Special Characters
41
+ ------------------
42
+ Another problem with TRAC is that some characters are special, and so can't be
43
+ used normally. This is especially true of the two editing characters - the "\"
44
+ and the "@". They can't be typed in, but since editing is not done when
45
+ reading a file, they can be entered in a file. So here are definitions for
46
+ each.
47
+
48
+ #(DS,backslash,\)'
49
+ #(DS,at,@)'
50
+
51
+ The meta character can be changed, so that a definition of the default meta
52
+ character single quote can be made.
53
+
54
+ #(CM,*)'
55
+ #(DS,quote,')*
56
+ #(CM,')*
57
+
58
+ Both the hash or number sign and the comma can easily be protected by
59
+ parentheses, so neither need a separate defintion. Here's how parentheses can
60
+ be defined:
61
+
62
+ #(DS,parens,(()))
63
+ #(DS,open-paren,##(CC,parens))
64
+ #(DS,close-paren,##(CC,parens))
65
+ #(DD,parens)'
66
+
67
+ However, even if you use a neutral call, unmatched parens can only be passed to
68
+ a TRAC primitive. You can't pass them to a form you define, because once the
69
+ form is expanded, the parens will no longer match.
70
+
71
+ Some important characters:
72
+
73
+ #(DS,return,(
74
+ ))'
75
+ #(DS,tab, )'
76
+ #(DS,space, )'
77
+ #(DS,bell,)'
78
+ #(DS,escape,)'
79
+ #(DS,backspace,)'
80
+
81
+ The following is the first control character, known as SOH. We will use it as
82
+ a delimiter sometimes, instead of using a printable character.
83
+
84
+ #(DS,.,)'
85
+
86
+
87
+ Character Classes
88
+ -----------------
89
+
90
+ Here are some useful character classes.
91
+
92
+ #(DS,lower,abcdefghijklmnopqrstuvwxyz)'
93
+ #(DS,upper,ABCDEFGHIJKLMNOPQRSTUVWXYZ)'
94
+ #(DS,digit,0123456789)'
95
+ #(DS,whitespace,##(return)##(tab)##(space))'
96
+
97
+ Here are some scripts for using the character classes. These were inspired by
98
+ TTM primitives that have the same names. See page 20 and 21 of TTM: An
99
+ Experimental and Interpretive Language.
100
+
101
+ https://github.com/Unidata/ttm/raw/master/ttm_interpretive_language_pr_07.pdf
102
+
103
+ #(DS,[TCL],(
104
+ #(EQ,(<c>),--,(Z),(
105
+ #(CR,class)
106
+ #(EQ,##(IN,class,(<c>),--),--,(F),(T))
107
+ ))
108
+ ))
109
+ #(sss,[TCL],(class,<c>,T,F,Z))
110
+ #(DS,TCL,(#([TCL],class,##(CC,form,--),(T),(F),(Z))))
111
+ #(SS,TCL,class,form,T,F,Z)'
112
+
113
+ TCL (Test Class) tests if the character pointed to by the form pointer is in
114
+ the class given. If returns T if so, F if not, and Z if the form pointer is at
115
+ the end of the form.
116
+
117
+ #(DS,[CCL],(
118
+ #([TCL],class,(<c>),(
119
+ (<c>)#([CCL],class,##(CC,form,--),form)
120
+ ),(
121
+ #(,##(CN,form,-1))
122
+ ))
123
+ ))
124
+ #(sss,[CCL],(class,<c>,form))
125
+ #(DS,CCL,(#([CCL],class,##(CC,form,--),form)))
126
+ #(SS,CCL,class,form)'
127
+
128
+ CCL (Call Class) returns all consecutive characters from the given form,
129
+ starting at the form pointer and going up to but not including the first
130
+ character that is not in the given class. In other words, it will return a
131
+ string of characters that are in the class given. If there are no characters
132
+ in the given class at the form pointer, or if the form pointer is at the end of
133
+ the form, nothing is returned.
134
+
135
+ #(DS,SCL,(#(,#(CCL,class,form))))
136
+ #(SS,SCL,class,form)'
137
+
138
+ SCL (Scan Class) will move the form pointer past all characters in the form
139
+ that are in the given character class.
140
+
141
+
142
+ Times
143
+ -----
144
+ Execute something a number of times. The action can be a simple string or
145
+ something more complicated.
146
+
147
+ #(DS,times,(
148
+ #(EQ,<n>,0,,(
149
+ <action>#(times,#(SU,<n>,1),(<action>)))
150
+ ))
151
+ )
152
+ #(sss,times,(<n>,<action>))'
153
+
154
+
155
+ Character Count
156
+ ---------------
157
+ Count the number of characters in a form. This is probably the most involved
158
+ thing that I wish was a primitive in TRAC. There isn't a code golf challenge
159
+ that doesn't require this, and if it was a primitive TRAC might actually have a
160
+ chance.
161
+
162
+ This really counts from the form pointer to the end, and sets the form pointer
163
+ at the end of the string as a side effect. So if you want the real length, you
164
+ have to call CR beforehand.
165
+
166
+ #(DS,count,(
167
+ #(EQ,##(CC,<f>,--),--,<tot>,(
168
+ #(count,<f>,#(AD,1,<tot>))
169
+ ))
170
+ ))
171
+ #(sss,count,(<f>,<tot>))'
172
+
173
+
174
+ Concatenate
175
+ -----------
176
+
177
+ Add given characters to the end of a given form. A very simple definition, but
178
+ useful when you only have one reference to the form you want to concatenate on.
179
+
180
+ #(DS,concat,(
181
+ #(DS,form,##(CL,form,args)(str))
182
+ #(SS,form,args)
183
+ ))
184
+ #(sss,concat,(form,args,str))'
185
+
186
+
187
+ Increment
188
+ ---------
189
+
190
+ Another very simple definition of something that's easy to do. But it's also
191
+ easy to forget that the form "num" needs to executed for the AD to work, in
192
+ which case you end up with one as your value, instead of what you want.
193
+
194
+ #(DS,inc,(#(DS,num,#(AD,#(num),1))))
195
+ #(SS,inc,num)'
196
+
197
+
198
+ Move To End
199
+ -----------
200
+ Move to the end of a form. This is relatively simple, but it sure would be
201
+ nice to have a primitive that could do this, the way CR can move to the start
202
+ of a form.
203
+
204
+ #(DS,end,(
205
+ #(EQ,##(CC,<form>,--),--,,(
206
+ #(end,<form>)
207
+ ))
208
+ ))
209
+ #(sss,end,<form>)'
210
+
211
+
212
+ At End Or Beginning?
213
+ --------------------
214
+ Test if you are at the end of a form. This uses a special trick of TRAC, when
215
+ the form pointer is at the end of a form, CN returns the end-of-form argument
216
+ even when you ask for zero characters. The same trick works at the beginning
217
+ of a form when you use negative zero. This trick is the whole reason that
218
+ negative zero exists in TRAC.
219
+
220
+ #(DS,end?,(#(EQ,#(CN,form,0,#(.)),#(.),(T),(F))))
221
+ #(SS,end?,form,T,F)'
222
+
223
+ #(DS,start?,(#(EQ,#(CN,form,-0,#(.)),#(.),(T),(F))))
224
+ #(SS,start?,form,T,F)'
225
+
226
+
227
+ Form Exists
228
+ -----------
229
+
230
+ This relies on a odd property of IN. If you search for the empty string in a
231
+ form using IN, if the form doesn't exist, the empty string is returned. If the
232
+ form does exist, searching for the empty string will fail, and so the
233
+ "not found" parameter will be returned. We can use this to create a test for
234
+ the existence of a form.
235
+
236
+ #(DS,exists?,(#(EQ,#(IN,form,,notfound),notfound,(T),(F))))
237
+ #(SS,exists?,form,T,F)'
238
+
239
+
240
+ Starts With
241
+ -----------
242
+
243
+ Tests if a given string starts with a given value. Notice that I have to
244
+ define a form with the string to search in and then delete it when I'm done
245
+ with it. I use the special character as the temporary name, so that I don't
246
+ overwrite an existing form.
247
+
248
+ #(DS,starts-with,(
249
+ #(DS,#(.),(string1))
250
+ #(EQ,#(IN,#(.),(string2),-),,#(DD,#(.))(T),(F))
251
+ ))
252
+ #(sss,starts-with,(string1,string2,T,F))
253
+
254
+
255
+ List Forms With Prefix
256
+ ----------------------
257
+
258
+ One way to organize the list of defined forms is to prefix the name of related
259
+ forms with a certain value. For instance, all the color code definitions in
260
+ the term.trl file are prefixed with "clr-". This script allows you to list the
261
+ only those forms. Notice I use the dot special character as a delimiter, so
262
+ you can use any printable character in your form names.
263
+
264
+ #(DS,list-prefix,(
265
+ #(DS,[names],#(LN,#(.)))
266
+ #(SS,[names],#(.))
267
+ #(DS,[delimiter])
268
+ #(DS,[next],(
269
+ #(EQ,<name>,#(.),,(
270
+ #(DS,[name],<name>)
271
+ #(EQ,#(IN,[name],prefix,#(.)),,(
272
+ #(CR,[name])
273
+ ##([delimiter])#([name])
274
+ #(DS,[delimiter],(<delimiter>))
275
+ ))
276
+ #([next],#(CS,[names],#(.)))
277
+ ))
278
+ ))
279
+ #(SS,[next],<name>)
280
+ #([next],#(CS,[names],#(.)))
281
+ #(DD,[next],[names],[name],[delimiter])
282
+ ))
283
+ #(sss,list-prefix,(prefix,<delimiter>))'
284
+
285
+
286
+ Get Segment By Index
287
+ --------------------
288
+
289
+ Returns a segment of a form by the one-based index of it. If the index is out
290
+ of range (below one or above the number of segments in the form), the default
291
+ is returned.
292
+
293
+ #(DS,segment,(
294
+ #(DS,[seg],(
295
+ #(EQ,(value),#(.),(default),(
296
+ #(GR,2,count,#(CR,form)(value),(
297
+ #([seg],#(SU,count,1),##(CS,form,#(.)))
298
+ ))
299
+ ))
300
+ ))
301
+ #(SS,[seg],count,value)
302
+ #(GR,1,index,(default),(
303
+ #([seg],index,#(CS,form,#(.)))#(CR,form)
304
+ ))
305
+ ))
306
+ #(sss,segment,(index,form,default))'
307
+
308
+
309
+ Logic - And, Or and Not
310
+ -----------------------
311
+
312
+ These work by passing partial function calls. For example, to test if a number
313
+ is between -1 and 1 you would do:
314
+ (
315
+ #(and,(GR,a,-1),(GR,1,a),between,not-between)
316
+ )
317
+ Any test that returns either a true or false value can be used, both built-in
318
+ tests and any user-defined tests as well. These can be nested if necessary,
319
+ although that can become unreadable very quickly. For example, test if "b" is
320
+ in the interval ]-1,1[ or the interval ]2,3[:
321
+ (
322
+ #(or,(and,(GR,b,-1),(GR,1,b)),(and,(GR,b,2),(GR,3,b)),true,false)
323
+ )
324
+ Both "and" and "or" are short-circuited, in other words, if the first test
325
+ determines what the result is, the second test is not executed.
326
+
327
+ #(DS,and,(
328
+ #(EQ,#(test1,T,F),T,(
329
+ #(EQ,#(test2,T,F),T,(true),(false))
330
+ ),(false))
331
+ ))
332
+ #(sss,and,(test1,test2,true,false))'
333
+
334
+ #(DS,or,(
335
+ #(EQ,#(test1,T,F),T,(true),(
336
+ #(EQ,#(test2,T,F),T,(true),(false))
337
+ ))
338
+ ))
339
+ #(sss,or,(test1,test2,true,false))'
340
+
341
+ And here's the implementation of not. Just pass it a partial test, same as you
342
+ do for "and" and "or".
343
+
344
+ #(DS,not,(#(test,(F),(T))))
345
+ #(SS,not,test,T,F)'
346
+
347
+
348
+ #(PS,(success!
349
+ ))'
350
+
351
+
352
+ Load Other Files
353
+ ----------------
354
+
355
+ #(DS,term,term.trl)
356
+ #(FB,term)'
357
+ #(DS,math,math.trl)
358
+ #(FB,math)'
359
+ #(DS,meta,meta.trl)
360
+ #(FB,meta)'
361
+ #(DS,ratio,ratio.trl)
362
+ #(FB,ratio)'
363
+ #(DS,struct,struct.trl)
364
+ #(FB,struct)'
365
+ #(DS,list,list.trl)
366
+ #(FB,list)'