Add Str <-> Int, Nat convertors

This commit is contained in:
Shunsuke Shibayama 2022-12-06 23:44:24 +09:00
parent 592a77caab
commit 287a65276e
6 changed files with 63 additions and 4 deletions

View file

@ -143,6 +143,7 @@ pub struct PyCodeGenerator {
record_type_loaded: bool, record_type_loaded: bool,
module_type_loaded: bool, module_type_loaded: bool,
control_loaded: bool, control_loaded: bool,
convertors_loaded: bool,
abc_loaded: bool, abc_loaded: bool,
unit_size: usize, unit_size: usize,
units: PyCodeGenStack, units: PyCodeGenStack,
@ -160,6 +161,7 @@ impl PyCodeGenerator {
record_type_loaded: false, record_type_loaded: false,
module_type_loaded: false, module_type_loaded: false,
control_loaded: false, control_loaded: false,
convertors_loaded: false,
abc_loaded: false, abc_loaded: false,
unit_size: 0, unit_size: 0,
units: PyCodeGenStack::empty(), units: PyCodeGenStack::empty(),
@ -436,6 +438,7 @@ impl PyCodeGenerator {
fn emit_load_const<C: Into<ValueObj>>(&mut self, cons: C) { fn emit_load_const<C: Into<ValueObj>>(&mut self, cons: C) {
let value: ValueObj = cons.into(); let value: ValueObj = cons.into();
let is_str = value.is_str();
let is_int = value.is_int(); let is_int = value.is_int();
let is_nat = value.is_nat(); let is_nat = value.is_nat();
let is_bool = value.is_bool(); let is_bool = value.is_bool();
@ -449,8 +452,12 @@ impl PyCodeGenerator {
} else if is_int { } else if is_int {
self.emit_push_null(); self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Int")); self.emit_load_name_instr(Identifier::public("Int"));
} else if is_str {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Str"));
} }
} }
let wrapped = is_str || is_int; // is_int => is_nat and is_bool
let idx = self let idx = self
.mut_cur_block_codeobj() .mut_cur_block_codeobj()
.consts .consts
@ -463,8 +470,7 @@ impl PyCodeGenerator {
self.write_instr(LOAD_CONST); self.write_instr(LOAD_CONST);
self.write_arg(idx); self.write_arg(idx);
self.stack_inc(); self.stack_inc();
if !self.cfg.no_std && is_int { if !self.cfg.no_std && wrapped {
// is_int => is_nat and is_bool
self.emit_call_instr(1, Name); self.emit_call_instr(1, Name);
self.stack_dec(); self.stack_dec();
} }
@ -632,9 +638,15 @@ impl PyCodeGenerator {
fn emit_load_name_instr(&mut self, ident: Identifier) { fn emit_load_name_instr(&mut self, ident: Identifier) {
log!(info "entered {}({ident})", fn_name!()); log!(info "entered {}({ident})", fn_name!());
let escaped = escape_name(ident); let escaped = escape_name(ident);
if let "if__" | "for__" | "while__" | "with__" | "discard__" = &escaped[..] { match &escaped[..] {
"if__" | "for__" | "while__" | "with__" | "discard__" => {
self.load_control(); self.load_control();
} }
"int__" | "nat__" => {
self.load_convertors();
}
_ => {}
}
let name = self let name = self
.local_search(&escaped, Name) .local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped)); .unwrap_or_else(|| self.register_name(escaped));
@ -2797,6 +2809,12 @@ impl PyCodeGenerator {
self.control_loaded = true; self.control_loaded = true;
} }
fn load_convertors(&mut self) {
let mod_name = Identifier::public("_erg_convertors");
self.emit_import_all_instr(mod_name);
self.convertors_loaded = true;
}
fn load_prelude_py(&mut self) { fn load_prelude_py(&mut self) {
self.emit_global_import_items( self.emit_global_import_items(
Identifier::public("sys"), Identifier::public("sys"),

View file

@ -941,6 +941,12 @@ impl Context {
Immutable, Immutable,
Public, Public,
); );
str_.register_builtin_impl(
"to_int",
fn_met(Str, vec![], None, vec![], or(Int, NoneType)),
Immutable,
Public,
);
let str_getitem_t = fn1_kw_met(Str, kw("idx", Nat), Str); let str_getitem_t = fn1_kw_met(Str, kw("idx", Nat), Str);
str_.register_builtin_impl("__getitem__", str_getitem_t, Immutable, Public); str_.register_builtin_impl("__getitem__", str_getitem_t, Immutable, Public);
let mut str_eq = Self::builtin_methods(Some(mono("Eq")), 2); let mut str_eq = Self::builtin_methods(Some(mono("Eq")), 2);
@ -1731,6 +1737,7 @@ impl Context {
or(T, U), or(T, U),
) )
.quantify(); .quantify();
let t_int = nd_func(vec![kw("obj", Obj)], None, or(Int, NoneType));
let t_import = nd_func( let t_import = nd_func(
vec![anon(tp_enum(Str, set! {Path.clone()}))], vec![anon(tp_enum(Str, set! {Path.clone()}))],
None, None,
@ -1769,6 +1776,7 @@ impl Context {
], ],
NoneType, NoneType,
); );
let t_nat = nd_func(vec![kw("obj", Obj)], None, or(Nat, NoneType));
// e.g. not(b: Bool!): Bool! // e.g. not(b: Bool!): Bool!
let B = mono_q("B", subtypeof(Bool)); let B = mono_q("B", subtypeof(Bool));
let t_not = nd_func(vec![kw("b", B.clone())], None, B).quantify(); let t_not = nd_func(vec![kw("b", B.clone())], None, B).quantify();
@ -1808,6 +1816,7 @@ impl Context {
self.register_builtin_py_impl("discard", t_discard, Immutable, Private, Some("discard__")); self.register_builtin_py_impl("discard", t_discard, Immutable, Private, Some("discard__"));
self.register_builtin_py_impl("exit", t_exit, Immutable, Private, Some("exit")); self.register_builtin_py_impl("exit", t_exit, Immutable, Private, Some("exit"));
self.register_builtin_py_impl("if", t_if, Immutable, Private, Some("if__")); self.register_builtin_py_impl("if", t_if, Immutable, Private, Some("if__"));
self.register_builtin_py_impl("int", t_int, Immutable, Private, Some("int__"));
self.register_builtin_py_impl("import", t_import, Immutable, Private, Some("__import__")); self.register_builtin_py_impl("import", t_import, Immutable, Private, Some("__import__"));
self.register_builtin_py_impl( self.register_builtin_py_impl(
"isinstance", "isinstance",
@ -1825,6 +1834,7 @@ impl Context {
); );
self.register_builtin_py_impl("len", t_len, Immutable, Private, Some("len")); self.register_builtin_py_impl("len", t_len, Immutable, Private, Some("len"));
self.register_builtin_py_impl("log", t_log, Immutable, Private, Some("print")); self.register_builtin_py_impl("log", t_log, Immutable, Private, Some("print"));
self.register_builtin_py_impl("nat", t_nat, Immutable, Private, Some("nat__"));
self.register_builtin_py_impl("not", t_not, Immutable, Private, None); // `not` is not a function in Python self.register_builtin_py_impl("not", t_not, Immutable, Private, None); // `not` is not a function in Python
self.register_builtin_py_impl("oct", t_oct, Immutable, Private, Some("oct")); self.register_builtin_py_impl("oct", t_oct, Immutable, Private, Some("oct"));
self.register_builtin_py_impl("ord", t_ord, Immutable, Private, Some("ord")); self.register_builtin_py_impl("ord", t_ord, Immutable, Private, Some("ord"));

View file

@ -0,0 +1,14 @@
from _erg_int import Int
from _erg_nat import Nat
def int__(i):
try:
return Int(i)
except:
return None
def nat__(i):
try:
return Nat(i)
except:
return None

View file

@ -1,4 +1,5 @@
from _erg_result import Error from _erg_result import Error
from _erg_int import Int
class Str(str): class Str(str):
def __instancecheck__(cls, obj): def __instancecheck__(cls, obj):
@ -15,6 +16,8 @@ class Str(str):
return None return None
def mutate(self): def mutate(self):
return StrMut(self) return StrMut(self)
def to_int(self):
return Int(self) if self.isdigit() else None
class StrMut(): # Inherits Str class StrMut(): # Inherits Str
value: Str value: Str

View file

@ -227,6 +227,7 @@ pub struct ScriptGenerator {
range_ops_loaded: bool, range_ops_loaded: bool,
builtin_types_loaded: bool, builtin_types_loaded: bool,
builtin_control_loaded: bool, builtin_control_loaded: bool,
convertors_loaded: bool,
prelude: String, prelude: String,
} }
@ -241,6 +242,7 @@ impl ScriptGenerator {
range_ops_loaded: false, range_ops_loaded: false,
builtin_types_loaded: false, builtin_types_loaded: false,
builtin_control_loaded: false, builtin_control_loaded: false,
convertors_loaded: false,
prelude: String::new(), prelude: String::new(),
} }
} }
@ -317,6 +319,10 @@ impl ScriptGenerator {
self.prelude += include_str!("lib/std/_erg_control.py"); self.prelude += include_str!("lib/std/_erg_control.py");
} }
fn load_convertors(&mut self) {
self.prelude += &Self::replace_import(include_str!("lib/std/_erg_convertors.py"));
}
fn escape_str(s: &str) -> String { fn escape_str(s: &str) -> String {
s.replace('\n', "\\n") s.replace('\n', "\\n")
.replace('\r', "\\r") .replace('\r', "\\r")
@ -525,6 +531,10 @@ impl ScriptGenerator {
self.load_builtin_controls(); self.load_builtin_controls();
self.builtin_control_loaded = true; self.builtin_control_loaded = true;
} }
"int" | "nat" if !self.convertors_loaded => {
self.load_convertors();
self.convertors_loaded = true;
}
_ => {} _ => {}
} }
Self::transpile_ident(ident) Self::transpile_ident(ident)

View file

@ -677,6 +677,10 @@ impl ValueObj {
} }
} }
pub const fn is_str(&self) -> bool {
matches!(self, Self::Str(_))
}
pub const fn is_type(&self) -> bool { pub const fn is_type(&self) -> bool {
matches!(self, Self::Type(_)) matches!(self, Self::Type(_))
} }