def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t1: TypeSystem.T = rt.chd[0].t if t1.base: if type(t1) == TypeSystem.Sym: rt.t = t1 elif type(t1) == TypeSystem.Real: rt.t = TypeSystem.Real else: return None else: return None return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t1: TypeSystem.T = rt.chd[0].t t2: TypeSystem.T = rt.chd[1].t if t1.base: if t2.base: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2) if type(res_t) in [ TypeSystem.Real, TypeSystem.Cmplx, TypeSystem.Sym ]: rt.t = res_t else: return None else: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2.chd_t) if type(res_t) in [ TypeSystem.Real, TypeSystem.Cmplx, TypeSystem.Sym ]: rt.t = TypeSystem.ArrFact.inst().coerce_arr_t(t2, res_t) else: return None else: if t2.base: res_t: TypeSystem.T = TypeSystem.T.supt(t1.chd_t, t2) if type(res_t) in [ TypeSystem.Real, TypeSystem.Cmplx, TypeSystem.Sym ]: rt.t = TypeSystem.ArrFact.inst().coerce_arr_t(t1, res_t) else: return None else: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2) if res_t and type( res_t.chd_t) in [TypeSystem.Real, TypeSystem.Cmplx]: rt.t = res_t else: return None return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t: TypeSystem.T = rt.chd[0].t if t.base: if type(t) not in [TypeSystem.Bool, TypeSystem.Sym]: return None else: rt.t = TypeSystem.Bool.inst() else: if type(t.chd_t) != TypeSystem.Bool: return None else: rt.t = TypeSystem.Bool.inst() return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t1: TypeSystem.T = rt.chd[0].t t2: TypeSystem.T = rt.chd[1].t if t1.base: if t2.base: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2) if not res_t or type(res_t) == TypeSystem.Void: return None else: rt.t = TypeSystem.Bool.inst() else: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2.chd_t) if not res_t or type(res_t) == TypeSystem.Void: return None else: rt.t = TypeSystem.ArrFact.inst().coerce_arr_t( t2, TypeSystem.Bool.inst()) else: if t2.base: res_t: TypeSystem.T = TypeSystem.T.supt(t1.chd_t, t2) if not res_t or type(res_t) == TypeSystem.Void: return None else: rt.t = TypeSystem.ArrFact.inst().coerce_arr_t( t1, TypeSystem.Bool.inst()) else: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2) if not res_t.chd_t or type(res_t.chd_t) == TypeSystem.Void: return None else: rt.t = TypeSystem.ArrFact.inst().coerce_arr_t( t1, TypeSystem.Bool.inst()) return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t1: TypeSystem.T = rt.chd[0].t t2: TypeSystem.T = rt.chd[1].t if t1.base and t2.base: res_t: TypeSystem.T = TypeSystem.T.supt(t1, t2) if type(res_t) == TypeSystem.Real: rt.t = TypeSystem.Tens(res_t, [None]) elif type(res_t) == TypeSystem.Sym: rt.t = res_t else: return None else: return None return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t: TypeSystem.T = rt.chd[0].t if t.base: if type(t) in [TypeSystem.Real, TypeSystem.Cmplx, TypeSystem.Sym]: rt.t = t return t_env else: return None else: if type(t.chd_t) in [TypeSystem.Real, TypeSystem.Cmplx]: rt.t = t return t_env else: return None
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t: TypeSystem.T = rt.chd[0].t if t.base: if type(t) == TypeSystem.Sym: rt.t = t return t_env else: return None else: if type(t.chd_t) == TypeSystem.Void or t.fold == 1: return None else: rt.t = t return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t1: TypeSystem.T = rt.chd[0].t if any(map(lambda x: type(x.t) == TypeSystem.Sym, rt.chd)): rt.t = TypeSystem.Sym.inst() return t_env if t1.base or t1.fold < rt.argc - 1: return None for tok in rt.chd[1:]: t1 = cls.__chk_t_hlpr(t1, tok.t) if not t1: return None rt.t = t1 return t_env
def chk_t( cls, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Optional[Dict[int, TypeSystem.T]]: t1: TypeSystem.T = rt.chd[0].t t2: TypeSystem.T = rt.chd[1].t if t1.base: if not (type(t1) == TypeSystem.Sym) or type(t2) == TypeSystem.Void: return None else: rt.t = t2 else: return None return t_env
def __str_pos_hlpr(self, rt: Token.Tok, target: Token.Tok) -> Tuple[str, bool, int]: tok_t: type = type(rt) if tok_t == Token.Op: if rt.v == Binary.Pow or rt.v.__base__ in [Assign.AsgnOp]: tmp_1: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[0], target) tmp_2: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[1], target) if rt == target: if type( rt.chd[0] ) == Token.Op and rt.precd_in >= rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' pos: int = tmp_1[2] + 3 else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' pos: int = tmp_1[2] + 1 if type(rt.chd[1] ) == Token.Op and rt.precd_in > rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, True, pos elif tmp_1[1]: if type( rt.chd[0] ) == Token.Op and rt.precd_in >= rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' pos: int = tmp_1[2] + 1 else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' pos: int = tmp_1[2] if type(rt.chd[1] ) == Token.Op and rt.precd_in > rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, True, pos elif tmp_2[1]: if type( rt.chd[0] ) == Token.Op and rt.precd_in >= rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' if type(rt.chd[1] ) == Token.Op and rt.precd_in > rt.chd[1].precd_in: pos: int = len(buf) + tmp_2[2] + 1 buf += f'({tmp_2[0]})' else: pos: int = len(buf) + tmp_2[2] buf += tmp_2[0] return buf, True, pos else: if type( rt.chd[0] ) == Token.Op and rt.precd_in >= rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' if type(rt.chd[1] ) == Token.Op and rt.precd_in > rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, False, len(buf) elif rt.v in [Unary.Plus, Unary.Minus, Bool.Neg]: tmp: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[0], target) if rt == target: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: return f'{rt.v.sym()}({tmp[0]})', True, 0 else: return f'{rt.v.sym()}{tmp[0]}', True, 0 elif tmp[1]: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: return f'{rt.v.sym()}({tmp[0]})', True, tmp[2] + 2 else: return f'{rt.v.sym()}{tmp[0]}', True, tmp[2] + 1 else: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: return f'{rt.v.sym()}({tmp[0]})', False, tmp[2] + 3 else: return f'{rt.v.sym()}{tmp[0]}', False, tmp[2] + 1 elif rt.v == Unary.Trans: tmp: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[0], target) if rt == target: if type(rt.chd[0]) == Token.Op and rt.precd_in > rt.chd[0].precd_in and \ rt.chd[0].v != Delimiter.Idx: return f'({tmp[0]})\'', True, tmp[2] + 2 else: return f'{tmp[0]}\'', True, tmp[2] elif tmp[1]: if type(rt.chd[0]) == Token.Op and rt.precd_in > rt.chd[0].precd_in and \ rt.chd[0].v != Delimiter.Idx: return f'({tmp[0]})\'', True, tmp[2] + 1 else: return f'{tmp[0]}\'', True, tmp[2] else: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: return f'({tmp[0]})\'', False, tmp[2] + 3 else: return f'{tmp[0]}\'', False, tmp[2] + 1 elif rt.v == Delimiter.Seq: tmp_1: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[0], target) tmp_2: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[1], target) if rt == target: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}):' pos: int = tmp_1[2] + 2 else: buf: str = f'{tmp_1[0]}:' pos: int = tmp_1[2] if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, True, pos elif tmp_1[1]: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}):' pos: int = tmp_1[2] + 1 else: buf: str = f'{tmp_1[0]}:' pos: int = tmp_1[2] if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, True, pos elif tmp_2[1]: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}):' else: buf: str = f'{tmp_1[0]}:' if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: pos: int = len(buf) + tmp_2[2] + 1 buf += f'({tmp_2[0]})' else: pos: int = len(buf) + tmp_2[2] buf += tmp_2[0] return buf, True, pos else: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}):' else: buf: str = f'{tmp_1[0]}:' if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, False, len(buf) elif rt.v == Delimiter.Idx: tmp_l: List[Tuple[str, bool, int]] = [ self.__str_pos_hlpr(tok, target) for tok in rt.chd ] if rt == target: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_l[0][0]})[' pos: int = tmp_l[0][2] + 2 else: buf: str = f'{tmp_l[0][0]}[' pos: int = tmp_l[0][2] return buf + ', '.join([tmp[0] for tmp in tmp_l[1:] ]) + ']', True, pos elif tmp_l[0][1]: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_l[0][0]})[' pos: int = tmp_l[0][2] + 1 else: buf: str = f'{tmp_l[0][0]}[' pos: int = tmp_l[0][2] return buf + ', '.join([tmp[0] for tmp in tmp_l[1:] ]) + ']', True, pos if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_l[0][0]})[' else: buf: str = f'{tmp_l[0][0]}[' pos: int = len(buf) i: int = 1 while i < len(tmp_l) and not tmp_l[i][1]: pos += tmp_l[i][2] + 2 i += 1 if i == len(tmp_l): return buf + ', '.join([ tmp[0] for tmp in tmp_l[1:] ]) + ']', False, pos - 1 if i > 1 else pos + 1 else: return buf + ', '.join([tmp[0] for tmp in tmp_l[1:] ]) + ']', True, pos else: tmp_1: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[0], target) tmp_2: Tuple[str, bool, int] = self.__str_pos_hlpr(rt.chd[1], target) if rt == target: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' pos: int = tmp_1[2] + 3 else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' pos: int = tmp_1[2] + 1 if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, True, pos elif tmp_1[1]: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' pos: int = tmp_1[2] + 1 else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' pos: int = tmp_1[2] if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, True, pos elif tmp_2[1]: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: pos: int = len(buf) + tmp_2[2] + 1 buf += f'({tmp_2[0]})' else: pos: int = len(buf) + tmp_2[2] buf += tmp_2[0] return buf, True, pos else: if type(rt.chd[0] ) == Token.Op and rt.precd_in > rt.chd[0].precd_in: buf: str = f'({tmp_1[0]}) {rt.v.sym()} ' else: buf: str = f'{tmp_1[0]} {rt.v.sym()} ' if type( rt.chd[1] ) == Token.Op and rt.precd_in >= rt.chd[1].precd_in: buf += f'({tmp_2[0]})' else: buf += tmp_2[0] return buf, False, len(buf) elif tok_t == Token.Fun: tmp_l: List[Tuple[str, bool, int]] = [ self.__str_pos_hlpr(tok, target) for tok in rt.chd ] if rt == target: return rt.v_str() + '[' + ', '.join([tmp[0] for tmp in tmp_l ]) + ']', True, 0 buf: str = rt.v_str() + '[' pos: int = len(buf) i: int = 0 while i < len(tmp_l) and not tmp_l[i][1]: pos += tmp_l[i][2] + 2 i += 1 print(pos) if i == len(tmp_l): return buf + ', '.join([ tmp[0] for tmp in tmp_l ]) + ']', False, pos - 1 if i > 0 else pos + 1 else: return buf + ', '.join([tmp[0] for tmp in tmp_l ]) + ']', True, pos + tmp_l[i][2] elif tok_t == Token.List: tmp_l: List[Tuple[str, bool, int]] = [ self.__str_pos_hlpr(tok, target) for tok in rt.chd ] if rt == target: return '{' + ', '.join([tmp[0] for tmp in tmp_l]) + '}', True, 0 buf: str = '{' pos: int = 1 i: int = 0 while i < len(tmp_l) and not tmp_l[i][1]: pos += tmp_l[i][2] + 2 i += 1 if i == len(tmp_l): return buf + ', '.join([ tmp[0] for tmp in tmp_l ]) + '}', False, pos - 1 if i > 0 else pos + 1 else: return buf + ', '.join([tmp[0] for tmp in tmp_l]) + '}', True, pos else: buf: str = rt.v_str() return (buf, True, 0) if rt == target else (buf, False, len(buf))
def __chk_t_hlpr(self, rt: Token.Tok, t_env: Dict[int, TypeSystem.T]) -> Dict[int, TypeSystem.T]: """ Check type of partial AST. Usually, type checking is quite tricky logic. For example, Hindley-Milner let type system needs unification algorithms for type checking. But since grammar of math expression is simple, type checking logic is relatively simple. It just calls corresponding type checking methods by looking up the value of root token. After checking type, it assign inferred type of root token as its field value. For concept of Hindley-Milner let type system and unification algorithm, consult the references below. This method is private and called internally as a helper of ``Interp.__chk_t``. **Reference** * https://en.wikipedia.org/wiki/Hindley–Milner_type_system * https://en.wikipedia.org/wiki/Unification_(computer_science) :param rt: Root of partial AST to be typed checked. :type rt: Token.Tok """ tok_t: type = type(rt) if tok_t == Token.Num: rt.t = TypeSystem.Cmplx.inst() if type(rt.v) == complex else TypeSystem.Real.inst() return t_env elif tok_t == Token.Str: rt.t = TypeSystem.Str.inst() return t_env elif tok_t == Token.Bool: rt.t = TypeSystem.Bool.inst() return t_env elif tok_t == Token.Void: rt.t = TypeSystem.Void.inst() return t_env elif tok_t == Token.Var: # find: TypeSystem.T = t_env.get(rt.v) rt.t = TypeSystem.Sym.inst() return t_env elif tok_t == Token.List: chd_t: List[TypeSystem.T] = [] for tok in rt.chd: t_env = self.__chk_t_hlpr(tok, t_env) chd_t.append(tok.t) res_t: TypeSystem.T = TypeSystem.ArrFact.inst().get_arr_t(chd_t) if not res_t: raise Exception('type error') rt.t = res_t return t_env elif tok_t == Token.Op: for tok in rt.chd: t_env = self.__chk_t_hlpr(tok, t_env) t_env = rt.v.chk_t(rt, t_env) if not t_env: raise InterpreterError.TErr(23, *self.__expr.str_pos(rt), rt, rt.v.sgn(), rt.v.__name__.upper()) return t_env else: for tok in rt.chd: t_env = self.__chk_t_hlpr(tok, t_env) rt.t = TypeSystem.Sym() return t_env