mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 20:14:45 +00:00
fix: keyword argument bugs
This commit is contained in:
parent
21283b668e
commit
80872fc50e
14 changed files with 166 additions and 74 deletions
|
@ -67,6 +67,8 @@ pub enum CommonOpcode {
|
|||
MAKE_FUNCTION = 132,
|
||||
CALL_FUNCTION_EX = 142,
|
||||
EXTENDED_ARG = 144,
|
||||
BUILD_CONST_KEY_MAP = 156,
|
||||
BUILD_STRING = 157,
|
||||
LOAD_METHOD = 160,
|
||||
NOT_IMPLEMENTED = 255,
|
||||
}
|
||||
|
@ -132,6 +134,8 @@ impl TryFrom<u8> for CommonOpcode {
|
|||
132 => MAKE_FUNCTION,
|
||||
142 => CALL_FUNCTION_EX,
|
||||
144 => EXTENDED_ARG,
|
||||
156 => BUILD_CONST_KEY_MAP,
|
||||
157 => BUILD_STRING,
|
||||
160 => LOAD_METHOD,
|
||||
255 => NOT_IMPLEMENTED,
|
||||
_other => return Err(()),
|
||||
|
|
|
@ -109,6 +109,8 @@ impl_u8_enum! {Opcode308;
|
|||
CALL_FUNCTION_EX = 142,
|
||||
SETUP_WITH = 143,
|
||||
EXTENDED_ARG = 144,
|
||||
BUILD_CONST_KEY_MAP = 156,
|
||||
BUILD_STRING = 157,
|
||||
BUILD_TUPLE_UNPACK_WITH_CALL = 158,
|
||||
LOAD_METHOD = 160,
|
||||
CALL_METHOD = 161,
|
||||
|
|
|
@ -108,6 +108,8 @@ impl_u8_enum! {Opcode309;
|
|||
CALL_FUNCTION_EX = 142,
|
||||
SETUP_WITH = 143,
|
||||
EXTENDED_ARG = 144,
|
||||
BUILD_CONST_KEY_MAP = 156,
|
||||
BUILD_STRING = 157,
|
||||
BUILD_TUPLE_UNPACK_WITH_CALL = 158,
|
||||
LOAD_METHOD = 160,
|
||||
CALL_METHOD = 161,
|
||||
|
|
|
@ -106,6 +106,8 @@ impl_u8_enum! {Opcode310;
|
|||
CALL_FUNCTION_EX = 142,
|
||||
SETUP_WITH = 143,
|
||||
EXTENDED_ARG = 144,
|
||||
BUILD_CONST_KEY_MAP = 156,
|
||||
BUILD_STRING = 157,
|
||||
LOAD_METHOD = 160,
|
||||
CALL_METHOD = 161,
|
||||
LIST_EXTEND = 162,
|
||||
|
|
|
@ -97,6 +97,8 @@ impl_u8_enum! {Opcode311;
|
|||
RESUME = 151,
|
||||
MATCH_CLASS = 152,
|
||||
FORMAT_VALUE = 155,
|
||||
BUILD_CONST_KEY_MAP = 156,
|
||||
BUILD_STRING = 157,
|
||||
LOAD_METHOD = 160,
|
||||
LIST_EXTEND = 162,
|
||||
PRECALL = 166,
|
||||
|
|
|
@ -36,6 +36,7 @@ use crate::compile::{AccessKind, Name, StoreLoadKind};
|
|||
use crate::context::ControlKind;
|
||||
use crate::error::CompileError;
|
||||
use crate::hir::ArrayWithLength;
|
||||
use crate::hir::DefaultParamSignature;
|
||||
use crate::hir::{
|
||||
Accessor, Args, Array, BinOp, Block, Call, ClassDef, Def, DefBody, Expr, GuardClause,
|
||||
Identifier, Lambda, Literal, NonDefaultParamSignature, Params, PatchDef, PosArg, ReDef, Record,
|
||||
|
@ -117,6 +118,8 @@ fn escape_ident(ident: Identifier) -> Str {
|
|||
)
|
||||
} else if let Some(py_name) = ident.vi.py_name {
|
||||
py_name
|
||||
} else if ident.vi.is_parameter() || ident.inspect() == "self" {
|
||||
ident.inspect().clone()
|
||||
} else {
|
||||
escape_name(
|
||||
ident.inspect(),
|
||||
|
@ -159,10 +162,12 @@ impl fmt::Display for PyCodeGenUnit {
|
|||
}
|
||||
|
||||
impl PyCodeGenUnit {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new<S: Into<Str>, T: Into<Str>>(
|
||||
id: usize,
|
||||
py_version: PythonVersion,
|
||||
params: Vec<Str>,
|
||||
kwonlyargcount: u32,
|
||||
filename: S,
|
||||
name: T,
|
||||
firstlineno: u32,
|
||||
|
@ -171,7 +176,7 @@ impl PyCodeGenUnit {
|
|||
Self {
|
||||
id,
|
||||
py_version,
|
||||
codeobj: CodeObj::empty(params, filename, name, firstlineno, flags),
|
||||
codeobj: CodeObj::empty(params, kwonlyargcount, filename, name, firstlineno, flags),
|
||||
captured_vars: vec![],
|
||||
stack_len: 0,
|
||||
prev_lineno: firstlineno,
|
||||
|
@ -1018,6 +1023,12 @@ impl PyCodeGenerator {
|
|||
.non_defaults
|
||||
.iter()
|
||||
.map(|p| (p.inspect().map(|s| &s[..]).unwrap_or("_"), &p.vi))
|
||||
.chain(
|
||||
params
|
||||
.defaults
|
||||
.iter()
|
||||
.map(|p| (p.inspect().map(|s| &s[..]).unwrap_or("_"), &p.sig.vi)),
|
||||
)
|
||||
.chain(if let Some(var_args) = ¶ms.var_params {
|
||||
vec![(
|
||||
var_args.inspect().map(|s| &s[..]).unwrap_or("_"),
|
||||
|
@ -1026,12 +1037,6 @@ impl PyCodeGenerator {
|
|||
} else {
|
||||
vec![]
|
||||
})
|
||||
.chain(
|
||||
params
|
||||
.defaults
|
||||
.iter()
|
||||
.map(|p| (p.inspect().map(|s| &s[..]).unwrap_or("_"), &p.sig.vi)),
|
||||
)
|
||||
.chain(if let Some(kw_var_args) = ¶ms.kw_var_params {
|
||||
vec![(
|
||||
kw_var_args.inspect().map(|s| &s[..]).unwrap_or("_"),
|
||||
|
@ -1047,7 +1052,7 @@ impl PyCodeGenerator {
|
|||
} else {
|
||||
escape_name(
|
||||
s,
|
||||
&VisibilityModifier::Private,
|
||||
&VisibilityModifier::Public,
|
||||
vi.def_loc.loc.ln_begin().unwrap_or(0),
|
||||
vi.def_loc.loc.col_begin().unwrap_or(0),
|
||||
)
|
||||
|
@ -1200,6 +1205,7 @@ impl PyCodeGenerator {
|
|||
self.unit_size,
|
||||
self.py_version,
|
||||
vec![],
|
||||
0,
|
||||
Str::rc(self.cfg.input.enclosed_name()),
|
||||
&name,
|
||||
firstlineno,
|
||||
|
@ -1269,6 +1275,7 @@ impl PyCodeGenerator {
|
|||
self.unit_size,
|
||||
self.py_version,
|
||||
vec![],
|
||||
0,
|
||||
Str::rc(self.cfg.input.enclosed_name()),
|
||||
ident.inspect(),
|
||||
ident.ln_begin().unwrap_or(0),
|
||||
|
@ -1403,22 +1410,63 @@ impl PyCodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_subr_def(&mut self, class_name: Option<&str>, sig: SubrSignature, body: DefBody) {
|
||||
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
|
||||
let name = sig.ident.inspect().clone();
|
||||
let mut make_function_flag = 0;
|
||||
let params = self.gen_param_names(&sig.params);
|
||||
if !sig.params.defaults.is_empty() {
|
||||
let defaults_len = sig.params.defaults.len();
|
||||
sig.params
|
||||
.defaults
|
||||
/// No parameter mangling is used
|
||||
/// so that Erg functions can be called from Python with keyword arguments.
|
||||
fn emit_params(
|
||||
&mut self,
|
||||
var_params: Option<&NonDefaultParamSignature>,
|
||||
defaults: Vec<DefaultParamSignature>,
|
||||
function_flag: &mut usize,
|
||||
) {
|
||||
if var_params.is_some() && !defaults.is_empty() {
|
||||
let defaults_len = defaults.len();
|
||||
let names = defaults
|
||||
.iter()
|
||||
.map(|default| {
|
||||
escape_name(
|
||||
default.sig.inspect().map_or("_", |s| &s[..]),
|
||||
&VisibilityModifier::Public,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
defaults
|
||||
.into_iter()
|
||||
.for_each(|default| self.emit_expr(default.default_val));
|
||||
self.emit_load_const(names);
|
||||
self.stack_dec();
|
||||
self.write_instr(BUILD_CONST_KEY_MAP);
|
||||
self.write_arg(defaults_len);
|
||||
self.stack_dec_n(defaults_len - 1);
|
||||
*function_flag += MakeFunctionFlags::KwDefaults as usize;
|
||||
} else if !defaults.is_empty() {
|
||||
let defaults_len = defaults.len();
|
||||
defaults
|
||||
.into_iter()
|
||||
.for_each(|default| self.emit_expr(default.default_val));
|
||||
self.write_instr(BUILD_TUPLE);
|
||||
self.write_arg(defaults_len);
|
||||
self.stack_dec_n(defaults_len - 1);
|
||||
make_function_flag += MakeFunctionFlags::Defaults as usize;
|
||||
*function_flag += MakeFunctionFlags::Defaults as usize;
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_subr_def(&mut self, class_name: Option<&str>, sig: SubrSignature, body: DefBody) {
|
||||
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
|
||||
let name = sig.ident.inspect().clone();
|
||||
let mut make_function_flag = 0;
|
||||
let params = self.gen_param_names(&sig.params);
|
||||
let kwonlyargcount = if sig.params.var_params.is_some() {
|
||||
sig.params.defaults.len()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
self.emit_params(
|
||||
sig.params.var_params.as_deref(),
|
||||
sig.params.defaults,
|
||||
&mut make_function_flag,
|
||||
);
|
||||
let mut flags = 0;
|
||||
if sig.params.var_params.is_some() {
|
||||
flags += CodeObjFlags::VarArgs as u32;
|
||||
|
@ -1431,6 +1479,7 @@ impl PyCodeGenerator {
|
|||
sig.params.guards,
|
||||
Some(name.clone()),
|
||||
params,
|
||||
kwonlyargcount as u32,
|
||||
sig.captured_names.clone(),
|
||||
flags,
|
||||
);
|
||||
|
@ -1464,7 +1513,10 @@ impl PyCodeGenerator {
|
|||
}
|
||||
// stack_dec: <code obj> + <name> -> <function>
|
||||
self.stack_dec();
|
||||
if make_function_flag & MakeFunctionFlags::Defaults as usize != 0 {
|
||||
if make_function_flag
|
||||
& (MakeFunctionFlags::Defaults as usize | MakeFunctionFlags::KwDefaults as usize)
|
||||
!= 0
|
||||
{
|
||||
self.stack_dec();
|
||||
}
|
||||
self.emit_store_instr(sig.ident, Name);
|
||||
|
@ -1474,18 +1526,16 @@ impl PyCodeGenerator {
|
|||
log!(info "entered {} ({lambda})", fn_name!());
|
||||
let mut make_function_flag = 0;
|
||||
let params = self.gen_param_names(&lambda.params);
|
||||
if !lambda.params.defaults.is_empty() {
|
||||
let defaults_len = lambda.params.defaults.len();
|
||||
lambda
|
||||
.params
|
||||
.defaults
|
||||
.into_iter()
|
||||
.for_each(|default| self.emit_expr(default.default_val));
|
||||
self.write_instr(BUILD_TUPLE);
|
||||
self.write_arg(defaults_len);
|
||||
self.stack_dec_n(defaults_len - 1);
|
||||
make_function_flag += MakeFunctionFlags::Defaults as usize;
|
||||
}
|
||||
let kwonlyargcount = if lambda.params.var_params.is_some() {
|
||||
lambda.params.defaults.len()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
self.emit_params(
|
||||
lambda.params.var_params.as_deref(),
|
||||
lambda.params.defaults,
|
||||
&mut make_function_flag,
|
||||
);
|
||||
let flags = if lambda.params.var_params.is_some() {
|
||||
CodeObjFlags::VarArgs as u32
|
||||
} else {
|
||||
|
@ -1496,6 +1546,7 @@ impl PyCodeGenerator {
|
|||
lambda.params.guards,
|
||||
Some(format!("<lambda_{}>", lambda.id).into()),
|
||||
params,
|
||||
kwonlyargcount as u32,
|
||||
lambda.captured_names.clone(),
|
||||
flags,
|
||||
);
|
||||
|
@ -1686,7 +1737,7 @@ impl PyCodeGenerator {
|
|||
let args = Args::pos_only(vec![PosArg::new(*bin.lhs), PosArg::new(*bin.rhs)], None);
|
||||
self.emit_push_null();
|
||||
self.emit_load_name_instr(Identifier::private("#UnionType"));
|
||||
self.emit_args_311(args, Name, false);
|
||||
self.emit_args_311(args, Name);
|
||||
return;
|
||||
}
|
||||
// short circuiting
|
||||
|
@ -2596,10 +2647,9 @@ impl PyCodeGenerator {
|
|||
self.emit_index_args(call.args);
|
||||
}
|
||||
other => {
|
||||
let is_py_api = other.is_py_api();
|
||||
self.emit_push_null();
|
||||
self.emit_expr(other);
|
||||
self.emit_args_311(call.args, Name, is_py_api);
|
||||
self.emit_args_311(call.args, Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2628,7 +2678,7 @@ impl PyCodeGenerator {
|
|||
"sum" if self.py_version.minor <= Some(7) && args.get_kw("start").is_some() => {
|
||||
self.load_builtins();
|
||||
self.emit_load_name_instr(Identifier::private("#sum"));
|
||||
self.emit_args_311(args, Name, true);
|
||||
self.emit_args_311(args, Name);
|
||||
}
|
||||
other if local.ref_t().is_poly_type_meta() && other != "classof" => {
|
||||
if self.py_version.minor <= Some(9) {
|
||||
|
@ -2636,7 +2686,7 @@ impl PyCodeGenerator {
|
|||
self.emit_load_name_instr(Identifier::private("#FakeGenericAlias"));
|
||||
let mut args = args;
|
||||
args.insert_pos(0, PosArg::new(Expr::Accessor(Accessor::Ident(local))));
|
||||
self.emit_args_311(args, Name, true);
|
||||
self.emit_args_311(args, Name);
|
||||
} else {
|
||||
self.emit_load_name_instr(local);
|
||||
self.emit_index_args(args);
|
||||
|
@ -2644,10 +2694,9 @@ impl PyCodeGenerator {
|
|||
}
|
||||
// "pyimport" | "py" are here
|
||||
_ => {
|
||||
let is_py_api = local.is_py_api();
|
||||
self.emit_push_null();
|
||||
self.emit_load_name_instr(local);
|
||||
self.emit_args_311(args, Name, is_py_api);
|
||||
self.emit_args_311(args, Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2676,13 +2725,12 @@ impl PyCodeGenerator {
|
|||
return self.emit_call_fake_method(obj, func_name, method_name, args);
|
||||
}
|
||||
let is_type = method_name.ref_t().is_poly_type_meta();
|
||||
let is_py_api = method_name.is_py_api();
|
||||
self.emit_expr(obj);
|
||||
self.emit_load_method_instr(method_name);
|
||||
if is_type {
|
||||
self.emit_index_args(args);
|
||||
} else {
|
||||
self.emit_args_311(args, BoundAttr, is_py_api);
|
||||
self.emit_args_311(args, BoundAttr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2712,7 +2760,7 @@ impl PyCodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_args_311(&mut self, mut args: Args, kind: AccessKind, is_py_api: bool) {
|
||||
fn emit_args_311(&mut self, mut args: Args, kind: AccessKind) {
|
||||
let argc = args.len();
|
||||
let pos_len = args.pos_args.len();
|
||||
let mut kws = Vec::with_capacity(args.kw_len());
|
||||
|
@ -2727,12 +2775,7 @@ impl PyCodeGenerator {
|
|||
}
|
||||
}
|
||||
while let Some(arg) = args.try_remove_kw(0) {
|
||||
let kw = if is_py_api {
|
||||
arg.keyword.content
|
||||
} else {
|
||||
escape_name(&arg.keyword.content, &VisibilityModifier::Private, 0, 0)
|
||||
};
|
||||
kws.push(ValueObj::Str(kw));
|
||||
kws.push(ValueObj::Str(arg.keyword.content));
|
||||
self.emit_expr(arg.expr);
|
||||
}
|
||||
let kwsc = if !kws.is_empty() {
|
||||
|
@ -2868,7 +2911,7 @@ impl PyCodeGenerator {
|
|||
self.emit_push_null();
|
||||
self.emit_load_name_instr(method_name);
|
||||
args.insert_pos(0, PosArg::new(obj));
|
||||
self.emit_args_311(args, Name, true);
|
||||
self.emit_args_311(args, Name);
|
||||
}
|
||||
|
||||
// assert takes 1 or 2 arguments (0: cond, 1: message)
|
||||
|
@ -3071,7 +3114,7 @@ impl PyCodeGenerator {
|
|||
/// Emits independent code blocks (e.g., linked other modules)
|
||||
fn emit_code(&mut self, code: Block) {
|
||||
let mut gen = self.inherit();
|
||||
let code = gen.emit_block(code, vec![], None, vec![], vec![], 0);
|
||||
let code = gen.emit_block(code, vec![], None, vec![], 0, vec![], 0);
|
||||
self.emit_load_const(code);
|
||||
}
|
||||
|
||||
|
@ -3363,6 +3406,7 @@ impl PyCodeGenerator {
|
|||
self.unit_size,
|
||||
self.py_version,
|
||||
vec![],
|
||||
0,
|
||||
Str::rc(self.cfg.input.enclosed_name()),
|
||||
&name,
|
||||
firstlineno,
|
||||
|
@ -3573,12 +3617,14 @@ impl PyCodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn emit_block(
|
||||
&mut self,
|
||||
block: Block,
|
||||
guards: Vec<GuardClause>,
|
||||
opt_name: Option<Str>,
|
||||
params: Vec<Str>,
|
||||
kwonlyargcount: u32,
|
||||
captured_names: Vec<Identifier>,
|
||||
flags: u32,
|
||||
) -> CodeObj {
|
||||
|
@ -3597,6 +3643,7 @@ impl PyCodeGenerator {
|
|||
self.unit_size,
|
||||
self.py_version,
|
||||
params,
|
||||
kwonlyargcount,
|
||||
Str::rc(self.cfg.input.enclosed_name()),
|
||||
name,
|
||||
firstlineno,
|
||||
|
@ -3848,6 +3895,7 @@ impl PyCodeGenerator {
|
|||
self.unit_size,
|
||||
self.py_version,
|
||||
vec![],
|
||||
0,
|
||||
Str::rc(self.cfg.input.enclosed_name()),
|
||||
"<module>",
|
||||
1,
|
||||
|
|
|
@ -1214,7 +1214,7 @@ impl Context {
|
|||
vec![],
|
||||
);
|
||||
let sig = Signature::Subr(sig);
|
||||
let call = Identifier::private("p!").call(Args::empty());
|
||||
let call = Identifier::public("p!").call(Args::empty());
|
||||
let block = Block::new(vec![Expr::Call(call)]);
|
||||
let body = DefBody::new(Token::DUMMY, block, DefId(0));
|
||||
let perform = Def::new(sig, body);
|
||||
|
|
|
@ -10,3 +10,10 @@
|
|||
.REVERSED = "\x1b[7m"
|
||||
.ATTR_RESET = "\x1b[0m"
|
||||
.RESET = "\x1b[m"
|
||||
|
||||
.cprint! *objs, color:=.GREEN =
|
||||
print! color, end:=""
|
||||
# print! *msg, end:=""
|
||||
for! objs, obj =>
|
||||
print! obj, end:=" "
|
||||
print! .RESET
|
||||
|
|
|
@ -37,6 +37,24 @@ pub fn consts_into_bytes(consts: Vec<ValueObj>, python_ver: PythonVersion) -> Ve
|
|||
tuple
|
||||
}
|
||||
|
||||
pub fn tuple_into_bytes(tup: &[ValueObj], python_ver: PythonVersion) -> Vec<u8> {
|
||||
let mut bytes = Vec::with_capacity(tup.len());
|
||||
if tup.len() <= u8::MAX as usize {
|
||||
bytes.push(DataTypePrefix::SmallTuple as u8);
|
||||
bytes.push(tup.len() as u8);
|
||||
for obj in tup.iter().cloned() {
|
||||
bytes.append(&mut obj.into_bytes(python_ver));
|
||||
}
|
||||
} else {
|
||||
bytes.push(DataTypePrefix::Tuple as u8);
|
||||
bytes.append(&mut (tup.len() as u32).to_le_bytes().to_vec());
|
||||
for obj in tup.iter().cloned() {
|
||||
bytes.append(&mut obj.into_bytes(python_ver));
|
||||
}
|
||||
}
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn jump_abs_addr(minor_ver: u8, op: u8, idx: usize, arg: usize) -> usize {
|
||||
match minor_ver {
|
||||
7..=9 => jump_abs_addr_309(Opcode309::try_from(op).unwrap(), idx, arg),
|
||||
|
@ -273,6 +291,7 @@ impl Default for CodeObj {
|
|||
impl CodeObj {
|
||||
pub fn empty<S: Into<Str>, T: Into<Str>>(
|
||||
params: Vec<Str>,
|
||||
kwonlyargcount: u32,
|
||||
filename: S,
|
||||
name: T,
|
||||
firstlineno: u32,
|
||||
|
@ -282,9 +301,9 @@ impl CodeObj {
|
|||
let var_args_defined = (flags & CodeObjFlags::VarArgs as u32 != 0) as u32;
|
||||
let kw_var_args_defined = (flags & CodeObjFlags::VarKeywords as u32 != 0) as u32;
|
||||
Self {
|
||||
argcount: params.len() as u32 - var_args_defined - kw_var_args_defined,
|
||||
argcount: params.len() as u32 - var_args_defined - kw_var_args_defined - kwonlyargcount,
|
||||
posonlyargcount: 0,
|
||||
kwonlyargcount: 0,
|
||||
kwonlyargcount,
|
||||
nlocals: params.len() as u32,
|
||||
stacksize: 2, // Seems to be the default in CPython, but not sure why
|
||||
flags, // CodeObjFlags::NoFree as u32,
|
||||
|
@ -820,7 +839,9 @@ impl CodeObj {
|
|||
CommonOpcode::MAKE_FUNCTION => {
|
||||
let flag = match arg {
|
||||
8 => "(closure)",
|
||||
// TODO:
|
||||
4 => "(annotations)",
|
||||
2 => "(kwdefaults)",
|
||||
1 => "(defaults)",
|
||||
_ => "",
|
||||
};
|
||||
write!(instrs, "{arg} {flag}").unwrap();
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::context::Context;
|
|||
|
||||
use self::value_set::inner_class;
|
||||
|
||||
use super::codeobj::CodeObj;
|
||||
use super::codeobj::{tuple_into_bytes, CodeObj};
|
||||
use super::constructors::{array_t, dict_t, refinement, set_t, tuple_t, unsized_array_t};
|
||||
use super::typaram::{OpKind, TyParam};
|
||||
use super::{ConstSubr, Field, HasType, Predicate, Type};
|
||||
|
@ -967,6 +967,12 @@ impl ValueObj {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tuple<V: Into<ValueObj>>(elems: Vec<V>) -> Self {
|
||||
ValueObj::Tuple(ArcArray::from(
|
||||
&elems.into_iter().map(Into::into).collect::<Vec<_>>()[..],
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: add Complex
|
||||
pub const fn is_num(&self) -> bool {
|
||||
matches!(
|
||||
|
@ -1093,25 +1099,7 @@ impl ValueObj {
|
|||
Self::Str(s) => str_into_bytes(s, false),
|
||||
Self::Bool(true) => vec![DataTypePrefix::True as u8],
|
||||
Self::Bool(false) => vec![DataTypePrefix::False as u8],
|
||||
// TODO: SmallTuple
|
||||
Self::Array(arr) => {
|
||||
let mut bytes = Vec::with_capacity(arr.len());
|
||||
bytes.push(DataTypePrefix::Tuple as u8);
|
||||
bytes.append(&mut (arr.len() as u32).to_le_bytes().to_vec());
|
||||
for obj in arr.iter().cloned() {
|
||||
bytes.append(&mut obj.into_bytes(python_ver));
|
||||
}
|
||||
bytes
|
||||
}
|
||||
Self::Tuple(tup) => {
|
||||
let mut bytes = Vec::with_capacity(tup.len());
|
||||
bytes.push(DataTypePrefix::Tuple as u8);
|
||||
bytes.append(&mut (tup.len() as u32).to_le_bytes().to_vec());
|
||||
for obj in tup.iter().cloned() {
|
||||
bytes.append(&mut obj.into_bytes(python_ver));
|
||||
}
|
||||
bytes
|
||||
}
|
||||
Self::Array(elems) | Self::Tuple(elems) => tuple_into_bytes(&elems, python_ver),
|
||||
Self::None => {
|
||||
vec![DataTypePrefix::None as u8]
|
||||
}
|
||||
|
|
|
@ -61,6 +61,10 @@ impl VarKind {
|
|||
}
|
||||
}
|
||||
|
||||
pub const fn nd_parameter(def_id: DefId) -> Self {
|
||||
Self::parameter(def_id, false, DefaultInfo::NonDefault)
|
||||
}
|
||||
|
||||
pub const fn has_default(&self) -> bool {
|
||||
match self {
|
||||
Self::Parameter { default, .. } => default.has_default(),
|
||||
|
|
7
examples/use_ansicolor.er
Normal file
7
examples/use_ansicolor.er
Normal file
|
@ -0,0 +1,7 @@
|
|||
ac = import "ansicolor"
|
||||
|
||||
print! "start"
|
||||
print! ac.RED + "hello" + ac.RESET
|
||||
print! "end"
|
||||
|
||||
ac.cprint! "hello", color:=ac.RED
|
|
@ -1,3 +1,3 @@
|
|||
kw_var(**x: Int) = x["::a"] + x["::b"]
|
||||
kw_var(**x: Int) = x["a"] + x["b"]
|
||||
|
||||
assert kw_var(a:=1, b:=2) == 3
|
||||
|
|
|
@ -121,6 +121,11 @@ fn exec_empty_check() -> Result<(), ()> {
|
|||
expect_success("tests/should_ok/dyn_type_check.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_use_ansicolor() -> Result<(), ()> {
|
||||
expect_success("examples/use_ansicolor.er", 0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_erg_compiler() -> Result<(), ()> {
|
||||
let py_command = opt_which_python().unwrap();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue