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