from typing import Callable, Dict, List, Tuple from ppp_ast import Statements from ppp_object import Bool, EnumValue, Int, Object, Function, Str, TypeObject, Void, List as ListObject from ppp_types import Bool as BoolType, FunctionType, GenericType, Int as IntType, Str as StrType, Type, TypeType, VariableType, Void as VoidType, Object as ObjectType, ListType def PythonFunction(name: str, parameters: List[Tuple[str, Type]], return_type: Type, func: Callable[..., Object]) -> Object: return Function(FunctionType([parameter[1] for parameter in parameters], return_type), (name, parameters, return_type, Statements([]), lambda _0, _1, _2, _3, *args: func(*args))) def print_impl(str_: Object) -> Object: assert isinstance(str_, Str) print(str_.str, end='') return Void Print = PythonFunction("print", [('string', StrType)], VoidType, print_impl) def int_to_str_impl(int_: Object) -> Object: assert isinstance(int_, Int) return Str(str(int_.num)) IntToStr = PythonFunction("int_to_str", [('integer', IntType)], StrType, int_to_str_impl) def debug_print_impl(obj: Object) -> Object: print(obj) return Void DebugPrint = PythonFunction("debug_print", [('object', ObjectType)], VoidType, debug_print_impl) def read_impl(str_: Object) -> Object: assert isinstance(str_, Str) with open(str_.str) as f: return Str(f.read()) Read = PythonFunction("read", [('file_path', StrType)], StrType, read_impl) def len_impl(list_: Object) -> Object: assert list_.get_type().is_indexable(), list_ match list_: case Str(str): return Int(len(str)) case ListObject(_, list): return Int(len(list)) case _: assert False, ("Unimplemented", list_) assert False # TODO: Use polymorphism to make this work for both list and str Len = PythonFunction("len", [('list', ListType(VariableType("")))], IntType, len_impl) def str_len_impl(str_: Object) -> Object: assert isinstance(str_, Str) return Int(len(str_.str)) StrLen = PythonFunction("strlen", [('string', StrType)], IntType, str_len_impl) def str_to_int_impl(str_: Object) -> Object: assert isinstance(str_, Str) assert str_.str.isdigit() return Int(int(str_.str)) StrToInt = PythonFunction("str_to_int", [('string', StrType)], IntType, str_to_int_impl) def range_impl(start: Object, end: Object) -> Object: assert isinstance(start, Int) assert isinstance(end, Int) return ListObject(ListType(IntType), [Int(i) for i in range(start.num, end.num)]) Range = PythonFunction("range", [('start', IntType), ('end', IntType)], ListType(IntType), range_impl) def join_by_impl(seperator: Object, list: Object) -> Object: assert isinstance(seperator, Str) assert isinstance(list, ListObject) if len(list.list) == 0: return Str("") assert list.type.type.is_subtype_of(StrType), list new_array: List[str] = [] for str_ in list.list: assert isinstance(str_, Str) new_array.append(str_.str) return Str(seperator.str.join(new_array)) JoinBy = PythonFunction("join_by", [('seperator', StrType), ('list', ListType(StrType))], StrType, join_by_impl) def id_impl(obj: Object) -> Object: match obj: case EnumValue(_, _, _): return Int(id(obj)) case _: assert False, ("Unimplemented", obj) Id = PythonFunction("id", [('object', ObjectType)], IntType, id_impl) StrTypeObj = TypeObject(StrType) IntTypeObj = TypeObject(IntType) VoidTypeObj = TypeObject(VoidType) BoolTypeObj = TypeObject(BoolType) True_ = Bool(True) False_ = Bool(False) NoneObj = Void variables: Dict[str, Object] = { 'print': Print, 'true': True_, 'false': False_, 'int_to_str': IntToStr, 'str': StrTypeObj, 'int': IntTypeObj, 'bool': BoolTypeObj, 'void': VoidTypeObj, 'debug_print': DebugPrint, 'read': Read, 'len': Len, 'str_len': StrLen, 'str_to_int': StrToInt, 'none': NoneObj, 'range': Range, 'join_by': JoinBy, 'id': Id }