Read Write eXecute framework
rwx.rwx.work
1# ╭──────╮
2# │ code │
3# ╰──────╯
4
5# ╭──────┬───────────╮
6# │ code │ functions │
7# ╰──────┴───────────╯
8
9function alias_eval(new, name, type) {
10 text = new "() { "
11 if (type == "function") {
12 text = text name " \"${@}\""
13 } else if (type == "variable") {
14 text = text "echo \"${" name "}\""
15 }
16 return text "; }"
17}
18
19# TODO delete when useless
20function extract(string, type) {
21 if (type == "alias") {
22 split(string, array, "#=")
23 return strip(array[2])
24 } else if (type == "command") {
25 split(string, array, "#/")
26 return strip(array[2])
27 } else if (type == "doc") {
28 split(string, array, "#")
29 return strip(array[2])
30 } else if (type == "function") {
31 split(string, array, "(")
32 return strip(array[1])
33 } else if (type == "module") {
34 split(string, array, "#\\.")
35 return strip(array[2])
36 } else if (type == "shebang") {
37 split(string, array, "#!")
38 return strip(array[2])
39 } else if ((type == "constant") || (type == "variable")) {
40 split(string, array, "=")
41 return strip(array[1])
42 }
43}
44
45# ╭──────┬───────────┬─────╮
46# │ code │ functions │ doc │
47# ╰──────┴───────────┴─────╯
48
49function doc_append(string) {
50 if (doc) {
51 doc = doc "\n"
52 }
53 doc = doc string
54}
55
56function doc_output(name, type) {
57 print "↙ " type
58 print name
59 print doc
60 exit
61}
62
63function doc_reset() {
64 if (current_function == "") {
65 doc = ""
66 }
67}
68
69# ╭──────┬───────────┬─────╮
70# │ code │ functions │ ids │
71# ╰──────┴───────────┴─────╯
72
73function ids_get(type) {
74 return ids[type]
75}
76
77function ids_put(type, name) {
78 if (ids[type]) {
79 ids[type] = ids[type] "\n"
80 }
81 ids[type] = ids[type] name
82}
83
84# ╭──────┬───────────┬───────╮
85# │ code │ functions │ strip │
86# ╰──────┴───────────┴───────╯
87
88function strip(string, tmp) {
89 tmp = string
90 sub("^[\t ]*", "", tmp)
91 sub("[\t ]*$", "", tmp)
92 return tmp
93}
94
95function strip_first(string, sep, tmp) {
96 tmp = string
97 sub(sep, "", tmp)
98 return strip(tmp)
99}
100
101function strip_from(string, sep, tmp) {
102 split(string, tmp, sep)
103 return strip(tmp[1])
104}
105
106function strip_function(string) {
107 return strip_from(string, "(")
108}
109
110function strip_task(string) {
111 return strip_from(strip_first(string, "#"), " ")
112}
113
114function strip_value(string) {
115 return strip_from(string, "=")
116}
117
118# ╭──────┬───────╮
119# │ code │ begin │
120# ╰──────┴───────╯
121
122BEGIN {
123
124# ╭──────┬───────┬───────────╮
125# │ code │ begin │ constants │
126# ╰──────┴───────┴───────────╯
127
128 RECORD_SEPARATOR = "\036"
129 UNIT_SEPARATOR = "\037"
130
131# ╭──────┬───────┬───────────┬───────╮
132# │ code │ begin │ constants │ regex │
133# ╰──────┴───────┴───────────┴───────╯
134
135 RE_ANY = "(.*)"
136 RE_BEGIN = "^"
137 RE_CONST = "([_A-Z][_0-9A-Z]*)"
138 RE_SET = "=.*"
139 RE_SPACE = "[[:space:]]"
140 RE_TSK = "(FIXME|TODO)"
141 RE_VAR = "([_a-z][_0-9a-z]*)"
142
143 RE_SPACES = RE_SPACE "*"
144
145 RE_END = RE_SPACES "$"
146 RE_FUNC = RE_SPACES "\\(" RE_SPACES "\\)" RE_SPACES
147
148 re["alias"] = RE_BEGIN "#=" RE_SPACES RE_VAR RE_END
149 re["binary"] = RE_BEGIN "#\\|" RE_SPACES RE_VAR RE_END
150 RE_CLOSE = RE_BEGIN RE_ANY "}" RE_SPACES RE_END
151 re["command"] = RE_BEGIN "#/" RE_SPACES RE_VAR RE_END
152 RE_COMMENT = RE_BEGIN RE_SPACES "#" RE_ANY RE_END
153 re["constant"] = RE_BEGIN RE_CONST RE_SET RE_END
154 RE_DOC = RE_BEGIN RE_SPACES "# " RE_ANY RE_END
155 re["function"] = RE_BEGIN RE_VAR RE_FUNC RE_ANY RE_END
156 RE_MODULE = RE_BEGIN "#\\." RE_SPACES RE_ANY RE_END
157 RE_SHEBANG = RE_BEGIN "#!" RE_SPACES RE_ANY RE_END
158 RE_TASK = RE_BEGIN RE_SPACES "#" RE_SPACES RE_TSK RE_ANY RE_END
159 re["variable"] = RE_BEGIN RE_VAR RE_SET RE_END
160
161# ╭──────┬───────┬───────────╮
162# │ code │ begin │ variables │
163# ╰──────┴───────┴───────────╯
164
165 current_function = ""
166 current_match = ""
167 doc = ""
168 line = 0
169 lint = ""
170 module = ""
171
172# begin
173}
174
175# ╭──────┬───────╮
176# │ code │ parse │
177# ╰──────┴───────╯
178
179function parse(string, name) {
180
181 # module
182 if (match(string, RE_MODULE)) {
183 current_match = "module"
184 line = 0
185 module = strip_first(string, "#\\.")
186 doc_reset()
187 shebang = ""
188
189 # shebang
190 } else if (match(string, RE_SHEBANG)) {
191 current_match = "shebang"
192 shebang = strip_first(string, "#!")
193
194 # constant
195 } else if (match(string, re["constant"])) {
196 current_match = "constant"
197 constant = strip_value(string)
198 ids_put(current_match, constant)
199
200 # variable
201 } else if (match(string, re["variable"])) {
202 current_match = "variable"
203 variable = strip_value(string)
204 ids_put(current_match, variable)
205
206 # alias
207 } else if (match(string, re["alias"])) {
208 current_match = "alias"
209 current_alias = strip_first(string, "#=")
210 ids_put(current_match, current_alias)
211 current_aliases[current_alias] = ""
212 doc_append("= " current_alias)
213
214 # command
215 } else if (match(string, re["command"])) {
216 current_match = "command"
217 current_command = strip_first(string, "#/")
218 ids_put(current_match, current_command)
219 current_commands[current_command] = ""
220 doc_append("/ " current_command)
221
222 # function
223 } else if (match(string, re["function"])) {
224 current_match = "function"
225 current_function = strip_function(string)
226 ids_put(current_match, current_function)
227 for (name in current_aliases) {
228 aliases[name] = current_function
229 }
230 delete current_aliases
231 for (name in current_commands) {
232 commands[name] = current_function
233 }
234 delete current_commands
235
236 # task
237 } else if (match(string, RE_TASK)) {
238 current_match = "task"
239 task = strip_task(string)
240 tasks[task] = ""
241 doc_append(line " " string)
242
243 # doc
244 } else if (match(string, RE_DOC)) {
245 current_match = "doc"
246 doc_append(strip_first(string, "# "))
247
248 # comment
249 } else if (match(string, RE_COMMENT)) {
250 current_match = "comment"
251 doc_append(string)
252
253 # other
254 } else {
255 current_match = ""
256 if (target) {
257 if (module == target) {
258 doc_output(target, "module")
259 }
260 }
261 doc_reset()
262
263 # match
264 }
265
266 # close
267 if (match(string, RE_CLOSE)) {
268 current_match = "close"
269 }
270
271}
272
273# ╭──────┬──────╮
274# │ code │ main │
275# ╰──────┴──────╯
276
277{
278
279# ╭──────┬──────┬───────╮
280# │ code │ main │ parse │
281# ╰──────┴──────┴───────╯
282
283parse($0)
284
285# ╭──────┬──────┬──────╮
286# │ code │ main │ exit │
287# ╰──────┴──────┴──────╯
288
289# doc
290if (action == "doc") {
291
292 # constant
293 if (current_match == "constant") {
294 if (constant == target) {
295 doc_output(constant, "constant")
296 }
297
298 # variable
299 } else if (current_match == "variable") {
300 if (variable == target) {
301 doc_output(variable, "variable")
302 }
303
304 # match
305 }
306
307 # function
308 if (current_match == "close") {
309 if (target == current_function) {
310 doc_output(current_function, "function")
311 } else if (target in aliases) {
312 print "= " target
313 doc_output(current_function, "function")
314 } else if (target in commands) {
315 print "/ " target
316 doc_output(current_function, "function")
317 }
318 }
319
320# tasks
321} else if (action == "tasks") {
322
323 # module
324 if (current_match == "module") {
325 if (output_tasks) {
326 print ""
327 print ". " module
328 print output_tasks
329 output_tasks = ""
330 }
331 doc = ""
332 match_task = 0
333
334 # task
335 } else if (current_match == "task") {
336 if (target) {
337 if (target in tasks) {
338 match_task = 1
339 }
340 } else {
341 match_task = 1
342 }
343
344 # other
345 } else {
346 if (match_task) {
347 output_tasks = output_tasks "\n" doc
348 }
349 doc = ""
350 match_task = 0
351
352 # match
353 }
354
355# function
356} else if (action == "function") {
357
358 if (current_match == "function") {
359 if (target in commands) {
360 print commands[target]
361 exit
362 }
363 }
364
365# lint
366} else if (action == "lint") {
367
368 # TODO RWX_ constant
369 # TODO rwx_ variable
370 # TODO rwx_ function
371
372 # TODO unique alias
373 if (current_match == "alias") {
374 if (alias in aliases) {
375 print "dupe: " alias
376 }
377 }
378 # TODO unique command
379 # TODO unique function
380
381# eval
382} else if (action == "eval") {
383
384# filter
385} else if (action == "filter") {
386
387# unknown
388} else {
389 print "unknown action: " action
390 exit 1
391
392# action
393}
394
395# ╭──────┬──────┬──────╮
396# │ code │ main │ next │
397# ╰──────┴──────┴──────╯
398
399 # constant
400 if (current_match == "constant") {
401 doc_reset()
402 constant = ""
403
404 # variable
405 } else if (current_match == "variable") {
406 doc_reset()
407 variable = ""
408
409 # alias
410 } else if (current_match == "alias") {
411 current_alias = ""
412
413 # command
414 } else if (current_match == "command") {
415 current_command = ""
416
417 # task
418 } else if (current_match == "task") {
419 task = ""
420
421 # close
422 } else if (current_match == "close") {
423 doc_reset()
424 current_function = ""
425
426 # match
427 }
428
429 # next
430 line++
431
432# main
433}
434
435# ╭──────┬─────╮
436# │ code │ end │
437# ╰──────┴─────╯
438
439END {
440
441 # eval
442 if (action == "eval") {
443 if (target == "alias") {
444 for (eval in aliases) {
445 print alias_eval(eval, aliases[eval], "function")
446 }
447 } else if (target == "command") {
448 for (eval in commands) {
449 print alias_eval(eval, commands[eval], "function")
450 }
451 }
452
453 # filter
454 } else if (action == "filter") {
455 print ids_get(target)
456
457 # lint
458 } else if (action == "lint") {
459 print lint
460
461 # action
462 }
463
464# end
465}