| 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 |     LiteralBlock Func
 | 
| 12 |     NameType
 | 
| 13 |     EggexFlag
 | 
| 14 |   }
 | 
| 15 | 
 | 
| 16 |   use core runtime {
 | 
| 17 |     Cell
 | 
| 18 |   }
 | 
| 19 | 
 | 
| 20 |   IntBox = (int i)
 | 
| 21 | 
 | 
| 22 |   ProcDefaults = (
 | 
| 23 |     List[value]? for_word,  # all of them are value.Str
 | 
| 24 |     List[value]? for_typed,
 | 
| 25 |     Dict[str, value]? for_named,
 | 
| 26 |     value? for_block,
 | 
| 27 |   )
 | 
| 28 | 
 | 
| 29 |   LeftName = (str name, loc blame_loc)
 | 
| 30 | 
 | 
| 31 |   # for setvar, and value.Place
 | 
| 32 |   y_lvalue = 
 | 
| 33 |     # e.g. read (&x)
 | 
| 34 |     Local %LeftName
 | 
| 35 |     # e.g. &a[0][1].key -- we evaluate a[0][1] first
 | 
| 36 |   | Container(value obj, value index)
 | 
| 37 | 
 | 
| 38 |   # An sh_lvalue is for things mutation that happen with dynamic scope
 | 
| 39 |   #
 | 
| 40 |   # - sh_expr_eval uses this for unset / printf -v
 | 
| 41 |   # - word_eval uses this for ${a[0]=}
 | 
| 42 |   # - expr_eval / cmd_eval use this for setvar a[i] = 42
 | 
| 43 |   sh_lvalue = 
 | 
| 44 |     Var %LeftName
 | 
| 45 |   | Indexed(str name, int index, loc blame_loc)
 | 
| 46 |   | Keyed(str name, str key, loc blame_loc)
 | 
| 47 | 
 | 
| 48 |   eggex_ops =
 | 
| 49 |     # for BASH_REMATCH or ~ with a string
 | 
| 50 |     No
 | 
| 51 |     # These lists are indexed by group number, and will have None entries
 | 
| 52 |   | Yes(List[value?] convert_funcs, List[Token?] convert_toks,
 | 
| 53 |         List[str?] capture_names)
 | 
| 54 | 
 | 
| 55 |   RegexMatch = (str s, List[int] indices, eggex_ops ops)
 | 
| 56 | 
 | 
| 57 |   regex_match = 
 | 
| 58 |     No
 | 
| 59 |   | Yes %RegexMatch
 | 
| 60 | 
 | 
| 61 |   # Commands, words, and expressions from syntax.asdl are evaluated to a VALUE.
 | 
| 62 |   # value_t instances are stored in state.Mem().
 | 
| 63 |   value =
 | 
| 64 |     # Only used for val_ops.StdinIterator.  (It would be nice if we could
 | 
| 65 |     # express iter_value.{Eof,Interrupted,Str,Int,...} in ASDL)
 | 
| 66 |     Interrupted
 | 
| 67 |   | Stdin
 | 
| 68 | 
 | 
| 69 |     # Methods on state.Mem return value.Undef, but it's not visible in YSH.
 | 
| 70 |     #
 | 
| 71 |     # A var bound to Undef is different than no binding because of dynamic
 | 
| 72 |     # scope.  Undef can shadow values lower on the stack.
 | 
| 73 |   | Undef
 | 
| 74 | 
 | 
| 75 |   | Str(str s)
 | 
| 76 | 
 | 
| 77 |     # "holes" in the array are represented by None
 | 
| 78 |   | BashArray(List[str] strs)
 | 
| 79 |     # TODO: Switch to this more efficient representation?
 | 
| 80 |     # max_index makes append-sparse workload faster, and normal append loops too
 | 
| 81 |   | SparseArray(Dict[BigInt, str] d, BigInt max_index)
 | 
| 82 | 
 | 
| 83 |   | BashAssoc(Dict[str, str] d)
 | 
| 84 | 
 | 
| 85 |     # DATA model for YSH follows JSON.  Note: YSH doesn't have 'undefined' and
 | 
| 86 |     # 'null' like JavaScript, just 'null'.
 | 
| 87 |   | Null
 | 
| 88 |   | Bool(bool b)
 | 
| 89 |   | Int(BigInt i)
 | 
| 90 |   #| Int(int i)
 | 
| 91 |   | Float(float f)
 | 
| 92 |   | List(List[value] items)
 | 
| 93 |   | Dict(Dict[str, value] d)
 | 
| 94 | 
 | 
| 95 |   # CODE types
 | 
| 96 |   #   unevaluated: Eggex, Expr, Template, Command/Block
 | 
