mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 02:39:20 +00:00
refactor: std -> core
This commit is contained in:
parent
767d51d48b
commit
6de8355a25
40 changed files with 52 additions and 37 deletions
110
crates/erg_compiler/lib/core/_erg_array.py
Normal file
110
crates/erg_compiler/lib/core/_erg_array.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
from _erg_control import then__
|
||||
from _erg_range import Range
|
||||
from _erg_nat import NatMut
|
||||
from _erg_int import IntMut
|
||||
from _erg_contains_operator import contains_operator
|
||||
from _erg_result import is_ok
|
||||
from _erg_result import Error
|
||||
from _erg_type import UnionType
|
||||
|
||||
class Array(list):
|
||||
@staticmethod
|
||||
def try_new(arr): # -> Result[Array]
|
||||
if isinstance(arr, list):
|
||||
return Array(arr)
|
||||
else:
|
||||
return Error("not a list")
|
||||
|
||||
def generic_try_new(arr, cls = None): # -> Result[Array]
|
||||
if cls is None:
|
||||
return Array.try_new(arr)
|
||||
else:
|
||||
elem_t = cls.__args__[0]
|
||||
elems = []
|
||||
for elem in arr:
|
||||
if not hasattr(elem_t, "try_new"):
|
||||
return Error("not a " + str(elem_t))
|
||||
# TODO: nested check
|
||||
elem = elem_t.try_new(elem)
|
||||
if is_ok(elem):
|
||||
elems.append(elem)
|
||||
else:
|
||||
return Error("not a " + str(elem_t))
|
||||
return Array(elems)
|
||||
|
||||
def dedup(self, same_bucket=None):
|
||||
if same_bucket is None:
|
||||
return Array(list(set(self)))
|
||||
else:
|
||||
removes = []
|
||||
for lhs, rhs in zip(self, self[1:]):
|
||||
if same_bucket(lhs, rhs):
|
||||
removes.append(lhs)
|
||||
for remove in removes:
|
||||
self.remove(remove)
|
||||
return self
|
||||
|
||||
def get(self, index, default=None):
|
||||
try:
|
||||
return self[index]
|
||||
except IndexError:
|
||||
return default
|
||||
|
||||
def push(self, value):
|
||||
self.append(value)
|
||||
return self
|
||||
|
||||
def partition(self, f):
|
||||
return Array(list(filter(f, self))), Array(
|
||||
list(filter(lambda x: not f(x), self))
|
||||
)
|
||||
|
||||
def __mul__(self, n):
|
||||
return then__(list.__mul__(self, n), Array)
|
||||
|
||||
def __getitem__(self, index_or_slice):
|
||||
if isinstance(index_or_slice, slice):
|
||||
return Array(list.__getitem__(self, index_or_slice))
|
||||
elif isinstance(index_or_slice, NatMut) or isinstance(index_or_slice, IntMut):
|
||||
return list.__getitem__(self, int(index_or_slice))
|
||||
elif isinstance(index_or_slice, Range):
|
||||
return Array(list.__getitem__(self, index_or_slice.into_slice()))
|
||||
else:
|
||||
return list.__getitem__(self, index_or_slice)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(tuple(self))
|
||||
|
||||
def update(self, f):
|
||||
self = Array(f(self))
|
||||
|
||||
def type_check(self, t: type) -> bool:
|
||||
if isinstance(t, list):
|
||||
if len(t) < len(self):
|
||||
return False
|
||||
for (inner_t, elem) in zip(t, self):
|
||||
if not contains_operator(inner_t, elem):
|
||||
return False
|
||||
return True
|
||||
elif isinstance(t, set):
|
||||
return self in t
|
||||
elif isinstance(t, UnionType):
|
||||
return any([self.type_check(_t) for _t in t.__args__])
|
||||
elif not hasattr(t, "__args__"):
|
||||
return isinstance(self, t)
|
||||
elem_t = t.__args__[0]
|
||||
l = None if len(t.__args__) != 2 else t.__args__[1]
|
||||
if l is not None and l != len(self):
|
||||
return False
|
||||
for elem in self:
|
||||
if not contains_operator(elem_t, elem):
|
||||
return False
|
||||
return True
|
||||
|
||||
def update_nth(self, index, f):
|
||||
self[index] = f(self[index])
|
||||
|
||||
class UnsizedArray:
|
||||
elem: object
|
||||
def __init__(self, elem):
|
||||
self.elem = elem
|
60
crates/erg_compiler/lib/core/_erg_bool.py
Normal file
60
crates/erg_compiler/lib/core/_erg_bool.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
from _erg_nat import Nat
|
||||
from _erg_nat import NatMut
|
||||
from _erg_result import Error
|
||||
|
||||
|
||||
class Bool(Nat):
|
||||
def try_new(b: bool): # -> Result[Nat]
|
||||
if b == True or b == False:
|
||||
return Bool(b)
|
||||
else:
|
||||
return Error("Bool can't be other than True or False")
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self:
|
||||
return "True"
|
||||
else:
|
||||
return "False"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.__str__()
|
||||
|
||||
def mutate(self):
|
||||
return BoolMut(self)
|
||||
|
||||
def invert(self):
|
||||
return Bool(not self)
|
||||
|
||||
|
||||
class BoolMut(NatMut):
|
||||
value: Bool
|
||||
|
||||
def __init__(self, b: Bool):
|
||||
self.value = b
|
||||
|
||||
def __repr__(self):
|
||||
return self.value.__repr__()
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self.value)
|
||||
|
||||
def __hash__(self):
|
||||
return self.value.__hash__()
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, bool):
|
||||
return self.value == other
|
||||
else:
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, bool):
|
||||
return self.value != other
|
||||
else:
|
||||
return self.value != other.value
|
||||
|
||||
def update(self, f):
|
||||
self.value = Bool(f(self.value))
|
||||
|
||||
def invert(self):
|
||||
self.value = self.value.invert()
|
6
crates/erg_compiler/lib/core/_erg_builtins.py
Normal file
6
crates/erg_compiler/lib/core/_erg_builtins.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
# in Python 3.7, `sum` takes no keyword arguments
|
||||
def sum(iterable, start=0):
|
||||
s = start
|
||||
for i in iterable:
|
||||
s += i
|
||||
return s
|
12
crates/erg_compiler/lib/core/_erg_bytes.py
Normal file
12
crates/erg_compiler/lib/core/_erg_bytes.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
class Bytes(bytes):
|
||||
def try_new(*b): # -> Result[Nat]
|
||||
return Bytes(bytes(*b))
|
||||
|
||||
def __getitem__(self, index_or_slice):
|
||||
from _erg_range import Range
|
||||
if isinstance(index_or_slice, slice):
|
||||
return Bytes(bytes.__getitem__(self, index_or_slice))
|
||||
elif isinstance(index_or_slice, Range):
|
||||
return Bytes(bytes.__getitem__(self, index_or_slice.into_slice()))
|
||||
else:
|
||||
return bytes.__getitem__(self, index_or_slice)
|
70
crates/erg_compiler/lib/core/_erg_contains_operator.py
Normal file
70
crates/erg_compiler/lib/core/_erg_contains_operator.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
from _erg_result import is_ok
|
||||
from _erg_range import Range
|
||||
from _erg_type import is_type
|
||||
from _erg_type import _isinstance
|
||||
from _erg_type import UnionType
|
||||
|
||||
from collections import namedtuple
|
||||
from typing import Callable
|
||||
|
||||
# (elem in y) == contains_operator(y, elem)
|
||||
def contains_operator(y, elem) -> bool:
|
||||
if hasattr(elem, "type_check"):
|
||||
return elem.type_check(y)
|
||||
elif isinstance(y, UnionType):
|
||||
return any([contains_operator(t, elem) for t in y.__args__])
|
||||
# 1 in Int
|
||||
elif is_type(y):
|
||||
if _isinstance(elem, y):
|
||||
return True
|
||||
elif hasattr(y, "generic_try_new"):
|
||||
return is_ok(y.generic_try_new(elem, y))
|
||||
elif hasattr(y, "try_new") and is_ok(y.try_new(elem)):
|
||||
return True
|
||||
elif hasattr(y, "__origin__") and hasattr(y.__origin__, "type_check"):
|
||||
return y.__origin__.type_check(elem, y)
|
||||
# TODO: trait check
|
||||
return False
|
||||
# [1] in [Int]
|
||||
elif (
|
||||
_isinstance(y, list)
|
||||
and _isinstance(elem, list)
|
||||
and (len(y) == 0 or is_type(y[0]) or _isinstance(y[0], Range))
|
||||
):
|
||||
type_check = all(map(lambda x: contains_operator(x[0], x[1]), zip(y, elem)))
|
||||
len_check = len(elem) <= len(y)
|
||||
return type_check and len_check
|
||||
# (1, 2) in (Int, Int)
|
||||
elif (
|
||||
_isinstance(y, tuple)
|
||||
and _isinstance(elem, tuple)
|
||||
and (len(y) == 0 or is_type(y[0]) or _isinstance(y[0], Range))
|
||||
):
|
||||
if not hasattr(elem, "__iter__"):
|
||||
return False
|
||||
type_check = all(map(lambda x: contains_operator(x[0], x[1]), zip(y, elem)))
|
||||
len_check = len(elem) <= len(y)
|
||||
return type_check and len_check
|
||||
# {1: 2} in {Int: Int}
|
||||
elif (
|
||||
_isinstance(y, dict)
|
||||
and _isinstance(elem, dict)
|
||||
and (len(y) == 0 or is_type(next(iter(y.keys()))))
|
||||
):
|
||||
if len(y) == 1:
|
||||
key = next(iter(y.keys()))
|
||||
key_check = all([contains_operator(key, el) for el in elem.keys()])
|
||||
value = next(iter(y.values()))
|
||||
value_check = all([contains_operator(value, el) for el in elem.values()])
|
||||
return key_check and value_check
|
||||
type_check = True # TODO:
|
||||
len_check = True # It can be True even if either elem or y has the larger number of elems
|
||||
return type_check and len_check
|
||||
elif _isinstance(elem, list):
|
||||
from _erg_array import Array
|
||||
return contains_operator(y, Array(elem))
|
||||
elif _isinstance(elem, Callable):
|
||||
# TODO:
|
||||
return _isinstance(y, Callable)
|
||||
else:
|
||||
return elem in y
|
34
crates/erg_compiler/lib/core/_erg_control.py
Normal file
34
crates/erg_compiler/lib/core/_erg_control.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
def if__(cond, then, else_=lambda: None):
|
||||
if cond:
|
||||
return then()
|
||||
else:
|
||||
return else_()
|
||||
|
||||
|
||||
def for__(iterable, body):
|
||||
for i in iterable:
|
||||
body(i)
|
||||
|
||||
|
||||
def while__(cond_block, body):
|
||||
while cond_block():
|
||||
body()
|
||||
|
||||
|
||||
def with__(obj, body):
|
||||
obj.__enter__()
|
||||
body(obj)
|
||||
obj.__exit__()
|
||||
|
||||
|
||||
def discard__(obj):
|
||||
pass
|
||||
|
||||
def assert__(test, msg=None):
|
||||
assert test, msg
|
||||
|
||||
def then__(x, f):
|
||||
if x == None or x == NotImplemented:
|
||||
return x
|
||||
else:
|
||||
return f(x)
|
20
crates/erg_compiler/lib/core/_erg_convertors.py
Normal file
20
crates/erg_compiler/lib/core/_erg_convertors.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from _erg_int import Int
|
||||
from _erg_nat import Nat
|
||||
from _erg_float import Float
|
||||
from _erg_str import Str
|
||||
|
||||
|
||||
def int__(i):
|
||||
return Int(i)
|
||||
|
||||
|
||||
def nat__(i):
|
||||
return Nat(i)
|
||||
|
||||
|
||||
def float__(f):
|
||||
return Float(f)
|
||||
|
||||
|
||||
def str__(s):
|
||||
return Str(s)
|
36
crates/erg_compiler/lib/core/_erg_dict.py
Normal file
36
crates/erg_compiler/lib/core/_erg_dict.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
class Dict(dict):
|
||||
@staticmethod
|
||||
def try_new(dic): # -> Result[Dict]
|
||||
if isinstance(dic, dict):
|
||||
return Dict(dic)
|
||||
else:
|
||||
return Error("not a dict")
|
||||
def concat(self, other):
|
||||
return Dict({**self, **other})
|
||||
def diff(self, other):
|
||||
return Dict({k: v for k, v in self.items() if k not in other})
|
||||
# other: Iterable
|
||||
def update(self, other, conflict_resolver=None):
|
||||
if conflict_resolver == None:
|
||||
super().update(other)
|
||||
elif isinstance(other, dict):
|
||||
self.merge(other, conflict_resolver)
|
||||
else:
|
||||
for k, v in other:
|
||||
if k in self:
|
||||
self[k] = conflict_resolver(self[k], v)
|
||||
else:
|
||||
self[k] = v
|
||||
# other: Dict
|
||||
def merge(self, other, conflict_resolver=None):
|
||||
self.update(other, conflict_resolver)
|
||||
def insert(self, key, value):
|
||||
self[key] = value
|
||||
def remove(self, key):
|
||||
res = self.get(key)
|
||||
if res != None:
|
||||
del self[key]
|
||||
return res
|
||||
def as_record(self):
|
||||
from collections import namedtuple
|
||||
return namedtuple('Record', self.keys())(**self)
|
140
crates/erg_compiler/lib/core/_erg_float.py
Normal file
140
crates/erg_compiler/lib/core/_erg_float.py
Normal file
|
@ -0,0 +1,140 @@
|
|||
from _erg_result import Error
|
||||
from _erg_control import then__
|
||||
|
||||
|
||||
class Float(float):
|
||||
EPSILON = 2.220446049250313e-16
|
||||
|
||||
def try_new(i): # -> Result[Nat]
|
||||
if isinstance(i, float):
|
||||
return Float(i)
|
||||
else:
|
||||
return Error("not a float")
|
||||
|
||||
def mutate(self):
|
||||
return FloatMut(self)
|
||||
|
||||
def __abs__(self):
|
||||
return Float(float.__abs__(self))
|
||||
|
||||
def __add__(self, other):
|
||||
return then__(float.__add__(self, other), Float)
|
||||
|
||||
def __sub__(self, other):
|
||||
return then__(float.__sub__(self, other), Float)
|
||||
|
||||
def __mul__(self, other):
|
||||
return then__(float.__mul__(self, other), Float)
|
||||
|
||||
def __div__(self, other):
|
||||
return then__(float.__div__(self, other), Float)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return then__(float.__floordiv__(self, other), Float)
|
||||
|
||||
def __pow__(self, other):
|
||||
return then__(float.__pow__(self, other), Float)
|
||||
|
||||
def __rpow__(self, other):
|
||||
return then__(float.__pow__(float(other), self), Float)
|
||||
|
||||
def __pos__(self):
|
||||
return self
|
||||
|
||||
def __neg__(self):
|
||||
return then__(float.__neg__(self), Float)
|
||||
|
||||
def nearly_eq(self, other, epsilon=EPSILON):
|
||||
return abs(self - other) < epsilon
|
||||
|
||||
class FloatMut: # inherits Float
|
||||
value: Float
|
||||
|
||||
EPSILON = 2.220446049250313e-16
|
||||
|
||||
def __init__(self, i):
|
||||
self.value = Float(i)
|
||||
|
||||
def __repr__(self):
|
||||
return self.value.__repr__()
|
||||
|
||||
def __hash__(self):
|
||||
return self.value.__hash__()
|
||||
|
||||
def __deref__(self):
|
||||
return self.value
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return self.value == other
|
||||
else:
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return self.value != other
|
||||
else:
|
||||
return self.value != other.value
|
||||
|
||||
def __le__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return self.value <= other
|
||||
else:
|
||||
return self.value <= other.value
|
||||
|
||||
def __ge__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return self.value >= other
|
||||
else:
|
||||
return self.value >= other.value
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return self.value < other
|
||||
else:
|
||||
return self.value < other.value
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return self.value > other
|
||||
else:
|
||||
return self.value > other.value
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return FloatMut(self.value + other)
|
||||
else:
|
||||
return FloatMut(self.value + other.value)
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return FloatMut(self.value - other)
|
||||
else:
|
||||
return FloatMut(self.value - other.value)
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return FloatMut(self.value * other)
|
||||
else:
|
||||
return FloatMut(self.value * other.value)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return FloatMut(self.value // other)
|
||||
else:
|
||||
return FloatMut(self.value // other.value)
|
||||
|
||||
def __pow__(self, other):
|
||||
if isinstance(other, Float):
|
||||
return FloatMut(self.value**other)
|
||||
else:
|
||||
return FloatMut(self.value**other.value)
|
||||
|
||||
def __pos__(self):
|
||||
return self
|
||||
|
||||
def __neg__(self):
|
||||
return FloatMut(-self.value)
|
||||
|
||||
def update(self, f):
|
||||
self.value = Float(f(self.value))
|
154
crates/erg_compiler/lib/core/_erg_int.py
Normal file
154
crates/erg_compiler/lib/core/_erg_int.py
Normal file
|
@ -0,0 +1,154 @@
|
|||
from _erg_result import Error
|
||||
from _erg_control import then__
|
||||
|
||||
|
||||
class Int(int):
|
||||
def try_new(i): # -> Result[Nat]
|
||||
if isinstance(i, int):
|
||||
return Int(i)
|
||||
else:
|
||||
return Error("not an integer")
|
||||
|
||||
def bit_count(self):
|
||||
if hasattr(int, "bit_count"):
|
||||
return int.bit_count(self)
|
||||
else:
|
||||
return bin(self).count("1")
|
||||
|
||||
def succ(self):
|
||||
return Int(self + 1)
|
||||
|
||||
def pred(self):
|
||||
return Int(self - 1)
|
||||
|
||||
def mutate(self):
|
||||
return IntMut(self)
|
||||
|
||||
def __add__(self, other):
|
||||
return then__(int.__add__(self, other), Int)
|
||||
|
||||
def __sub__(self, other):
|
||||
return then__(int.__sub__(self, other), Int)
|
||||
|
||||
def __mul__(self, other):
|
||||
return then__(int.__mul__(self, other), Int)
|
||||
|
||||
def __div__(self, other):
|
||||
return then__(int.__div__(self, other), Int)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
return then__(int.__floordiv__(self, other), Int)
|
||||
|
||||
def __pow__(self, other):
|
||||
return then__(int.__pow__(self, other), Int)
|
||||
|
||||
def __rpow__(self, other):
|
||||
return then__(int.__pow__(other, self), Int)
|
||||
|
||||
def __pos__(self):
|
||||
return self
|
||||
|
||||
def __neg__(self):
|
||||
return then__(int.__neg__(self), Int)
|
||||
|
||||
|
||||
class IntMut: # inherits Int
|
||||
value: Int
|
||||
|
||||
def __init__(self, i):
|
||||
self.value = Int(i)
|
||||
def __int__(self):
|
||||
return self.value.__int__()
|
||||
|
||||
def __repr__(self):
|
||||
return self.value.__repr__()
|
||||
|
||||
def __hash__(self):
|
||||
return self.value.__hash__()
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return self.value == other
|
||||
else:
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return self.value != other
|
||||
else:
|
||||
return self.value != other.value
|
||||
|
||||
def __le__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return self.value <= other
|
||||
else:
|
||||
return self.value <= other.value
|
||||
|
||||
def __ge__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return self.value >= other
|
||||
else:
|
||||
return self.value >= other.value
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return self.value < other
|
||||
else:
|
||||
return self.value < other.value
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return self.value > other
|
||||
else:
|
||||
return self.value > other.value
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return IntMut(self.value + other)
|
||||
else:
|
||||
return IntMut(self.value + other.value)
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return IntMut(self.value - other)
|
||||
else:
|
||||
return IntMut(self.value - other.value)
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return IntMut(self.value * other)
|
||||
else:
|
||||
return IntMut(self.value * other.value)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return IntMut(self.value // other)
|
||||
else:
|
||||
return IntMut(self.value // other.value)
|
||||
|
||||
def __pow__(self, other):
|
||||
if isinstance(other, Int):
|
||||
return IntMut(self.value**other)
|
||||
else:
|
||||
return IntMut(self.value**other.value)
|
||||
|
||||
def __pos__(self):
|
||||
return self
|
||||
|
||||
def __neg__(self):
|
||||
return IntMut(-self.value)
|
||||
|
||||
def update(self, f):
|
||||
self.value = Int(f(self.value))
|
||||
|
||||
def inc(self, i=1):
|
||||
self.value = Int(self.value + i)
|
||||
|
||||
def dec(self, i=1):
|
||||
self.value = Int(self.value - i)
|
||||
|
||||
def succ(self):
|
||||
return self.value.succ()
|
||||
|
||||
def pred(self):
|
||||
return self.value.pred()
|
5
crates/erg_compiler/lib/core/_erg_mutate_operator.py
Normal file
5
crates/erg_compiler/lib/core/_erg_mutate_operator.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
def mutate_operator(x):
|
||||
if hasattr(x, "mutate"):
|
||||
return x.mutate()
|
||||
else:
|
||||
return x
|
137
crates/erg_compiler/lib/core/_erg_nat.py
Normal file
137
crates/erg_compiler/lib/core/_erg_nat.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
from _erg_result import Error
|
||||
from _erg_int import Int
|
||||
from _erg_int import IntMut # don't unify with the above line
|
||||
from _erg_control import then__
|
||||
|
||||
class Nat(Int):
|
||||
def __init__(self, i):
|
||||
if int(i) < 0:
|
||||
raise ValueError("Nat can't be negative: {}".format(i))
|
||||
|
||||
def try_new(i): # -> Result[Nat]
|
||||
if i >= 0:
|
||||
return Nat(i)
|
||||
else:
|
||||
return Error("Nat can't be negative: {}".format(i))
|
||||
|
||||
def times(self, f):
|
||||
for _ in range(self):
|
||||
f()
|
||||
|
||||
def saturating_sub(self, other):
|
||||
if self > other:
|
||||
return self - other
|
||||
else:
|
||||
return 0
|
||||
|
||||
def mutate(self):
|
||||
return NatMut(self)
|
||||
|
||||
def __add__(self, other):
|
||||
return then__(super().__add__(other), Nat)
|
||||
|
||||
def __mul__(self, other):
|
||||
return then__(super().__mul__(other), Nat)
|
||||
|
||||
def __pos__(self):
|
||||
return self
|
||||
|
||||
|
||||
class NatMut(IntMut): # and Nat
|
||||
value: Nat
|
||||
|
||||
def __init__(self, n: Nat):
|
||||
if int(n) < 0:
|
||||
raise ValueError("Nat can't be negative: {}".format(n))
|
||||
self.value = n
|
||||
|
||||
def __int__(self):
|
||||
return self.value.__int__()
|
||||
|
||||
def __repr__(self):
|
||||
return self.value.__repr__()
|
||||
|
||||
def __hash__(self):
|
||||
return self.value.__hash__()
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.value == other
|
||||
else:
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.value != other
|
||||
else:
|
||||
return self.value != other.value
|
||||
|
||||
def __le__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.value <= other
|
||||
else:
|
||||
return self.value <= other.value
|
||||
|
||||
def __ge__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.value >= other
|
||||
else:
|
||||
return self.value >= other.value
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.value < other
|
||||
else:
|
||||
return self.value < other.value
|
||||
|
||||
def __gt__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.value > other
|
||||
else:
|
||||
return self.value > other.value
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, Nat):
|
||||
return NatMut(self.value + other)
|
||||
else:
|
||||
return NatMut(self.value + other.value)
|
||||
|
||||
def __radd__(self, other):
|
||||
if isinstance(other, Nat):
|
||||
return Nat(other + self.value)
|
||||
else:
|
||||
return Nat(other.value + self.value)
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, Nat):
|
||||
return NatMut(self.value * other)
|
||||
else:
|
||||
return NatMut(self.value * other.value)
|
||||
|
||||
def __rmul__(self, other):
|
||||
if isinstance(other, Nat):
|
||||
return Nat(other * self.value)
|
||||
else:
|
||||
return Nat(other.value * self.value)
|
||||
|
||||
def __pow__(self, other):
|
||||
if isinstance(other, Nat):
|
||||
return NatMut(self.value**other)
|
||||
else:
|
||||
return NatMut(self.value**other.value)
|
||||
|
||||
def __pos__(self):
|
||||
return self
|
||||
|
||||
def update(self, f):
|
||||
self.value = Nat(f(self.value))
|
||||
|
||||
def try_new(i): # -> Result[Nat]
|
||||
if i >= 0:
|
||||
return NatMut(i)
|
||||
else:
|
||||
return Error("Nat can't be negative")
|
||||
|
||||
def times(self, f):
|
||||
for _ in range(self.value):
|
||||
f()
|
129
crates/erg_compiler/lib/core/_erg_range.py
Normal file
129
crates/erg_compiler/lib/core/_erg_range.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
from _erg_nat import Nat
|
||||
from _erg_str import Str
|
||||
|
||||
# from collections.abc import Iterable, Sequence, Iterator, Container
|
||||
|
||||
|
||||
class Range:
|
||||
def __init__(self, start, end):
|
||||
self.start = start
|
||||
self.end = end
|
||||
|
||||
def __contains__(self, item):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def from_slice(slice):
|
||||
pass
|
||||
|
||||
def into_slice(self):
|
||||
pass
|
||||
|
||||
def __getitem__(self, item):
|
||||
res = self.start + item
|
||||
if res in self:
|
||||
return res
|
||||
else:
|
||||
raise IndexError("Index out of range")
|
||||
|
||||
# TODO: for Str, etc.
|
||||
def __len__(self):
|
||||
if self.start in self:
|
||||
if self.end in self:
|
||||
# len(1..4) == 4
|
||||
return self.end - self.start + 1
|
||||
else:
|
||||
# len(1..<4) == 3
|
||||
return self.end - self.start
|
||||
else:
|
||||
if self.end in self:
|
||||
# len(1<..4) == 3
|
||||
return self.end - self.start
|
||||
else:
|
||||
# len(1<..<4) == 2
|
||||
return self.end - self.start - 2
|
||||
|
||||
def __iter__(self):
|
||||
return RangeIterator(rng=self)
|
||||
|
||||
|
||||
# Sequence.register(Range)
|
||||
# Container.register(Range)
|
||||
# Iterable.register(Range)
|
||||
|
||||
|
||||
# represents `start<..end`
|
||||
class LeftOpenRange(Range):
|
||||
def __contains__(self, item):
|
||||
return self.start < item <= self.end
|
||||
|
||||
|
||||
# represents `start..<end`
|
||||
class RightOpenRange(Range):
|
||||
def __contains__(self, item):
|
||||
return self.start <= item < self.end
|
||||
|
||||
@staticmethod
|
||||
def from_slice(slice):
|
||||
return Range(slice.start, slice.stop)
|
||||
|
||||
def into_slice(self):
|
||||
return slice(self.start, self.end)
|
||||
|
||||
|
||||
# represents `start<..<end`
|
||||
class OpenRange(Range):
|
||||
def __contains__(self, item):
|
||||
return self.start < item < self.end
|
||||
|
||||
|
||||
# represents `start..end`
|
||||
class ClosedRange(Range):
|
||||
def __contains__(self, item):
|
||||
return self.start <= item <= self.end
|
||||
|
||||
@staticmethod
|
||||
def from_slice(slice):
|
||||
return Range(slice.start, slice.stop - 1)
|
||||
|
||||
def into_slice(self):
|
||||
return slice(self.start, self.end + 1)
|
||||
|
||||
|
||||
class RangeIterator:
|
||||
def __init__(self, rng):
|
||||
self.rng = rng
|
||||
self.needle = self.rng.start
|
||||
if issubclass(Nat, type(self.rng.start)):
|
||||
if not (self.needle in self.rng):
|
||||
self.needle += 1
|
||||
elif issubclass(Str, type(self.rng.start)):
|
||||
if not (self.needle in self.rng):
|
||||
self.needle = chr(ord(self.needle) + 1)
|
||||
else:
|
||||
if not (self.needle in self.rng):
|
||||
self.needle = self.needle.succ()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if issubclass(Nat, type(self.rng.start)):
|
||||
if self.needle in self.rng:
|
||||
result = self.needle
|
||||
self.needle += 1
|
||||
return result
|
||||
elif issubclass(Str, type(self.rng.start)):
|
||||
if self.needle in self.rng:
|
||||
result = self.needle
|
||||
self.needle = chr(ord(self.needle) + 1)
|
||||
return result
|
||||
else:
|
||||
if self.needle in self.rng:
|
||||
result = self.needle
|
||||
self.needle = self.needle.succ()
|
||||
return result
|
||||
raise StopIteration
|
||||
|
||||
|
||||
# Iterator.register(RangeIterator)
|
21
crates/erg_compiler/lib/core/_erg_result.py
Normal file
21
crates/erg_compiler/lib/core/_erg_result.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
# from typing import TypeVar, Union, _SpecialForm, _type_check
|
||||
|
||||
|
||||
class Error:
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
|
||||
# T = TypeVar("T")
|
||||
# @_SpecialForm
|
||||
# def Result(self, parameters):
|
||||
# """Result type.
|
||||
#
|
||||
# Result[T] is equivalent to Union[T, Error].
|
||||
# """
|
||||
# arg = _type_check(parameters, f"{self} requires a single type.")
|
||||
# return [arg, Error]
|
||||
|
||||
|
||||
def is_ok(obj) -> bool:
|
||||
return not isinstance(obj, Error)
|
2
crates/erg_compiler/lib/core/_erg_set.py
Normal file
2
crates/erg_compiler/lib/core/_erg_set.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
class Set(set):
|
||||
pass
|
0
crates/erg_compiler/lib/core/_erg_std_prelude.d.er
Normal file
0
crates/erg_compiler/lib/core/_erg_std_prelude.d.er
Normal file
25
crates/erg_compiler/lib/core/_erg_std_prelude.py
Normal file
25
crates/erg_compiler/lib/core/_erg_std_prelude.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from _erg_range import (
|
||||
Range,
|
||||
LeftOpenRange,
|
||||
RightOpenRange,
|
||||
OpenRange,
|
||||
ClosedRange,
|
||||
RangeIterator,
|
||||
)
|
||||
from _erg_result import Error, is_ok
|
||||
from _erg_float import Float, FloatMut
|
||||
from _erg_int import Int, IntMut
|
||||
from _erg_nat import Nat, NatMut
|
||||
from _erg_bool import Bool
|
||||
from _erg_bytes import Bytes
|
||||
from _erg_str import Str, StrMut
|
||||
from _erg_array import Array, UnsizedArray
|
||||
from _erg_dict import Dict
|
||||
from _erg_set import Set
|
||||
from _erg_contains_operator import contains_operator
|
||||
from _erg_mutate_operator import mutate_operator
|
||||
|
||||
Record = tuple
|
||||
|
||||
class Never:
|
||||
pass
|
107
crates/erg_compiler/lib/core/_erg_str.py
Normal file
107
crates/erg_compiler/lib/core/_erg_str.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
from _erg_result import Error
|
||||
from _erg_int import Int
|
||||
from _erg_control import then__
|
||||
|
||||
class Str(str):
|
||||
def __instancecheck__(cls, obj):
|
||||
return isinstance(obj, str)
|
||||
|
||||
def try_new(s: str): # -> Result[Nat]
|
||||
if isinstance(s, str):
|
||||
return Str(s)
|
||||
else:
|
||||
return Error("Str can't be other than str")
|
||||
|
||||
def get(self, i: int):
|
||||
if len(self) > i:
|
||||
return Str(self[i])
|
||||
else:
|
||||
return None
|
||||
|
||||
def mutate(self):
|
||||
return StrMut(self)
|
||||
|
||||
def to_int(self):
|
||||
return Int(self) if self.isdigit() else None
|
||||
|
||||
def contains(self, s):
|
||||
return s in self
|
||||
|
||||
def __add__(self, other):
|
||||
return then__(str.__add__(self, other), Str)
|
||||
|
||||
def __mul__(self, other):
|
||||
return then__(str.__mul__(self, other), Str)
|
||||
|
||||
def __mod__(self, other):
|
||||
return then__(str.__mod__(other, self), Str)
|
||||
|
||||
def __getitem__(self, index_or_slice):
|
||||
from _erg_range import Range
|
||||
if isinstance(index_or_slice, slice):
|
||||
return Str(str.__getitem__(self, index_or_slice))
|
||||
elif isinstance(index_or_slice, Range):
|
||||
return Str(str.__getitem__(self, index_or_slice.into_slice()))
|
||||
else:
|
||||
return str.__getitem__(self, index_or_slice)
|
||||
|
||||
|
||||
class StrMut: # Inherits Str
|
||||
value: Str
|
||||
|
||||
def __init__(self, s: str):
|
||||
self.value = s
|
||||
|
||||
def __repr__(self):
|
||||
return self.value.__repr__()
|
||||
|
||||
def __str__(self):
|
||||
return self.value.__str__()
|
||||
|
||||
def __hash__(self):
|
||||
return self.value.__hash__()
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Str):
|
||||
return self.value == other
|
||||
else:
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
if isinstance(other, Str):
|
||||
return self.value != other
|
||||
else:
|
||||
return self.value != other.value
|
||||
|
||||
def update(self, f):
|
||||
self.value = Str(f(self.value))
|
||||
|
||||
def try_new(s: str):
|
||||
if isinstance(s, str):
|
||||
self = StrMut()
|
||||
self.value = s
|
||||
return self
|
||||
else:
|
||||
return Error("Str! can't be other than str")
|
||||
|
||||
def clear(self):
|
||||
self.value = ""
|
||||
|
||||
def pop(self):
|
||||
if len(self.value) > 0:
|
||||
last = self.value[-1]
|
||||
self.value = self.value[:-1]
|
||||
return last
|
||||
else:
|
||||
return Error("Can't pop from empty `Str!`")
|
||||
|
||||
def push(self, s: str):
|
||||
self.value += s
|
||||
|
||||
def remove(self, idx: int):
|
||||
char = self.value[idx]
|
||||
self.value = self.value[:idx] + self.value[idx + 1 :]
|
||||
return char
|
||||
|
||||
def insert(self, idx: int, s: str):
|
||||
self.value = self.value[:idx] + s + self.value[idx:]
|
52
crates/erg_compiler/lib/core/_erg_type.py
Normal file
52
crates/erg_compiler/lib/core/_erg_type.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from typing import Callable
|
||||
|
||||
try:
|
||||
from typing import Union
|
||||
except ImportError:
|
||||
import warnings
|
||||
warnings.warn("`typing.Union` is not available. Please use Python 3.8+.")
|
||||
class Union:
|
||||
pass
|
||||
|
||||
class UnionType:
|
||||
__origin__ = Union
|
||||
__args__: list # list[type]
|
||||
def __init__(self, *args):
|
||||
self.__args__ = args
|
||||
def __str__(self):
|
||||
s = "UnionType["
|
||||
for i, arg in enumerate(self.__args__):
|
||||
if i > 0:
|
||||
s += ", "
|
||||
s += str(arg)
|
||||
s += "]"
|
||||
return s
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class FakeGenericAlias:
|
||||
__origin__: type
|
||||
__args__: list # list[type]
|
||||
def __init__(self, origin, *args):
|
||||
self.__origin__ = origin
|
||||
self.__args__ = args
|
||||
try:
|
||||
from types import GenericAlias
|
||||
except ImportError:
|
||||
GenericAlias = FakeGenericAlias
|
||||
|
||||
def is_type(x) -> bool:
|
||||
return isinstance(x, (type, FakeGenericAlias, GenericAlias, UnionType))
|
||||
|
||||
# The behavior of `builtins.isinstance` depends on the Python version.
|
||||
def _isinstance(obj, classinfo) -> bool:
|
||||
if isinstance(classinfo, (FakeGenericAlias, GenericAlias, UnionType)):
|
||||
if classinfo.__origin__ == Union:
|
||||
return any(_isinstance(obj, t) for t in classinfo.__args__)
|
||||
else:
|
||||
return isinstance(obj, classinfo.__origin__)
|
||||
else:
|
||||
try:
|
||||
return isinstance(obj, classinfo)
|
||||
except:
|
||||
return False
|
92
crates/erg_compiler/lib/core/_prelude.er
Normal file
92
crates/erg_compiler/lib/core/_prelude.er
Normal file
|
@ -0,0 +1,92 @@
|
|||
@Attach NeImpl
|
||||
Eq(R := Self) = Trait {
|
||||
.`==` = (self: Self, R) -> Bool
|
||||
}
|
||||
|
||||
NeImpl R = Patch Eq R
|
||||
NeImpl(R).
|
||||
`!=`(self, other: R): Bool = not(self == other)
|
||||
|
||||
@Attach EqImpl, LeImpl, LtImpl, GeImpl, GtImpl
|
||||
PartialOrd(R := Self) = Trait {
|
||||
.cmp = (self: Self, R) -> Option Ordering
|
||||
}
|
||||
Ord = Subsume PartialOrd()
|
||||
|
||||
EqForOrd R = Patch Ord
|
||||
EqForOrd(R)|<: Eq()|.
|
||||
`==`(self, other: R): Bool = self.cmp(other) == Ordering.Equal
|
||||
|
||||
LeForOrd = Patch Ord
|
||||
LeForOrd.
|
||||
`<=`(self, other: Self): Bool = self.cmp(other) == Ordering.Less or self == other
|
||||
LtForOrd = Patch Ord
|
||||
LtForOrd.
|
||||
`<`(self, other: Self): Bool = self.cmp(other) == Ordering.Less
|
||||
GeForOrd = Patch Ord
|
||||
GeForOrd.
|
||||
`>=`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater or self == other
|
||||
GtForOrd = Patch Ord
|
||||
GtForOrd.
|
||||
`>`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater
|
||||
|
||||
Add(R := Self) = Trait {
|
||||
.Output = Type;
|
||||
.`_+_` = (self: Self, R) -> Self.Output;
|
||||
}
|
||||
Sub(R := Self) = Trait {
|
||||
.Output = Type;
|
||||
.`_-_` = (self: Self, R) -> Self.Output;
|
||||
}
|
||||
Mul(R := Self) = Trait {
|
||||
.Output = Type;
|
||||
.`*` = (self: Self, R) -> Self.Output
|
||||
}
|
||||
Div(R := Self) = Trait {
|
||||
.Output = Type;
|
||||
.`/` = (self: Self, R) -> Self.Output or Panic
|
||||
}
|
||||
Num = Add and Sub and Mul
|
||||
|
||||
Seq T = Trait {
|
||||
.__len__ = (self: Ref(Self)) -> Nat;
|
||||
.get = (self: Ref(Self), Nat) -> T
|
||||
}
|
||||
|
||||
AddForInt = Patch Int
|
||||
AddForInt|<: Add(Int)|.
|
||||
AddO = Int
|
||||
`_+_`(self: Self, other: Int): Int = magic("Add.`_+_`")
|
||||
|
||||
# TODO: Mul and Div
|
||||
NumForInterval M, N, O, P: Int = Patch M..N
|
||||
NumForInterval(M, N, O, P)|<: Add(O..P)|.
|
||||
Output = M+O..N+P
|
||||
__add__(self: Self, other: O..P) = magic("NumForInterval.`_+_`")
|
||||
NumForInterval(M, N, O, P)|<: Sub(O..P)|.
|
||||
Output = M-P..N-O
|
||||
__sub__(self: Self, other: O..P) = magic("NumForInterval.`_-_`")
|
||||
|
||||
Read = Trait {
|
||||
.read = (self: Ref(Self),) -> Str
|
||||
}
|
||||
Read! = Trait {
|
||||
.read! = (self: Ref!(Self),) => Str
|
||||
}
|
||||
Write! = Trait {
|
||||
.write! = (self: Ref!(Self), Str) => ()
|
||||
}
|
||||
|
||||
discard _x = None
|
||||
|
||||
discard 1
|
||||
|
||||
# if: |T, U|(Bool, T, U) -> T or U
|
||||
cond|T: Type|(c: Bool, then: T, else: T): T =
|
||||
if c:
|
||||
do then
|
||||
do else
|
||||
|
||||
assert cond(False, 1, 2) == 2
|
||||
# assert cond(True, 1, 3) == "a"
|
||||
# assert "a" == cond(True, 1, 3)
|
18
crates/erg_compiler/lib/core/pyproject.toml
Normal file
18
crates/erg_compiler/lib/core/pyproject.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=45", "wheel"]
|
||||
|
||||
[project]
|
||||
name = "std"
|
||||
readme = "README.md"
|
||||
license = {file = "LICENSE"}
|
||||
authors = [{name = "Erg", email = "moderation@erg-lang.org"}]
|
||||
urls = {repository = "https://github.com/erg-lang/erg"}
|
||||
|
||||
dynamic = ["version"]
|
||||
requires-python = ">=3.7"
|
||||
|
||||
# dependencies = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
test = ["pytest"]
|
||||
dev = ["black", "ruff", "mypy"]
|
Loading…
Add table
Add a link
Reference in a new issue