1 # args.ysh
2 #
3 # Usage:
4 # source --builtin args.sh
5 #
6 # Args :spec {
7 # flag -v --verbose "Verbosely" # default is Bool, false
8 #
9 # flag -P --max-procs '''
10 # Run at most P processes at a time
11 # ''' (Int, default=-1)
12 #
13 # flag -i --invert '''
14 # Long multiline
15 # Description
16 # ''' (Bool, default = true)
17 #
18 # arg src 'Source'
19 # arg src 'Dest'
20 # arg times 'Foo' (Int)
21 # }
22 #
23 # var opt, i = parseArgs(spec, ARGV)
24 #
25 # echo "Verbose $[opt.verbose]"
26
27
28 # TODO: how to register these as Args ?
29 #
30 # var proc_bindings = {}
31 # var var_bindings = {}
32 # eval ()
33
34
35 # How to make this private to a file? Or is redefine_func_proc enough?
36 #
37 # Also it would be nice if we can setref a variable?
38
39 proc __flag (...strs ; type ; default Any = null) {
40
41 var short = ''
42 var long = ''
43 if (strs[0].startsWith('-')) {
44 setvar short = strs[0]
45 }
46
47 case (len(strs)) {
48 (1) {
49 echo
50 }
51 (2) {
52 echo
53 }
54 }
55
56 var result = {short, long, type, default}
57
58 # TODO:
59 # - need :: because vars start with _
60 # - It would be nice if _this was a magic param?
61 # - it would be nice if 'flag' was a "method" on something?
62 # - that's what it's doing, it's mutating "self"
63 # - _this is the thing we're currently creating
64
65 _ _this.flags->append(result)
66
67 var this = getvar('_this', scope='dynamic')
68 _ this.flags->append(result)
69 }
70
71 proc __arg (name, desc ; type ; default Any = null) {
72 # Type is always string? Or support conversion?
73 # I guess there's no reason not to
74 #
75 # Int or Float
76
77 echo 'arg'
78 }
79
80 # TODO: create a builtin?
81 func getProc(x) {
82 return (x)
83 }
84 # TODO: builtin?
85 # Is this different than shvar? How?
86 # Is it a global or a local?
87
88 # Maybe we can rename shvar IFS=: (foo={}) { }
89 #
90 # - shvar does LocalOnly
91 # - but 'proc arg' will push a new stack frame?
92 # - so we need something like setref?
93 #
94
95 proc bind-vars (; ; ...bindings; block) {
96 echo
97 }
98
99 hay define Documented
100
101 Documented { # Do we inherit the name of the proc? Or $path/$procName?
102
103 # Do we want a longer way of documenting APIs?
104 # Document every argument?
105 # I like Go's docs
106 desc = '''
107 These are my docs
108 '''
109
110 proc p {
111 echo
112 }
113
114 }
115
116 proc Args(spec Ref ; ; ; block) {
117
118 var more_procs = {
119 flag: getProc('__flag'),
120 arg: getProc('__arg'),
121 }
122
123 var this = {}
124
125 # _this is part of this frame -- it's a duplicate that callers can look up I
126 # guess
127 # Well then all you need is getvar() ? You don't even need bind-vars?
128 bind-vars (_this=this) {
129 # So now 'arg' and 'flag' can see _this?
130
131 # TODO: more_procs vs. replace procs?
132 eval (block, procs=more_procs)
133 }
134 = this
135
136 # You have to put 'flag' and 'arg' in scope
137
138 # Flags have these fields
139 # default type is Bool
140 var flag = {short: '', long: '', type: null, default: '', help: ''}
141
142 # Args have these fields
143 #
144 # I think all args are required -- you can ARGV[i:] if you want something else
145 #
146 # Default type is string
147 var arg = {name: '', type: null, help: ''}
148
149 # May also have program name, etc.
150 var result = {flags: [], args: []}
151
152 #= spec
153 #= block
154
155 setref spec = result
156 }
157
158 func parseArgs(spec, argv) {
159 var i = 0
160 var arg = {}
161
162 return ([arg, i])
163 }