| 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 |  | 
| 68 | # Methods on state.Mem return value.Undef, but it's not visible in YSH. | 
| 69 | # | 
| 70 | # A var bound to Undef is different than no binding because of dynamic | 
| 71 | # scope.  Undef can shadow values lower on the stack. | 
| 72 | | Undef | 
| 73 |  | 
| 74 | | Str(str s) | 
| 75 |  | 
| 76 | # "holes" in the array are represented by None | 
| 77 | | BashArray(List[str] strs) | 
| 78 | # TODO: Switch to this more efficient representation? | 
| 79 | # max_index makes append-sparse workload faster, and normal append loops too | 
| 80 | | SparseArray(Dict[BigInt, str] d, BigInt max_index) | 
| 81 |  | 
| 82 | | BashAssoc(Dict[str, str] d) | 
| 83 |  | 
| 84 | # DATA model for YSH follows JSON.  Note: YSH doesn't have 'undefined' and | 
| 85 | # 'null' like JavaScript, just 'null'. | 
| 86 | | Null | 
| 87 | | Bool(bool b) | 
| 88 | | Int(BigInt i) | 
| 89 | #| Int(int i) | 
| 90 | | Float(float f) | 
| 91 | | List(List[value] items) | 
| 92 | | Dict(Dict[str, value] d) | 
| 93 |  | 
| 94 | # CODE types | 
| 95 | #   unevaluated: Eggex, Expr, Template, Command/Block | 
| 96 | #   callable, in separate namespaces: Func, BoundFunc, Proc | 
| 97 |  | 
| 98 | # expr is spliced | 
| 99 | # / d+; ignorecase / -> '[[:digit:]]+' REG_ICASE | 
| 100 | | Eggex(re spliced, str canonical_flags, | 
| 101 | List[value?] convert_funcs, List[Token?] convert_toks, | 
| 102 | # str? is because some groups are not named | 
| 103 | str? as_ere, List[str?] capture_names) | 
| 104 |  | 
| 105 | # The indices list has 2 * (num_group + 1) entries.  Group 0 is the whole | 
| 106 | # match, and each group has both a start and end index. | 
| 107 | # It's flat to reduce allocations.  The group() start() end() funcs/methods | 
| 108 | # provide a nice interface. | 
| 109 | | Match %RegexMatch | 
| 110 |  | 
| 111 | # ^[42 + a[i]] | 
| 112 | | Expr(expr e) | 
| 113 |  | 
| 114 | # ^(echo 1; echo 2) and cd { echo 1; echo 2 } | 
| 115 | | Command(command c) | 
| 116 |  | 
| 117 | # for Hay to get the backing lines | 
| 118 | # TODO: Consolidate value.Command and value.LiteralBlock.  All Command | 
| 119 | # instance should have backing lines. | 
| 120 |  | 
| 121 | # TODO: ASDL doesn't support shared variant across module | 
| 122 | # This would be more efficient | 
| 123 | # | LiteralBlock %LiteralBlock | 
| 124 | | Block(LiteralBlock block) | 
| 125 |  | 
| 126 | # A place has an additional stack frame where the value is evaluated. | 
| 127 | # The frame MUST be lower on the stack at the time of use. | 
| 128 | | Place(y_lvalue lval, Dict[str, Cell] frame) | 
| 129 |  | 
| 130 | # for Flags/flag and Flags/arg? | 
| 131 | # for json read/write ? | 
| 132 | # Possibly unify Hay and modules/namespaces | 
| 133 | | Module(Dict[str, value] defs) | 
| 134 |  | 
| 135 | # The ability to use operating system functions.  Right now some functions | 
| 136 | # leak, like glob(). | 
| 137 | | IO(any cmd_ev, any prompt_ev) | 
| 138 |  | 
| 139 | # Do we need this? | 
| 140 | # _guts->heapId() can be used to detect object cycles. | 
| 141 | # It's considered impure; it depends on VM implementation details.  The = | 
| 142 | # operator and 'pp value' also print the heap ID. | 
| 143 | | Guts(any vm) | 
| 144 |  | 
| 145 | # callable is vm._Callable. | 
| 146 | # TODO: ASDL needs some kind of "extern" to declare vm._Callable and | 
| 147 | # cmd_eval.CommandEvaluator.  I think it would just generate a forward | 
| 148 | # declaration. | 
| 149 | | BuiltinFunc(any callable) | 
| 150 | | BoundFunc(value me, value func) | 
| 151 |  | 
| 152 | # command.ShFunction and command.Proc evaluate to value.Proc | 
| 153 | # They each have name, name_tok, and body. | 
| 154 | # | 
| 155 | # YSH procs disable dynamic scope, have default args to evaluate, and | 
| 156 | # different @ARGV. | 
| 157 |  | 
| 158 | | Proc(str name, Token name_tok, proc_sig sig, command body, | 
| 159 | ProcDefaults? defaults, bool sh_compat) | 
| 160 |  | 
| 161 | # module may be a frame where defined | 
| 162 | | Func(str name, Func parsed, | 
| 163 | List[value] pos_defaults, Dict[str, value] named_defaults, | 
| 164 | Dict[str, Cell]? module_) | 
| 165 |  | 
| 166 | # a[3:5] a[:10] a[3:] a[:]  # both ends are optional | 
| 167 | | Slice(IntBox? lower, IntBox? upper) | 
| 168 |  | 
| 169 | # for i in (1:n) { echo $i }  # both ends are required | 
| 170 | | Range(int lower, int upper) | 
| 171 | } | 
| 172 |  | 
| 173 | # vim: sw=2 | 
| 174 |  |