use crate::{error::EvalError, state::InterpreterState, tools::Tools, value::Value};
pub fn is_user_collection(name: &str) -> bool {
matches!(name, "UserDict" | "UserList" | "UserString")
}
fn source(name: &str) -> Option<&'static str> {
match name {
"UserDict" => Some(USER_DICT_SRC),
"UserList" => Some(USER_LIST_SRC),
"UserString" => Some(USER_STRING_SRC),
_ => None,
}
}
pub async fn ensure_registered(
state: &mut InterpreterState,
name: &str,
tools: &Tools,
) -> Result<(), EvalError> {
if state.classes.contains_key(name) {
return Ok(());
}
let Some(src) = source(name) else {
return Ok(());
};
let stmts = crate::parser::parse(src).map_err(EvalError::Interpreter)?;
let saved = std::mem::replace(&mut state.current_source, src.to_string());
let outcome = crate::eval::eval_body(state, &stmts, tools).await;
state.current_source = saved;
outcome.map(|_| ())
}
pub async fn import_binding(
state: &mut InterpreterState,
name: &str,
target: &str,
tools: &Tools,
) -> Result<(), EvalError> {
let newly = !state.classes.contains_key(name);
ensure_registered(state, name, tools).await?;
state.set_variable(target, Value::Class(name.to_string())).map_err(EvalError::Interpreter)?;
if newly && target != name {
state.variables.remove(name);
}
Ok(())
}
const USER_DICT_SRC: &str = r#"
class UserDict:
def __init__(self, dict=None, **kwargs):
self.data = {}
if dict is not None:
self.update(dict)
if kwargs:
self.update(kwargs)
def __len__(self):
return len(self.data)
def __getitem__(self, key):
if key in self.data:
return self.data[key]
raise KeyError(key)
def __setitem__(self, key, item):
self.data[key] = item
def __delitem__(self, key):
del self.data[key]
def __iter__(self):
return iter(self.data)
def __contains__(self, key):
return key in self.data
def __repr__(self):
return repr(self.data)
def __eq__(self, other):
if isinstance(other, UserDict):
return self.data == other.data
return self.data == other
def __ne__(self, other):
return not (self == other)
def keys(self):
return self.data.keys()
def values(self):
return self.data.values()
def items(self):
return self.data.items()
def get(self, key, default=None):
return self.data.get(key, default)
def pop(self, key, *args):
return self.data.pop(key, *args)
def popitem(self):
return self.data.popitem()
def setdefault(self, key, default=None):
return self.data.setdefault(key, default)
def clear(self):
self.data.clear()
def update(self, other=None, **kwargs):
if other is not None:
if hasattr(other, "keys"):
for k in other.keys():
self.data[k] = other[k]
else:
for k, v in other:
self.data[k] = v
for k in kwargs:
self.data[k] = kwargs[k]
def copy(self):
return type(self)(dict(self.data))
"#;
const USER_LIST_SRC: &str = r#"
class UserList:
def __init__(self, initlist=None):
self.data = []
if initlist is not None:
if isinstance(initlist, UserList):
self.data[:] = initlist.data[:]
elif isinstance(initlist, list):
self.data[:] = initlist
else:
self.data = list(initlist)
def __repr__(self):
return repr(self.data)
def __len__(self):
return len(self.data)
def __getitem__(self, i):
if isinstance(i, slice):
return type(self)(self.data[i])
return self.data[i]
def __setitem__(self, i, item):
self.data[i] = item
def __delitem__(self, i):
del self.data[i]
def __contains__(self, item):
return item in self.data
def __iter__(self):
return iter(self.data)
def __add__(self, other):
if isinstance(other, UserList):
return type(self)(self.data + other.data)
elif isinstance(other, list):
return type(self)(self.data + other)
return type(self)(self.data + list(other))
def __mul__(self, n):
return type(self)(self.data * n)
def __eq__(self, other):
if isinstance(other, UserList):
return self.data == other.data
return self.data == other
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
if isinstance(other, UserList):
return self.data < other.data
return self.data < other
def append(self, item):
self.data.append(item)
def insert(self, i, item):
self.data.insert(i, item)
def pop(self, i=-1):
return self.data.pop(i)
def remove(self, item):
self.data.remove(item)
def clear(self):
self.data.clear()
def count(self, item):
return self.data.count(item)
def index(self, item, *args):
return self.data.index(item, *args)
def reverse(self):
self.data.reverse()
def sort(self, *args, **kwds):
self.data.sort(*args, **kwds)
def extend(self, other):
if isinstance(other, UserList):
self.data.extend(other.data)
else:
self.data.extend(other)
def copy(self):
return type(self)(self)
"#;
const USER_STRING_SRC: &str = r#"
class UserString:
def __init__(self, seq):
if isinstance(seq, str):
self.data = seq
elif isinstance(seq, UserString):
self.data = seq.data[:]
else:
self.data = str(seq)
def __str__(self):
return str(self.data)
def __repr__(self):
return repr(self.data)
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return type(self)(self.data[index])
def __contains__(self, char):
if isinstance(char, UserString):
char = char.data
return char in self.data
def __add__(self, other):
if isinstance(other, UserString):
return type(self)(self.data + other.data)
elif isinstance(other, str):
return type(self)(self.data + other)
return type(self)(self.data + str(other))
def __mul__(self, n):
return type(self)(self.data * n)
def __eq__(self, other):
if isinstance(other, UserString):
return self.data == other.data
return self.data == other
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
if isinstance(other, UserString):
return self.data < other.data
return self.data < other
def __iter__(self):
return iter(self.data)
def upper(self):
return type(self)(self.data.upper())
def lower(self):
return type(self)(self.data.lower())
def capitalize(self):
return type(self)(self.data.capitalize())
def title(self):
return type(self)(self.data.title())
def swapcase(self):
return type(self)(self.data.swapcase())
def strip(self, chars=None):
return type(self)(self.data.strip(chars))
def lstrip(self, chars=None):
return type(self)(self.data.lstrip(chars))
def rstrip(self, chars=None):
return type(self)(self.data.rstrip(chars))
def split(self, sep=None, maxsplit=-1):
return self.data.split(sep, maxsplit)
def rsplit(self, sep=None, maxsplit=-1):
return self.data.rsplit(sep, maxsplit)
def splitlines(self, keepends=False):
return self.data.splitlines(keepends)
def join(self, seq):
return self.data.join(seq)
def replace(self, old, new, maxsplit=-1):
if isinstance(old, UserString):
old = old.data
if isinstance(new, UserString):
new = new.data
return type(self)(self.data.replace(old, new, maxsplit))
def startswith(self, prefix, start=0, end=None):
return self.data.startswith(prefix, start, end if end is not None else len(self.data))
def endswith(self, suffix, start=0, end=None):
return self.data.endswith(suffix, start, end if end is not None else len(self.data))
def find(self, sub, start=0, end=None):
if isinstance(sub, UserString):
sub = sub.data
return self.data.find(sub, start, end if end is not None else len(self.data))
def rfind(self, sub, start=0, end=None):
if isinstance(sub, UserString):
sub = sub.data
return self.data.rfind(sub, start, end if end is not None else len(self.data))
def index(self, sub, start=0, end=None):
if isinstance(sub, UserString):
sub = sub.data
return self.data.index(sub, start, end if end is not None else len(self.data))
def count(self, sub, start=0, end=None):
if isinstance(sub, UserString):
sub = sub.data
return self.data.count(sub, start, end if end is not None else len(self.data))
def center(self, width, *args):
return type(self)(self.data.center(width, *args))
def ljust(self, width, *args):
return type(self)(self.data.ljust(width, *args))
def rjust(self, width, *args):
return type(self)(self.data.rjust(width, *args))
def zfill(self, width):
return type(self)(self.data.zfill(width))
def format(self, *args, **kwargs):
return self.data.format(*args, **kwargs)
def encode(self, encoding="utf-8", errors="strict"):
return self.data.encode(encoding, errors)
def isalpha(self):
return self.data.isalpha()
def isdigit(self):
return self.data.isdigit()
def isalnum(self):
return self.data.isalnum()
def isspace(self):
return self.data.isspace()
def isupper(self):
return self.data.isupper()
def islower(self):
return self.data.islower()
"#;