1 | # Runtime value
|
2 |
|
3 | module value
|
4 | {
|
5 | # import from frontend/syntax.asdl
|
6 | use frontend syntax {
|
7 | loc Token
|
8 | expr command
|
9 | DoubleQuoted
|
10 | re proc_sig
|
11 | Func
|
12 | NameType
|
13 | EggexFlag
|
14 | BraceGroup SourceLine
|
15 | }
|
16 |
|
17 | use core runtime {
|
18 | Cell
|
19 | }
|
20 |
|
21 | IntBox = (int i)
|
22 |
|
23 | ProcDefaults = (
|
24 | List[value]? for_word, # all of them are value.Str
|
25 | List[value]? for_typed,
|
26 | Dict[str, value]? for_named,
|
27 | value? for_block,
|
28 | )
|
29 |
|
30 | LeftName = (str name, loc blame_loc)
|
31 |
|
32 | # for setvar, and value.Place
|
33 | y_lvalue =
|
34 | # e.g. read (&x)
|
35 | Local %LeftName
|
36 | # e.g. &a[0][1].key -- we evaluate a[0][1] first
|
37 | | Container(value obj, value index)
|
38 |
|
39 | # An sh_lvalue is for things mutation that happen with dynamic scope
|
40 | #
|
41 | # - sh_expr_eval uses this for unset / printf -v
|
42 | # - word_eval uses this for ${a[0]=}
|
43 | # - expr_eval / cmd_eval use this for setvar a[i] = 42
|
44 | sh_lvalue =
|
45 | Var %LeftName
|
46 | | Indexed(str name, int index, loc blame_loc)
|
47 | | Keyed(str name, str key, loc blame_loc)
|
48 |
|
49 | eggex_ops =
|
50 | # for BASH_REMATCH or ~ with a string
|
51 | No
|
52 | # These lists are indexed by group number, and will have None entries
|
53 | | Yes(List[value?] convert_funcs, List[Token?] convert_toks,
|
54 | List[str?] capture_names)
|
55 |
|
56 | RegexMatch = (str s, List[int] indices, eggex_ops ops)
|
57 |
|
58 | regex_match =
|
59 | No
|
60 | | Yes %RegexMatch
|
61 |
|
62 | # Retain references to lines
|
63 | LiteralBlock = (BraceGroup brace_group, List[SourceLine] lines)
|
64 |
|
65 | cmd_frag =
|
66 | LiteralBlock %LiteralBlock # p { echo hi } has backing lines
|
67 | | Expr(command c) # var b = ^(echo hi)
|
68 |
|
69 | # Arbitrary objects, where attributes are looked up on the prototype chain.
|
70 | Obj = (Obj? prototype, Dict[str, value] d)
|
71 |
|
72 | # Commands, words, and expressions from syntax.asdl are evaluated to a VALUE.
|
73 | # value_t instances are stored in state.Mem().
|
74 | value =
|
75 | #
|
76 | # Implementation details
|
77 | #
|
78 |
|
79 | # Only used for io.stdin aka val_ops.StdinIterator. (It would be nice if
|
80 | # we could express iter_value.{Eof,Interrupted,Str,Int,...} in ASDL)
|
81 | Interrupted
|
82 | | Stdin
|
83 | # Can't be instantiated by users
|
84 | # a[3:5] a[:10] a[3:] a[:] # both ends are optional
|
85 | | Slice(IntBox? lower, IntBox? upper)
|
86 |
|
87 | #
|
88 | # OSH/Bash types
|
89 | #
|
90 |
|
91 | # Methods on state::Mem return value.Undef, but it's not visible in YSH.
|
92 | # Note: A var bound to Undef is different than no binding because of
|
93 | # dynamic scope. Undef can shadow values lower on the stack.
|
94 | | Undef
|
95 |
|
96 | | Str(str s)
|
97 |
|
98 | # "holes" in the array are represented by None
|
99 | | BashArray(List[str] strs)
|
100 | # TODO: Switch to this more efficient representation. max_index makes
|
101 | # append-sparse workload faster, and normal append loops too
|
102 | | SparseArray(Dict[BigInt, str] d, BigInt max_index)
|
103 |
|
104 | | BashAssoc(Dict[str, str] d)
|
105 |
|
106 | # The DATA model for YSH follows JSON. Note: YSH doesn't have 'undefined'
|
107 | # and 'null' like JavaScript, just 'null'.
|
108 | | Null
|
109 | | Bool(bool b)
|
110 | | Int(BigInt i)
|
111 | | Float(float f)
|
112 | | List(List[value] items)
|
113 | | Dict(Dict[str, value] d)
|
114 |
|
115 | # Possible types
|
116 | # value.Htm8 - a string that can be queried, with lazily materialized "views"
|
117 | # value.Tsv8 - ditto
|
118 | # value.Json8 - some kind of jq or JSONPath query language
|
119 |
|
120 | # Objects are for for polymorphism
|
121 | | Obj %Obj
|
122 |
|
123 | # for i in (0 .. n) { echo $i } # both ends are required
|
124 | # TODO: BigInt
|
125 | | Range(int lower, int upper)
|
126 |
|
127 | # expr is spliced
|
128 | # / d+; ignorecase / -> '[[:digit:]]+' REG_ICASE
|
129 | | Eggex(re spliced, str canonical_flags,
|
130 | List[value?] convert_funcs, List[Token?] convert_toks,
|
131 | # str? is because some groups are not named
|
132 | str? as_ere, List[str?] capture_names)
|
133 |
|
134 | # The indices list has 2 * (num_group + 1) entries. Group 0 is the whole
|
135 | # match, and each group has both a start and end index.
|
136 | # It's flat to reduce allocations. The group() start() end() funcs/methods
|
137 | # provide a nice interface.
|
138 | | Match %RegexMatch
|
139 |
|
140 | # A place has an additional stack frame where the value is evaluated.
|
141 | # The frame MUST be lower on the stack at the time of use.
|
142 | | Place(y_lvalue lval, Dict[str, Cell] frame)
|
143 |
|
144 | # for io->evalToDict(), which uses ctx_FrontFrame(), which is distinct from
|
145 | # ctx_Eval()
|
146 | # TODO: ASDL should let us "collapse" this Dict directly into value_t
|
147 | | Frame(Dict[str, Cell] frame)
|
148 |
|
149 | #
|
150 | # Code units: BoundFunc, BuiltinFunc, Func, BuiltinProc, Proc
|
151 | #
|
152 |
|
153 | # for obj.method and obj->mutatingMethod
|
154 | | BoundFunc(value me, value func)
|
155 | # callable is vm._Callable.
|
156 | # TODO: ASDL needs some kind of "extern" to declare vm._Callable,
|
157 | # vm._Builtin. I think it would just generate a forward declaration.
|
158 | | BuiltinFunc(any callable)
|
159 |
|
160 | | Func(str name, Func parsed,
|
161 | List[value] pos_defaults, Dict[str, value] named_defaults,
|
162 | # module is where "global" lookups happen
|
163 | Dict[str, Cell] module_frame)
|
164 |
|
165 | # command.ShFunction and command.Proc evaluate to value.Proc
|
166 | # They each have name, name_tok, and body.
|
167 | #
|
168 | # YSH procs disable dynamic scope, have default args to evaluate, and
|
169 | # different @ARGV.
|
170 |
|
171 | # builtin is vm._Builtin, this can be introspected
|
172 | | BuiltinProc(any builtin)
|
173 | | Proc(str name, Token name_tok, proc_sig sig, command body,
|
174 | ProcDefaults? defaults, bool sh_compat,
|
175 | # module is where "global" lookups happen
|
176 | Dict[str, Cell] module_frame)
|
177 |
|
178 | #
|
179 | # Unevaluated CODE types: ExprFrag, Expr, CommandFrag, Command
|
180 | #
|
181 |
|
182 | # This can be the output of parseExpr()?
|
183 | #| ExprFrag(expr e)
|
184 |
|
185 | # var x = ^[42 + a[i]]
|
186 | # my-ls | where [size > 10]
|
187 | | Expr(expr e,
|
188 | Dict[str, Cell] captured_frame,
|
189 | Dict[str, Cell] module_frame)
|
190 |
|
191 | # This is an UNBOUND command, like
|
192 | # ^(echo 1; echo 2) and cd { echo 1; echo 2 }
|
193 | | CommandFrag(command c)
|
194 |
|
195 | # Bound command
|
196 | | Command(cmd_frag frag,
|
197 | Dict[str, Cell] captured_frame,
|
198 | Dict[str, Cell] module_frame)
|
199 |
|
200 | # Other introspection
|
201 | # __builtins__ - Dict[str, value_t] - I would like to make this read-only
|
202 | # __modules__ - Dict[str, Obj] - read-only to prevent non-Obj
|
203 | # __sh_funcs__ - Dict[str, value.Proc] - read-only to prevent non-Proc
|
204 | # __traps__ - Dict[str, command_t] ?
|
205 | # __builtin_procs__ - Dict[str, BuiltinProc] - builtin commands - special
|
206 | # and non-special? and assignment?
|
207 | # __aliases__ - Dict[str, str]
|
208 | # __jobs__ - maybe nicer that jobs -p
|
209 | # __stack__ - replaces pp stacks_, frame_vars_
|
210 | #
|
211 | # More:
|
212 | # - dir stack pushd/popd - read-only variable
|
213 | # - there is a hidden mem.pwd, in addition to $PWD
|
214 | # - completion hooks and spec
|
215 | # - getopts state
|
216 | # - command cache - hash builtin
|
217 | }
|
218 |
|
219 | # vim: sw=2
|
220 |
|