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