| 1 | """Methods on Obj instances that represent types"""
|
| 2 | from __future__ import print_function
|
| 3 |
|
| 4 | from _devbuild.gen.value_asdl import value, value_e, value_t, Obj
|
| 5 |
|
| 6 | from core import error
|
| 7 | from core import vm
|
| 8 | from frontend import typed_args
|
| 9 | from mycpp import mylib
|
| 10 | from mycpp.mylib import log, tagswitch, str_switch
|
| 11 |
|
| 12 | from typing import Dict, List, Optional, cast, TYPE_CHECKING
|
| 13 | if TYPE_CHECKING:
|
| 14 | pass
|
| 15 |
|
| 16 | _ = log
|
| 17 |
|
| 18 |
|
| 19 | def _GetStringField(obj, field_name):
|
| 20 | # type: (Obj, str) -> Optional[str]
|
| 21 |
|
| 22 | val = obj.d.get(field_name)
|
| 23 |
|
| 24 | # This could happen if a user attaches this BuiltinFunc to another
|
| 25 | # Object? A non-type object. Or the user can mutate the type object.
|
| 26 | if val is None:
|
| 27 | return None
|
| 28 | if val.tag() != value_e.Str:
|
| 29 | return None
|
| 30 | return cast(value.Str, val).s
|
| 31 |
|
| 32 |
|
| 33 | class Index__(vm._Callable):
|
| 34 | """
|
| 35 | This maintains the invariants:
|
| 36 |
|
| 37 | List[Int] is List[Int]
|
| 38 | List[Str] is List[Str]
|
| 39 |
|
| 40 | i.e. 2 evaluations always yield the same object
|
| 41 | """
|
| 42 |
|
| 43 | def __init__(self):
|
| 44 | # type: () -> None
|
| 45 | self.unique_instances = {} # type: Dict[str, Obj]
|
| 46 |
|
| 47 | def Call(self, rd):
|
| 48 | # type: (typed_args.Reader) -> value_t
|
| 49 | val = self._Call(rd)
|
| 50 | if val is None:
|
| 51 | raise error.Expr(
|
| 52 | 'Obj __index__ method detected a broken type Obj invariant',
|
| 53 | rd.LeastSpecificLocation())
|
| 54 | return val
|
| 55 |
|
| 56 | def _Call(self, rd):
|
| 57 | # type: (typed_args.Reader) -> Optional[value_t]
|
| 58 | left_obj = rd.PosObj()
|
| 59 | right = rd.PosValue()
|
| 60 | rd.Done()
|
| 61 |
|
| 62 | left_name = _GetStringField(left_obj, 'name')
|
| 63 | if left_name is None:
|
| 64 | return None # all type objects should have 'name'
|
| 65 |
|
| 66 | # This would mess up the encoding of 'Dict[Str,Int]'
|
| 67 | assert (',' not in left_name and '[' not in left_name and
|
| 68 | ']' not in left_name), left_name
|
| 69 |
|
| 70 | UP_right = right
|
| 71 |
|
| 72 | objects = [] # type: List[Obj]
|
| 73 | with tagswitch(right) as case2:
|
| 74 | if case2(value_e.Obj):
|
| 75 | right = cast(Obj, UP_right)
|
| 76 | objects.append(right)
|
| 77 |
|
| 78 | elif case2(value_e.List):
|
| 79 | right = cast(value.List, UP_right)
|
| 80 | for i, val in enumerate(right.items):
|
| 81 | if val.tag() != value_e.Obj:
|
| 82 | # List[Str, 3] is invalid
|
| 83 | return None
|
| 84 | objects.append(cast(Obj, val))
|
| 85 | else:
|
| 86 | raise error.TypeErr(
|
| 87 | right, 'Obj __index__ method expected Obj or List',
|
| 88 | rd.LeastSpecificLocation())
|
| 89 |
|
| 90 | with str_switch(left_name) as case:
|
| 91 | if case('List'):
|
| 92 | expected_params = 1
|
| 93 | elif case('Dict'):
|
| 94 | expected_params = 2
|
| 95 | else:
|
| 96 | expected_params = 0
|
| 97 |
|
| 98 | actual = len(objects)
|
| 99 | if expected_params != actual:
|
| 100 | raise error.Expr(
|
| 101 | 'Obj __index__ method expected %d params, got %d' %
|
| 102 | (expected_params, actual), rd.LeastSpecificLocation())
|
| 103 |
|
| 104 | buf = mylib.BufWriter()
|
| 105 | buf.write(left_name)
|
| 106 | buf.write('[')
|
| 107 |
|
| 108 | for i, r in enumerate(objects):
|
| 109 | if i != 0:
|
| 110 | buf.write(',')
|
| 111 |
|
| 112 | #log('OBJ %s', r)
|
| 113 |
|
| 114 | r_unique_id = _GetStringField(r, 'unique_id')
|
| 115 | if r_unique_id is not None:
|
| 116 | buf.write(r_unique_id)
|
| 117 | else:
|
| 118 | r_name = _GetStringField(r, 'name')
|
| 119 | if r_name is None:
|
| 120 | # every param object should have either:
|
| 121 | # 'name' - type object
|
| 122 | # 'unique_id' - parameterized type object
|
| 123 | return None
|
| 124 | assert (',' not in r_name and '[' not in r_name and
|
| 125 | ']' not in r_name), r_name
|
| 126 | buf.write(r_name)
|
| 127 |
|
| 128 | buf.write(']')
|
| 129 |
|
| 130 | unique_id = buf.getvalue()
|
| 131 | obj_with_params = self.unique_instances.get(unique_id)
|
| 132 | if obj_with_params is None:
|
| 133 | # These are parameterized type objects
|
| 134 | props = {
|
| 135 | 'unique_id': value.Str(unique_id),
|
| 136 | #'children': value.List(children)
|
| 137 | } # type: Dict[str, value_t]
|
| 138 | obj_with_params = Obj(None, props)
|
| 139 | self.unique_instances[unique_id] = obj_with_params
|
| 140 |
|
| 141 | return obj_with_params
|