| 97 |   #   callable, in separate namespaces: Func, BoundFunc, Proc
 | 
| 98 | 
 | 
| 99 |     # expr is spliced
 | 
| 100 |     # / d+; ignorecase / -> '[[:digit:]]+' REG_ICASE
 | 
| 101 |   | Eggex(re spliced, str canonical_flags,
 | 
| 102 |           List[value?] convert_funcs, List[Token?] convert_toks,
 | 
| 103 |           # str? is because some groups are not named
 | 
| 104 |           str? as_ere, List[str?] capture_names)
 | 
| 105 | 
 | 
| 106 |     # The indices list has 2 * (num_group + 1) entries.  Group 0 is the whole
 | 
| 107 |     # match, and each group has both a start and end index.
 | 
| 108 |     # It's flat to reduce allocations.  The group() start() end() funcs/methods
 | 
| 109 |     # provide a nice interface.
 | 
| 110 |   | Match %RegexMatch
 | 
| 111 | 
 | 
| 112 |     # ^[42 + a[i]]
 | 
| 113 |   | Expr(expr e)
 | 
| 114 | 
 | 
| 115 |     # ^(echo 1; echo 2) and cd { echo 1; echo 2 } 
 | 
| 116 |   | Command(command c)
 | 
| 117 | 
 | 
| 118 |     # for Hay to get the backing lines
 | 
| 119 |     # TODO: Consolidate value.Command and value.LiteralBlock.  All Command
 | 
| 120 |     # instance should have backing lines.
 | 
| 121 | 
 | 
| 122 |     # TODO: ASDL doesn't support shared variant across module
 | 
| 123 |     # This would be more efficient
 | 
| 124 |   # | LiteralBlock %LiteralBlock
 | 
| 125 |   | Block(LiteralBlock block)
 | 
| 126 | 
 | 
| 127 |     # A place has an additional stack frame where the value is evaluated.
 | 
| 128 |     # The frame MUST be lower on the stack at the time of use.
 | 
| 129 |   | Place(y_lvalue lval, Dict[str, Cell] frame)
 | 
| 130 | 
 | 
| 131 |     # for Flags/flag and Flags/arg?
 | 
| 132 |     # for json read/write ?
 | 
| 133 |     # Possibly unify Hay and modules/namespaces
 | 
| 134 |   | Module(Dict[str, value] defs)
 | 
| 135 | 
 | 
| 136 |     # The ability to use operating system functions.  Right now some functions
 | 
| 137 |     # leak, like glob().
 | 
| 138 |   | IO(any cmd_ev, any prompt_ev)
 | 
| 139 | 
 | 
| 140 |     # Do we need this?
 | 
| 141 |     # _guts->heapId() can be used to detect object cycles.
 | 
| 142 |     # It's considered impure; it depends on VM implementation details.  The =
 | 
| 143 |     # operator and 'pp value' also print the heap ID.
 | 
| 144 |   | Guts(any vm)
 | 
| 145 | 
 | 
| 146 |     # callable is vm._Callable.
 | 
| 147 |     # TODO: ASDL needs some kind of "extern" to declare vm._Callable and
 | 
| 148 |     # cmd_eval.CommandEvaluator.  I think it would just generate a forward
 | 
| 149 |     # declaration.
 | 
| 150 |   | BuiltinFunc(any callable)
 | 
| 151 |   | BoundFunc(value me, value func)
 | 
| 152 | 
 | 
| 153 |     # command.ShFunction and command.Proc evaluate to value.Proc
 | 
| 154 |     # They each have name, name_tok, and body.
 | 
| 155 |     #
 | 
| 156 |     # YSH procs disable dynamic scope, have default args to evaluate, and
 | 
| 157 |     # different @ARGV.
 | 
| 158 | 
 | 
| 159 |   | Proc(str name, Token name_tok, proc_sig sig, command body,
 | 
| 160 |          ProcDefaults? defaults, bool sh_compat)
 | 
| 161 | 
 | 
| 162 |     # module may be a frame where defined
 | 
| 163 |   | Func(str name, Func parsed,
 | 
| 164 |          List[value] pos_defaults, Dict[str, value] named_defaults,
 | 
| 165 |          Dict[str, Cell]? module_)
 | 
| 166 | 
 | 
| 167 |     # a[3:5] a[:10] a[3:] a[:]  # both ends are optional
 | 
| 168 |   | Slice(IntBox? lower, IntBox? upper)
 | 
| 169 | 
 | 
| 170 |     # for i in (1:n) { echo $i }  # both ends are required
 | 
| 171 |   | Range(int lower, int upper)
 | 
| 172 | }
 | 
| 173 | 
 | 
| 174 | # vim: sw=2
 | 
| 175 | 
 |