mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 04:24:43 +00:00
Add user-defined var-params function
This commit is contained in:
parent
4b08fd21a2
commit
23a7e2caf3
28 changed files with 526 additions and 211 deletions
|
@ -228,10 +228,13 @@ impl ASTSemanticState {
|
||||||
|
|
||||||
fn gen_from_args(&mut self, args: Args) -> Vec<SemanticToken> {
|
fn gen_from_args(&mut self, args: Args) -> Vec<SemanticToken> {
|
||||||
let mut tokens = vec![];
|
let mut tokens = vec![];
|
||||||
let (pos_args, kw_args, ..) = args.deconstruct();
|
let (pos_args, var_args, kw_args, ..) = args.deconstruct();
|
||||||
for arg in pos_args {
|
for arg in pos_args {
|
||||||
tokens.extend(self.gen_from_expr(arg.expr));
|
tokens.extend(self.gen_from_expr(arg.expr));
|
||||||
}
|
}
|
||||||
|
if let Some(var_args) = var_args {
|
||||||
|
tokens.extend(self.gen_from_expr(var_args.expr));
|
||||||
|
}
|
||||||
for arg in kw_args {
|
for arg in kw_args {
|
||||||
tokens.extend(self.gen_from_expr(arg.expr));
|
tokens.extend(self.gen_from_expr(arg.expr));
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,11 +117,12 @@ impl PyCodeGenUnit {
|
||||||
filename: S,
|
filename: S,
|
||||||
name: T,
|
name: T,
|
||||||
firstlineno: u32,
|
firstlineno: u32,
|
||||||
|
flags: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
py_version,
|
py_version,
|
||||||
codeobj: CodeObj::empty(params, filename, name, firstlineno),
|
codeobj: CodeObj::empty(params, filename, name, firstlineno, flags),
|
||||||
stack_len: 0,
|
stack_len: 0,
|
||||||
prev_lineno: firstlineno,
|
prev_lineno: firstlineno,
|
||||||
lasti: 0,
|
lasti: 0,
|
||||||
|
@ -878,7 +879,7 @@ impl PyCodeGenerator {
|
||||||
.non_defaults
|
.non_defaults
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
|
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
|
||||||
.chain(if let Some(var_args) = ¶ms.var_args {
|
.chain(if let Some(var_args) = ¶ms.var_params {
|
||||||
vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")]
|
vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")]
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -1048,6 +1049,7 @@ impl PyCodeGenerator {
|
||||||
Str::rc(self.cfg.input.enclosed_name()),
|
Str::rc(self.cfg.input.enclosed_name()),
|
||||||
&name,
|
&name,
|
||||||
firstlineno,
|
firstlineno,
|
||||||
|
0,
|
||||||
));
|
));
|
||||||
let mod_name = self.toplevel_block_codeobj().name.clone();
|
let mod_name = self.toplevel_block_codeobj().name.clone();
|
||||||
self.emit_load_const(mod_name);
|
self.emit_load_const(mod_name);
|
||||||
|
@ -1116,6 +1118,7 @@ impl PyCodeGenerator {
|
||||||
Str::rc(self.cfg.input.enclosed_name()),
|
Str::rc(self.cfg.input.enclosed_name()),
|
||||||
ident.inspect(),
|
ident.inspect(),
|
||||||
ident.ln_begin().unwrap(),
|
ident.ln_begin().unwrap(),
|
||||||
|
0,
|
||||||
));
|
));
|
||||||
self.emit_load_const(ValueObj::None);
|
self.emit_load_const(ValueObj::None);
|
||||||
self.write_instr(RETURN_VALUE);
|
self.write_instr(RETURN_VALUE);
|
||||||
|
@ -1251,7 +1254,12 @@ impl PyCodeGenerator {
|
||||||
self.stack_dec_n(defaults_len - 1);
|
self.stack_dec_n(defaults_len - 1);
|
||||||
make_function_flag += MakeFunctionFlags::Defaults as usize;
|
make_function_flag += MakeFunctionFlags::Defaults as usize;
|
||||||
}
|
}
|
||||||
let code = self.emit_block(body.block, Some(name.clone()), params);
|
let flags = if sig.params.var_params.is_some() {
|
||||||
|
CodeObjFlags::VarArgs as u32
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let code = self.emit_block(body.block, Some(name.clone()), params, flags);
|
||||||
// code.flags += CodeObjFlags::Optimized as u32;
|
// code.flags += CodeObjFlags::Optimized as u32;
|
||||||
self.register_cellvars(&mut make_function_flag);
|
self.register_cellvars(&mut make_function_flag);
|
||||||
self.emit_load_const(code);
|
self.emit_load_const(code);
|
||||||
|
@ -1290,7 +1298,12 @@ impl PyCodeGenerator {
|
||||||
self.stack_dec_n(defaults_len - 1);
|
self.stack_dec_n(defaults_len - 1);
|
||||||
make_function_flag += MakeFunctionFlags::Defaults as usize;
|
make_function_flag += MakeFunctionFlags::Defaults as usize;
|
||||||
}
|
}
|
||||||
let code = self.emit_block(lambda.body, Some("<lambda>".into()), params);
|
let flags = if lambda.params.var_params.is_some() {
|
||||||
|
CodeObjFlags::VarArgs as u32
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let code = self.emit_block(lambda.body, Some("<lambda>".into()), params, flags);
|
||||||
self.register_cellvars(&mut make_function_flag);
|
self.register_cellvars(&mut make_function_flag);
|
||||||
self.emit_load_const(code);
|
self.emit_load_const(code);
|
||||||
if self.py_version.minor < Some(11) {
|
if self.py_version.minor < Some(11) {
|
||||||
|
@ -2650,7 +2663,7 @@ impl PyCodeGenerator {
|
||||||
Expr::Dict(dict) => self.emit_dict(dict),
|
Expr::Dict(dict) => self.emit_dict(dict),
|
||||||
Expr::Record(rec) => self.emit_record(rec),
|
Expr::Record(rec) => self.emit_record(rec),
|
||||||
Expr::Code(code) => {
|
Expr::Code(code) => {
|
||||||
let code = self.emit_block(code, None, vec![]);
|
let code = self.emit_block(code, None, vec![], 0);
|
||||||
self.emit_load_const(code);
|
self.emit_load_const(code);
|
||||||
}
|
}
|
||||||
Expr::Compound(chunks) => self.emit_compound(chunks),
|
Expr::Compound(chunks) => self.emit_compound(chunks),
|
||||||
|
@ -2679,7 +2692,7 @@ impl PyCodeGenerator {
|
||||||
Expr::Dict(dict) => self.emit_dict(dict),
|
Expr::Dict(dict) => self.emit_dict(dict),
|
||||||
Expr::Record(rec) => self.emit_record(rec),
|
Expr::Record(rec) => self.emit_record(rec),
|
||||||
Expr::Code(code) => {
|
Expr::Code(code) => {
|
||||||
let code = self.emit_block(code, None, vec![]);
|
let code = self.emit_block(code, None, vec![], 0);
|
||||||
self.emit_load_const(code);
|
self.emit_load_const(code);
|
||||||
}
|
}
|
||||||
Expr::Compound(chunks) => self.emit_compound(chunks),
|
Expr::Compound(chunks) => self.emit_compound(chunks),
|
||||||
|
@ -2738,6 +2751,7 @@ impl PyCodeGenerator {
|
||||||
Str::rc(self.cfg.input.enclosed_name()),
|
Str::rc(self.cfg.input.enclosed_name()),
|
||||||
&name,
|
&name,
|
||||||
firstlineno,
|
firstlineno,
|
||||||
|
0,
|
||||||
));
|
));
|
||||||
let init_stack_len = self.stack_len();
|
let init_stack_len = self.stack_len();
|
||||||
let mod_name = self.toplevel_block_codeobj().name.clone();
|
let mod_name = self.toplevel_block_codeobj().name.clone();
|
||||||
|
@ -2904,7 +2918,13 @@ impl PyCodeGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {
|
fn emit_block(
|
||||||
|
&mut self,
|
||||||
|
block: Block,
|
||||||
|
opt_name: Option<Str>,
|
||||||
|
params: Vec<Str>,
|
||||||
|
flags: u32,
|
||||||
|
) -> CodeObj {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
self.unit_size += 1;
|
self.unit_size += 1;
|
||||||
let name = if let Some(name) = opt_name {
|
let name = if let Some(name) = opt_name {
|
||||||
|
@ -2923,6 +2943,7 @@ impl PyCodeGenerator {
|
||||||
Str::rc(self.cfg.input.enclosed_name()),
|
Str::rc(self.cfg.input.enclosed_name()),
|
||||||
name,
|
name,
|
||||||
firstlineno,
|
firstlineno,
|
||||||
|
flags,
|
||||||
));
|
));
|
||||||
let idx_copy_free_vars = if self.py_version.minor >= Some(11) {
|
let idx_copy_free_vars = if self.py_version.minor >= Some(11) {
|
||||||
let idx_copy_free_vars = self.lasti();
|
let idx_copy_free_vars = self.lasti();
|
||||||
|
@ -3115,6 +3136,7 @@ impl PyCodeGenerator {
|
||||||
Str::rc(self.cfg.input.enclosed_name()),
|
Str::rc(self.cfg.input.enclosed_name()),
|
||||||
"<module>",
|
"<module>",
|
||||||
1,
|
1,
|
||||||
|
0,
|
||||||
));
|
));
|
||||||
if self.py_version.minor >= Some(11) {
|
if self.py_version.minor >= Some(11) {
|
||||||
self.write_instr(Opcode311::RESUME);
|
self.write_instr(Opcode311::RESUME);
|
||||||
|
|
|
@ -27,6 +27,7 @@ use crate::ty::typaram::{OpKind, TyParam};
|
||||||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||||
use crate::ty::{ConstSubr, HasType, Predicate, SubrKind, Type, UserConstSubr, ValueArgs};
|
use crate::ty::{ConstSubr, HasType, Predicate, SubrKind, Type, UserConstSubr, ValueArgs};
|
||||||
|
|
||||||
|
use crate::context::instantiate::ParamKind;
|
||||||
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
|
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
|
||||||
use crate::error::{EvalError, EvalErrors, EvalResult, SingleEvalResult};
|
use crate::error::{EvalError, EvalErrors, EvalResult, SingleEvalResult};
|
||||||
|
|
||||||
|
@ -451,19 +452,19 @@ impl Context {
|
||||||
let pt = self.instantiate_param_ty(
|
let pt = self.instantiate_param_ty(
|
||||||
sig,
|
sig,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
&mut tmp_tv_cache,
|
&mut tmp_tv_cache,
|
||||||
RegistrationMode::Normal,
|
RegistrationMode::Normal,
|
||||||
|
ParamKind::NonDefault,
|
||||||
)?;
|
)?;
|
||||||
non_default_params.push(pt);
|
non_default_params.push(pt);
|
||||||
}
|
}
|
||||||
let var_params = if let Some(p) = lambda.sig.params.var_args.as_ref() {
|
let var_params = if let Some(p) = lambda.sig.params.var_params.as_ref() {
|
||||||
let pt = self.instantiate_param_ty(
|
let pt = self.instantiate_param_ty(
|
||||||
p,
|
p,
|
||||||
None,
|
None,
|
||||||
None,
|
|
||||||
&mut tmp_tv_cache,
|
&mut tmp_tv_cache,
|
||||||
RegistrationMode::Normal,
|
RegistrationMode::Normal,
|
||||||
|
ParamKind::VarParams,
|
||||||
)?;
|
)?;
|
||||||
Some(pt)
|
Some(pt)
|
||||||
} else {
|
} else {
|
||||||
|
@ -474,10 +475,10 @@ impl Context {
|
||||||
let expr = self.eval_const_expr(&sig.default_val)?;
|
let expr = self.eval_const_expr(&sig.default_val)?;
|
||||||
let pt = self.instantiate_param_ty(
|
let pt = self.instantiate_param_ty(
|
||||||
&sig.sig,
|
&sig.sig,
|
||||||
Some(expr.t()),
|
|
||||||
None,
|
None,
|
||||||
&mut tmp_tv_cache,
|
&mut tmp_tv_cache,
|
||||||
RegistrationMode::Normal,
|
RegistrationMode::Normal,
|
||||||
|
ParamKind::Default(expr.t()),
|
||||||
)?;
|
)?;
|
||||||
default_params.push(pt);
|
default_params.push(pt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ use crate::{feature_error, hir};
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
|
use super::instantiate::ParamKind;
|
||||||
use super::{ContextKind, MethodInfo};
|
use super::{ContextKind, MethodInfo};
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
@ -274,6 +275,7 @@ impl Context {
|
||||||
None,
|
None,
|
||||||
&mut dummy_tv_cache,
|
&mut dummy_tv_cache,
|
||||||
Normal,
|
Normal,
|
||||||
|
ParamKind::NonDefault,
|
||||||
)?;
|
)?;
|
||||||
union_pat_t = self.union(&union_pat_t, &rhs);
|
union_pat_t = self.union(&union_pat_t, &rhs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,38 @@ use crate::unreachable_error;
|
||||||
use TyParamOrdering::*;
|
use TyParamOrdering::*;
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
|
||||||
use crate::context::{Context, RegistrationMode};
|
use crate::context::{Context, DefaultInfo, RegistrationMode};
|
||||||
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
|
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
|
||||||
use crate::hir;
|
use crate::hir;
|
||||||
use crate::AccessKind;
|
use crate::AccessKind;
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ParamKind {
|
||||||
|
NonDefault,
|
||||||
|
Default(Type),
|
||||||
|
VarParams,
|
||||||
|
KwParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParamKind {
|
||||||
|
pub const fn is_var_params(&self) -> bool {
|
||||||
|
matches!(self, ParamKind::VarParams)
|
||||||
|
}
|
||||||
|
pub const fn is_kw_params(&self) -> bool {
|
||||||
|
matches!(self, ParamKind::KwParams)
|
||||||
|
}
|
||||||
|
pub const fn is_default(&self) -> bool {
|
||||||
|
matches!(self, ParamKind::Default(_))
|
||||||
|
}
|
||||||
|
pub const fn default_info(&self) -> DefaultInfo {
|
||||||
|
match self {
|
||||||
|
ParamKind::Default(_) => DefaultInfo::WithDefault,
|
||||||
|
_ => DefaultInfo::NonDefault,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Context for instantiating a quantified type
|
/// Context for instantiating a quantified type
|
||||||
/// For example, cloning each type variable of quantified type `?T -> ?T` would result in `?1 -> ?2`.
|
/// For example, cloning each type variable of quantified type `?T -> ?T` would result in `?1 -> ?2`.
|
||||||
/// To avoid this, an environment to store type variables is needed, which is `TyVarCache`.
|
/// To avoid this, an environment to store type variables is needed, which is `TyVarCache`.
|
||||||
|
@ -252,7 +278,13 @@ impl Context {
|
||||||
let opt_decl_t = opt_decl_sig_t
|
let opt_decl_t = opt_decl_sig_t
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|subr| subr.non_default_params.get(n));
|
.and_then(|subr| subr.non_default_params.get(n));
|
||||||
match self.instantiate_param_ty(param, None, opt_decl_t, &mut tmp_tv_cache, mode) {
|
match self.instantiate_param_ty(
|
||||||
|
param,
|
||||||
|
opt_decl_t,
|
||||||
|
&mut tmp_tv_cache,
|
||||||
|
mode,
|
||||||
|
ParamKind::NonDefault,
|
||||||
|
) {
|
||||||
Ok(t) => non_defaults.push(t),
|
Ok(t) => non_defaults.push(t),
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
|
@ -260,16 +292,16 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let var_args = if let Some(var_args) = sig.params.var_args.as_ref() {
|
let var_args = if let Some(var_args) = sig.params.var_params.as_ref() {
|
||||||
let opt_decl_t = opt_decl_sig_t
|
let opt_decl_t = opt_decl_sig_t
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
|
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
|
||||||
let pt = match self.instantiate_param_ty(
|
let pt = match self.instantiate_param_ty(
|
||||||
var_args,
|
var_args,
|
||||||
None,
|
|
||||||
opt_decl_t,
|
opt_decl_t,
|
||||||
&mut tmp_tv_cache,
|
&mut tmp_tv_cache,
|
||||||
mode,
|
mode,
|
||||||
|
ParamKind::VarParams,
|
||||||
) {
|
) {
|
||||||
Ok(pt) => pt,
|
Ok(pt) => pt,
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
|
@ -288,10 +320,10 @@ impl Context {
|
||||||
.and_then(|subr| subr.default_params.get(n));
|
.and_then(|subr| subr.default_params.get(n));
|
||||||
match self.instantiate_param_ty(
|
match self.instantiate_param_ty(
|
||||||
&p.sig,
|
&p.sig,
|
||||||
Some(default_t),
|
|
||||||
opt_decl_t,
|
opt_decl_t,
|
||||||
&mut tmp_tv_cache,
|
&mut tmp_tv_cache,
|
||||||
mode,
|
mode,
|
||||||
|
ParamKind::Default(default_t),
|
||||||
) {
|
) {
|
||||||
Ok(t) => defaults.push(t),
|
Ok(t) => defaults.push(t),
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
|
@ -345,6 +377,7 @@ impl Context {
|
||||||
opt_decl_t: Option<&ParamTy>,
|
opt_decl_t: Option<&ParamTy>,
|
||||||
tmp_tv_cache: &mut TyVarCache,
|
tmp_tv_cache: &mut TyVarCache,
|
||||||
mode: RegistrationMode,
|
mode: RegistrationMode,
|
||||||
|
kind: ParamKind,
|
||||||
) -> TyCheckResult<Type> {
|
) -> TyCheckResult<Type> {
|
||||||
let spec_t = if let Some(spec_with_op) = &sig.t_spec {
|
let spec_t = if let Some(spec_with_op) = &sig.t_spec {
|
||||||
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_cache, mode, false)?
|
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_cache, mode, false)?
|
||||||
|
@ -365,15 +398,28 @@ impl Context {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(decl_pt) = opt_decl_t {
|
if let Some(decl_pt) = opt_decl_t {
|
||||||
self.sub_unify(
|
if kind.is_var_params() {
|
||||||
decl_pt.typ(),
|
let spec_t = unknown_len_array_t(spec_t.clone());
|
||||||
&spec_t,
|
self.sub_unify(
|
||||||
sig.t_spec
|
decl_pt.typ(),
|
||||||
.as_ref()
|
&spec_t,
|
||||||
.map(|s| s.loc())
|
sig.t_spec
|
||||||
.unwrap_or_else(|| sig.loc()),
|
.as_ref()
|
||||||
None,
|
.map(|s| s.loc())
|
||||||
)?;
|
.unwrap_or_else(|| sig.loc()),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
self.sub_unify(
|
||||||
|
decl_pt.typ(),
|
||||||
|
&spec_t,
|
||||||
|
sig.t_spec
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.loc())
|
||||||
|
.unwrap_or_else(|| sig.loc()),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(spec_t)
|
Ok(spec_t)
|
||||||
}
|
}
|
||||||
|
@ -381,17 +427,18 @@ impl Context {
|
||||||
pub(crate) fn instantiate_param_ty(
|
pub(crate) fn instantiate_param_ty(
|
||||||
&self,
|
&self,
|
||||||
sig: &NonDefaultParamSignature,
|
sig: &NonDefaultParamSignature,
|
||||||
opt_default_t: Option<Type>,
|
|
||||||
opt_decl_t: Option<&ParamTy>,
|
opt_decl_t: Option<&ParamTy>,
|
||||||
tmp_tv_cache: &mut TyVarCache,
|
tmp_tv_cache: &mut TyVarCache,
|
||||||
mode: RegistrationMode,
|
mode: RegistrationMode,
|
||||||
|
kind: ParamKind,
|
||||||
) -> TyCheckResult<ParamTy> {
|
) -> TyCheckResult<ParamTy> {
|
||||||
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode)?;
|
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode, kind.clone())?;
|
||||||
match (sig.inspect(), opt_default_t) {
|
match (sig.inspect(), kind) {
|
||||||
(Some(name), Some(default_t)) => Ok(ParamTy::kw_default(name.clone(), t, default_t)),
|
(Some(name), ParamKind::Default(default_t)) => {
|
||||||
(Some(name), None) => Ok(ParamTy::kw(name.clone(), t)),
|
Ok(ParamTy::kw_default(name.clone(), t, default_t))
|
||||||
(None, None) => Ok(ParamTy::anonymous(t)),
|
}
|
||||||
_ => unreachable!(),
|
(Some(name), _) => Ok(ParamTy::kw(name.clone(), t)),
|
||||||
|
(None, _) => Ok(ParamTy::anonymous(t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,8 +966,8 @@ impl Context {
|
||||||
let non_defaults = try_map_mut(subr.non_defaults.iter(), |p| {
|
let non_defaults = try_map_mut(subr.non_defaults.iter(), |p| {
|
||||||
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
|
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
|
||||||
})?;
|
})?;
|
||||||
let var_args = subr
|
let var_params = subr
|
||||||
.var_args
|
.var_params
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
|
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
|
||||||
|
@ -947,7 +994,7 @@ impl Context {
|
||||||
Ok(subr_t(
|
Ok(subr_t(
|
||||||
SubrKind::from(subr.arrow.kind),
|
SubrKind::from(subr.arrow.kind),
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_args,
|
var_params,
|
||||||
defaults,
|
defaults,
|
||||||
return_t,
|
return_t,
|
||||||
))
|
))
|
||||||
|
|
|
@ -17,7 +17,9 @@ use erg_common::{enum_unwrap, get_hash, log, set};
|
||||||
use ast::{Decorator, DefId, Identifier, OperationKind, SimpleTypeSpec, VarName};
|
use ast::{Decorator, DefId, Identifier, OperationKind, SimpleTypeSpec, VarName};
|
||||||
use erg_parser::ast::{self, ConstIdentifier};
|
use erg_parser::ast::{self, ConstIdentifier};
|
||||||
|
|
||||||
use crate::ty::constructors::{free_var, func, func0, func1, proc, ref_, ref_mut, v_enum};
|
use crate::ty::constructors::{
|
||||||
|
free_var, func, func0, func1, proc, ref_, ref_mut, unknown_len_array_t, v_enum,
|
||||||
|
};
|
||||||
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
||||||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||||
use crate::ty::{HasType, ParamTy, SubrType, Type};
|
use crate::ty::{HasType, ParamTy, SubrType, Type};
|
||||||
|
@ -37,7 +39,7 @@ use Mutability::*;
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
use super::instantiate::TyVarCache;
|
use super::instantiate::{ParamKind, TyVarCache};
|
||||||
|
|
||||||
const UBAR: &Str = &Str::ever("_");
|
const UBAR: &Str = &Str::ever("_");
|
||||||
|
|
||||||
|
@ -240,14 +242,15 @@ impl Context {
|
||||||
fn assign_param(
|
fn assign_param(
|
||||||
&mut self,
|
&mut self,
|
||||||
sig: &ast::NonDefaultParamSignature,
|
sig: &ast::NonDefaultParamSignature,
|
||||||
default_val_exists: bool,
|
|
||||||
opt_decl_t: Option<&ParamTy>,
|
opt_decl_t: Option<&ParamTy>,
|
||||||
|
kind: ParamKind,
|
||||||
) -> TyCheckResult<()> {
|
) -> TyCheckResult<()> {
|
||||||
let vis = if cfg!(feature = "py_compatible") {
|
let vis = if cfg!(feature = "py_compatible") {
|
||||||
Public
|
Public
|
||||||
} else {
|
} else {
|
||||||
Private
|
Private
|
||||||
};
|
};
|
||||||
|
let default = kind.default_info();
|
||||||
match &sig.pat {
|
match &sig.pat {
|
||||||
// Literal patterns will be desugared to discard patterns
|
// Literal patterns will be desugared to discard patterns
|
||||||
ast::ParamPattern::Lit(_) => unreachable!(),
|
ast::ParamPattern::Lit(_) => unreachable!(),
|
||||||
|
@ -257,6 +260,7 @@ impl Context {
|
||||||
opt_decl_t,
|
opt_decl_t,
|
||||||
&mut TyVarCache::new(self.level, self),
|
&mut TyVarCache::new(self.level, self),
|
||||||
Normal,
|
Normal,
|
||||||
|
kind,
|
||||||
)?;
|
)?;
|
||||||
let def_id = DefId(get_hash(&(&self.name, "_")));
|
let def_id = DefId(get_hash(&(&self.name, "_")));
|
||||||
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault);
|
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault);
|
||||||
|
@ -288,8 +292,13 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
// ok, not defined
|
// ok, not defined
|
||||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||||
let spec_t =
|
let spec_t = self.instantiate_param_sig_t(
|
||||||
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
|
sig,
|
||||||
|
opt_decl_t,
|
||||||
|
&mut dummy_tv_cache,
|
||||||
|
Normal,
|
||||||
|
kind,
|
||||||
|
)?;
|
||||||
if &name.inspect()[..] == "self" {
|
if &name.inspect()[..] == "self" {
|
||||||
if let Some(self_t) = self.rec_get_self_t() {
|
if let Some(self_t) = self.rec_get_self_t() {
|
||||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||||
|
@ -297,11 +306,6 @@ impl Context {
|
||||||
log!(err "self_t is None");
|
log!(err "self_t is None");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let default = if default_val_exists {
|
|
||||||
DefaultInfo::WithDefault
|
|
||||||
} else {
|
|
||||||
DefaultInfo::NonDefault
|
|
||||||
};
|
|
||||||
let def_id = DefId(get_hash(&(&self.name, name)));
|
let def_id = DefId(get_hash(&(&self.name, name)));
|
||||||
let kind = VarKind::parameter(def_id, default);
|
let kind = VarKind::parameter(def_id, default);
|
||||||
let muty = Mutability::from(&name.inspect()[..]);
|
let muty = Mutability::from(&name.inspect()[..]);
|
||||||
|
@ -334,8 +338,13 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
// ok, not defined
|
// ok, not defined
|
||||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||||
let spec_t =
|
let spec_t = self.instantiate_param_sig_t(
|
||||||
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
|
sig,
|
||||||
|
opt_decl_t,
|
||||||
|
&mut dummy_tv_cache,
|
||||||
|
Normal,
|
||||||
|
kind,
|
||||||
|
)?;
|
||||||
if &name.inspect()[..] == "self" {
|
if &name.inspect()[..] == "self" {
|
||||||
if let Some(self_t) = self.rec_get_self_t() {
|
if let Some(self_t) = self.rec_get_self_t() {
|
||||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||||
|
@ -344,11 +353,6 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let spec_t = ref_(spec_t);
|
let spec_t = ref_(spec_t);
|
||||||
let default = if default_val_exists {
|
|
||||||
DefaultInfo::WithDefault
|
|
||||||
} else {
|
|
||||||
DefaultInfo::NonDefault
|
|
||||||
};
|
|
||||||
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
|
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
|
||||||
let vi = VarInfo::new(
|
let vi = VarInfo::new(
|
||||||
spec_t,
|
spec_t,
|
||||||
|
@ -379,8 +383,13 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
// ok, not defined
|
// ok, not defined
|
||||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||||
let spec_t =
|
let spec_t = self.instantiate_param_sig_t(
|
||||||
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
|
sig,
|
||||||
|
opt_decl_t,
|
||||||
|
&mut dummy_tv_cache,
|
||||||
|
Normal,
|
||||||
|
kind,
|
||||||
|
)?;
|
||||||
if &name.inspect()[..] == "self" {
|
if &name.inspect()[..] == "self" {
|
||||||
if let Some(self_t) = self.rec_get_self_t() {
|
if let Some(self_t) = self.rec_get_self_t() {
|
||||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||||
|
@ -389,11 +398,6 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let spec_t = ref_mut(spec_t.clone(), Some(spec_t));
|
let spec_t = ref_mut(spec_t.clone(), Some(spec_t));
|
||||||
let default = if default_val_exists {
|
|
||||||
DefaultInfo::WithDefault
|
|
||||||
} else {
|
|
||||||
DefaultInfo::NonDefault
|
|
||||||
};
|
|
||||||
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
|
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
|
||||||
let vi = VarInfo::new(
|
let vi = VarInfo::new(
|
||||||
spec_t,
|
spec_t,
|
||||||
|
@ -433,7 +437,18 @@ impl Context {
|
||||||
.iter()
|
.iter()
|
||||||
.zip(decl_subr_t.non_default_params.iter())
|
.zip(decl_subr_t.non_default_params.iter())
|
||||||
{
|
{
|
||||||
if let Err(es) = self.assign_param(sig, false, Some(pt)) {
|
if let Err(es) = self.assign_param(sig, Some(pt), ParamKind::NonDefault) {
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(var_params) = ¶ms.var_params {
|
||||||
|
if let Some(pt) = &decl_subr_t.var_params {
|
||||||
|
let pt = pt.clone().map_type(unknown_len_array_t);
|
||||||
|
if let Err(es) = self.assign_param(var_params, Some(&pt), ParamKind::VarParams)
|
||||||
|
{
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
|
} else if let Err(es) = self.assign_param(var_params, None, ParamKind::VarParams) {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,18 +457,22 @@ impl Context {
|
||||||
.iter()
|
.iter()
|
||||||
.zip(decl_subr_t.default_params.iter())
|
.zip(decl_subr_t.default_params.iter())
|
||||||
{
|
{
|
||||||
if let Err(es) = self.assign_param(&sig.sig, true, Some(pt)) {
|
if let Err(es) =
|
||||||
|
self.assign_param(&sig.sig, Some(pt), ParamKind::Default(sig.default_val.t()))
|
||||||
|
{
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for sig in params.non_defaults.iter() {
|
for sig in params.non_defaults.iter() {
|
||||||
if let Err(es) = self.assign_param(sig, false, None) {
|
if let Err(es) = self.assign_param(sig, None, ParamKind::NonDefault) {
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for sig in params.defaults.iter() {
|
for sig in params.defaults.iter() {
|
||||||
if let Err(es) = self.assign_param(&sig.sig, true, None) {
|
if let Err(es) =
|
||||||
|
self.assign_param(&sig.sig, None, ParamKind::Default(sig.default_val.t()))
|
||||||
|
{
|
||||||
errs.extend(es);
|
errs.extend(es);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,7 +255,7 @@ impl SideEffectChecker {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((var_arg, va_type)) = sig.params.var_args.as_ref().zip(t.var_params()) {
|
if let Some((var_arg, va_type)) = sig.params.var_params.as_ref().zip(t.var_params()) {
|
||||||
if va_type.typ().is_procedure() && !var_arg.inspect().unwrap().ends_with('!') {
|
if va_type.typ().is_procedure() && !var_arg.inspect().unwrap().ends_with('!') {
|
||||||
self.errs.push(EffectError::proc_assign_error(
|
self.errs.push(EffectError::proc_assign_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
|
|
@ -1637,7 +1637,7 @@ impl DefaultParamSignature {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub non_defaults: Vec<NonDefaultParamSignature>,
|
pub non_defaults: Vec<NonDefaultParamSignature>,
|
||||||
pub var_args: Option<Box<NonDefaultParamSignature>>,
|
pub var_params: Option<Box<NonDefaultParamSignature>>,
|
||||||
pub defaults: Vec<DefaultParamSignature>,
|
pub defaults: Vec<DefaultParamSignature>,
|
||||||
pub parens: Option<(Token, Token)>,
|
pub parens: Option<(Token, Token)>,
|
||||||
}
|
}
|
||||||
|
@ -1648,7 +1648,7 @@ impl fmt::Display for Params {
|
||||||
f,
|
f,
|
||||||
"({}, {}, {})",
|
"({}, {}, {})",
|
||||||
fmt_vec(&self.non_defaults),
|
fmt_vec(&self.non_defaults),
|
||||||
fmt_option!(pre "...", &self.var_args),
|
fmt_option!(pre "*", &self.var_params),
|
||||||
fmt_vec(&self.defaults)
|
fmt_vec(&self.defaults)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1659,7 +1659,7 @@ impl NoTypeDisplay for Params {
|
||||||
format!(
|
format!(
|
||||||
"({}, {}, {})",
|
"({}, {}, {})",
|
||||||
fmt_vec(&self.non_defaults),
|
fmt_vec(&self.non_defaults),
|
||||||
fmt_option!(pre "...", &self.var_args),
|
fmt_option!(pre "*", &self.var_params),
|
||||||
self.defaults
|
self.defaults
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.to_string_notype())
|
.map(|p| p.to_string_notype())
|
||||||
|
@ -1678,7 +1678,7 @@ impl Locational for Params {
|
||||||
}
|
}
|
||||||
match (
|
match (
|
||||||
self.non_defaults.first(),
|
self.non_defaults.first(),
|
||||||
self.var_args.as_ref(),
|
self.var_params.as_ref(),
|
||||||
self.defaults.last(),
|
self.defaults.last(),
|
||||||
) {
|
) {
|
||||||
(Some(l), _, Some(r)) => Location::concat(l, r),
|
(Some(l), _, Some(r)) => Location::concat(l, r),
|
||||||
|
@ -1714,7 +1714,7 @@ impl Params {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_args,
|
var_params: var_args,
|
||||||
defaults,
|
defaults,
|
||||||
parens,
|
parens,
|
||||||
}
|
}
|
||||||
|
@ -1723,14 +1723,19 @@ impl Params {
|
||||||
pub const fn ref_deconstruct(&self) -> RefRawParams {
|
pub const fn ref_deconstruct(&self) -> RefRawParams {
|
||||||
(
|
(
|
||||||
&self.non_defaults,
|
&self.non_defaults,
|
||||||
&self.var_args,
|
&self.var_params,
|
||||||
&self.defaults,
|
&self.defaults,
|
||||||
&self.parens,
|
&self.parens,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> RawParams {
|
pub fn deconstruct(self) -> RawParams {
|
||||||
(self.non_defaults, self.var_args, self.defaults, self.parens)
|
(
|
||||||
|
self.non_defaults,
|
||||||
|
self.var_params,
|
||||||
|
self.defaults,
|
||||||
|
self.parens,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -92,7 +92,7 @@ Parameters:
|
||||||
* `flush`:
|
* `flush`:
|
||||||
ストリームを強制的にフラッシュするかどうか。
|
ストリームを強制的にフラッシュするかどうか。
|
||||||
'''
|
'''
|
||||||
.print!: (args: Ref(Obj), sep := Str, end := Str, file := Writable!, flush := Bool) => NoneType
|
.print!: (*args: Ref(Obj), sep := Str, end := Str, file := Writable!, flush := Bool) => NoneType
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Open file and return a stream.
|
Open file and return a stream.
|
||||||
|
|
|
@ -26,4 +26,4 @@
|
||||||
.getdoc: (object: Obj) -> Str
|
.getdoc: (object: Obj) -> Str
|
||||||
.getcomments: (object: Obj) -> Str
|
.getcomments: (object: Obj) -> Str
|
||||||
.getfile: (object: Obj) -> Str
|
.getfile: (object: Obj) -> Str
|
||||||
.getmodule: (object: Obj) -> Module or NoneType
|
.getmodule: (object: Obj) -> GenericModule or NoneType
|
||||||
|
|
|
@ -4,18 +4,18 @@
|
||||||
.NoReturn: Type
|
.NoReturn: Type
|
||||||
.Self: Type
|
.Self: Type
|
||||||
.TypeAlias: Type
|
.TypeAlias: Type
|
||||||
.Tuple: (...Type) -> Type
|
.Tuple: (*Type) -> Type
|
||||||
.Union: (...Type) -> Type
|
.Union: (*Type) -> Type
|
||||||
.Optional: (Type) -> Type
|
.Optional: (Type) -> Type
|
||||||
.Callable: (...Type) -> Type
|
.Callable: (*Type) -> Type
|
||||||
.Concatenate: (...Type) -> Type
|
.Concatenate: (*Type) -> Type
|
||||||
.Type: (Type) -> Type
|
.Type: (Type) -> Type
|
||||||
.Literal: (...Obj) -> Type
|
.Literal: (*Obj) -> Type
|
||||||
.ClassVar: (Type) -> Type
|
.ClassVar: (Type) -> Type
|
||||||
.Final: (Type) -> Type
|
.Final: (Type) -> Type
|
||||||
.Required: (Type) -> Type
|
.Required: (Type) -> Type
|
||||||
.NotRequired: (Type) -> Type
|
.NotRequired: (Type) -> Type
|
||||||
.Annotated: (Type, ...Obj) -> Type
|
.Annotated: (Type, *Obj) -> Type
|
||||||
.TypeGuard: (Type) -> Type
|
.TypeGuard: (Type) -> Type
|
||||||
.Generic: (Type) -> Type
|
.Generic: (Type) -> Type
|
||||||
.TypeVar: (Str) -> Type
|
.TypeVar: (Str) -> Type
|
||||||
|
|
|
@ -862,7 +862,7 @@ impl ASTLowerer {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let (pos_args, kw_args, paren) = call.args.deconstruct();
|
let (pos_args, var_args, kw_args, paren) = call.args.deconstruct();
|
||||||
let mut hir_args = hir::Args::new(
|
let mut hir_args = hir::Args::new(
|
||||||
Vec::with_capacity(pos_args.len()),
|
Vec::with_capacity(pos_args.len()),
|
||||||
None,
|
None,
|
||||||
|
@ -878,6 +878,16 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(var_args) = var_args {
|
||||||
|
match self.lower_expr(var_args.expr) {
|
||||||
|
Ok(expr) => hir_args.var_args = Some(Box::new(hir::PosArg::new(expr))),
|
||||||
|
Err(es) => {
|
||||||
|
errs.extend(es);
|
||||||
|
let dummy = hir::Expr::Dummy(hir::Dummy::empty());
|
||||||
|
hir_args.var_args = Some(Box::new(hir::PosArg::new(dummy)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for arg in kw_args.into_iter() {
|
for arg in kw_args.into_iter() {
|
||||||
match self.lower_expr(arg.expr) {
|
match self.lower_expr(arg.expr) {
|
||||||
Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
|
Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
|
||||||
|
@ -1032,7 +1042,7 @@ impl ASTLowerer {
|
||||||
} else {
|
} else {
|
||||||
let hir_params = hir::Params::new(
|
let hir_params = hir::Params::new(
|
||||||
params.non_defaults,
|
params.non_defaults,
|
||||||
params.var_args,
|
params.var_params,
|
||||||
hir_defaults,
|
hir_defaults,
|
||||||
params.parens,
|
params.parens,
|
||||||
);
|
);
|
||||||
|
|
|
@ -216,15 +216,17 @@ impl CodeObj {
|
||||||
filename: S,
|
filename: S,
|
||||||
name: T,
|
name: T,
|
||||||
firstlineno: u32,
|
firstlineno: u32,
|
||||||
|
flags: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
|
let var_args_defined = (flags & CodeObjFlags::VarArgs as u32 != 0) as u32;
|
||||||
Self {
|
Self {
|
||||||
argcount: params.len() as u32,
|
argcount: params.len() as u32 - var_args_defined,
|
||||||
posonlyargcount: 0,
|
posonlyargcount: 0,
|
||||||
kwonlyargcount: 0,
|
kwonlyargcount: 0,
|
||||||
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: 0, // CodeObjFlags::NoFree as u32,
|
flags, // CodeObjFlags::NoFree as u32,
|
||||||
code: Vec::with_capacity(8),
|
code: Vec::with_capacity(8),
|
||||||
consts: Vec::with_capacity(4),
|
consts: Vec::with_capacity(4),
|
||||||
names: Vec::with_capacity(3),
|
names: Vec::with_capacity(3),
|
||||||
|
|
|
@ -35,6 +35,10 @@ pub fn array_mut(elem_t: Type, len: TyParam) -> Type {
|
||||||
poly("Array!", vec![TyParam::t(elem_t), len])
|
poly("Array!", vec![TyParam::t(elem_t), len])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unknown_len_array_t(elem_t: Type) -> Type {
|
||||||
|
array_t(elem_t, TyParam::erased(Type::Nat))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tuple_t(args: Vec<Type>) -> Type {
|
pub fn tuple_t(args: Vec<Type>) -> Type {
|
||||||
poly(
|
poly(
|
||||||
"Tuple",
|
"Tuple",
|
||||||
|
|
|
@ -197,6 +197,21 @@ impl ParamTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_type<F>(self, f: F) -> Self
|
||||||
|
where
|
||||||
|
F: FnOnce(Type) -> Type,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Pos { name, ty } => Self::Pos { name, ty: f(ty) },
|
||||||
|
Self::Kw { name, ty } => Self::Kw { name, ty: f(ty) },
|
||||||
|
Self::KwWithDefault { name, ty, default } => Self::KwWithDefault {
|
||||||
|
name,
|
||||||
|
ty: f(ty),
|
||||||
|
default,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
|
pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
|
||||||
match self {
|
match self {
|
||||||
Self::Pos { name, ty } => (name, ty, None),
|
Self::Pos { name, ty } => (name, ty, None),
|
||||||
|
@ -242,7 +257,7 @@ impl LimitedDisplay for SubrType {
|
||||||
if !self.non_default_params.is_empty() {
|
if !self.non_default_params.is_empty() {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "...")?;
|
write!(f, "*")?;
|
||||||
var_params.typ().limited_fmt(f, limit - 1)?;
|
var_params.typ().limited_fmt(f, limit - 1)?;
|
||||||
}
|
}
|
||||||
for pt in self.default_params.iter() {
|
for pt in self.default_params.iter() {
|
||||||
|
@ -501,7 +516,7 @@ impl Ownership {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ArgsOwnership {
|
pub struct ArgsOwnership {
|
||||||
pub non_defaults: Vec<(Option<Str>, Ownership)>,
|
pub non_defaults: Vec<(Option<Str>, Ownership)>,
|
||||||
pub var_params: Option<(Str, Ownership)>,
|
pub var_params: Option<(Option<Str>, Ownership)>,
|
||||||
pub defaults: Vec<(Str, Ownership)>,
|
pub defaults: Vec<(Str, Ownership)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,7 +534,12 @@ impl fmt::Display for ArgsOwnership {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((name, o)) = self.var_params.as_ref() {
|
if let Some((name, o)) = self.var_params.as_ref() {
|
||||||
write!(f, ", ...{name}: {o:?}")?;
|
write!(f, ", *")?;
|
||||||
|
if let Some(name) = name {
|
||||||
|
write!(f, "{name}: {o:?}")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{o:?}")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (name, o) in self.defaults.iter() {
|
for (name, o) in self.defaults.iter() {
|
||||||
write!(f, ", {name} := {o:?}")?;
|
write!(f, ", {name} := {o:?}")?;
|
||||||
|
@ -532,7 +552,7 @@ impl fmt::Display for ArgsOwnership {
|
||||||
impl ArgsOwnership {
|
impl ArgsOwnership {
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
non_defaults: Vec<(Option<Str>, Ownership)>,
|
non_defaults: Vec<(Option<Str>, Ownership)>,
|
||||||
var_params: Option<(Str, Ownership)>,
|
var_params: Option<(Option<Str>, Ownership)>,
|
||||||
defaults: Vec<(Str, Ownership)>,
|
defaults: Vec<(Str, Ownership)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -1295,7 +1315,7 @@ impl Type {
|
||||||
let var_args = subr
|
let var_args = subr
|
||||||
.var_params
|
.var_params
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|t| (t.name().unwrap().clone(), t.typ().ownership()));
|
.map(|t| (t.name().cloned(), t.typ().ownership()));
|
||||||
let mut d_args = vec![];
|
let mut d_args = vec![];
|
||||||
for d_param in subr.default_params.iter() {
|
for d_param in subr.default_params.iter() {
|
||||||
let ownership = match d_param.typ() {
|
let ownership = match d_param.typ() {
|
||||||
|
@ -1670,7 +1690,6 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn container_len(&self) -> Option<usize> {
|
pub fn container_len(&self) -> Option<usize> {
|
||||||
log!(err "{self}");
|
|
||||||
match self {
|
match self {
|
||||||
Self::Poly { name, params } => match &name[..] {
|
Self::Poly { name, params } => match &name[..] {
|
||||||
"Array" => {
|
"Array" => {
|
||||||
|
|
|
@ -159,7 +159,7 @@ impl KwArg {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
pos_args: Vec<PosArg>,
|
pos_args: Vec<PosArg>,
|
||||||
// var_args: Option<Box<PosArg>>,
|
pub(crate) var_args: Option<Box<PosArg>>,
|
||||||
kw_args: Vec<KwArg>,
|
kw_args: Vec<KwArg>,
|
||||||
pub paren: Option<(Token, Token)>,
|
pub paren: Option<(Token, Token)>,
|
||||||
}
|
}
|
||||||
|
@ -194,25 +194,44 @@ impl Locational for Args {
|
||||||
// impl_stream!(Args, Arg, args);
|
// impl_stream!(Args, Arg, args);
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
pub const fn new(
|
pub fn new(
|
||||||
pos_args: Vec<PosArg>,
|
pos_args: Vec<PosArg>,
|
||||||
|
var_args: Option<PosArg>,
|
||||||
kw_args: Vec<KwArg>,
|
kw_args: Vec<KwArg>,
|
||||||
paren: Option<(Token, Token)>,
|
paren: Option<(Token, Token)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos_args,
|
pos_args,
|
||||||
|
var_args: var_args.map(Box::new),
|
||||||
kw_args,
|
kw_args,
|
||||||
paren,
|
paren,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn empty() -> Self {
|
pub fn pos_only(pos_args: Vec<PosArg>, paren: Option<(Token, Token)>) -> Self {
|
||||||
Self::new(vec![], vec![], None)
|
Self::new(pos_args, None, vec![], paren)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self::new(vec![], None, vec![], None)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for replacing to hir::Args
|
// for replacing to hir::Args
|
||||||
pub fn deconstruct(self) -> (Vec<PosArg>, Vec<KwArg>, Option<(Token, Token)>) {
|
#[allow(clippy::type_complexity)]
|
||||||
(self.pos_args, self.kw_args, self.paren)
|
pub fn deconstruct(
|
||||||
|
self,
|
||||||
|
) -> (
|
||||||
|
Vec<PosArg>,
|
||||||
|
Option<PosArg>,
|
||||||
|
Vec<KwArg>,
|
||||||
|
Option<(Token, Token)>,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
self.pos_args,
|
||||||
|
self.var_args.map(|x| *x),
|
||||||
|
self.kw_args,
|
||||||
|
self.paren,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
|
@ -267,6 +286,10 @@ impl Args {
|
||||||
self.pos_args.insert(index, arg);
|
self.pos_args.insert(index, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_var_args(&mut self, arg: PosArg) {
|
||||||
|
self.var_args = Some(Box::new(arg));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_kw(&mut self, arg: KwArg) {
|
pub fn push_kw(&mut self, arg: KwArg) {
|
||||||
self.kw_args.push(arg);
|
self.kw_args.push(arg);
|
||||||
}
|
}
|
||||||
|
@ -1015,6 +1038,11 @@ impl BinOp {
|
||||||
args: [Box::new(lhs), Box::new(rhs)],
|
args: [Box::new(lhs), Box::new(rhs)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deconstruct(self) -> (Token, Expr, Expr) {
|
||||||
|
let mut exprs = self.args.into_iter();
|
||||||
|
(self.op, *exprs.next().unwrap(), *exprs.next().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
@ -1045,6 +1073,11 @@ impl UnaryOp {
|
||||||
args: [Box::new(expr)],
|
args: [Box::new(expr)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deconstruct(self) -> (Token, Expr) {
|
||||||
|
let mut exprs = self.args.into_iter();
|
||||||
|
(self.op, *exprs.next().unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
@ -1660,6 +1693,7 @@ impl ConstKwArg {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ConstArgs {
|
pub struct ConstArgs {
|
||||||
pos_args: Vec<ConstPosArg>,
|
pos_args: Vec<ConstPosArg>,
|
||||||
|
var_args: Option<Box<ConstPosArg>>,
|
||||||
kw_args: Vec<ConstKwArg>,
|
kw_args: Vec<ConstKwArg>,
|
||||||
paren: Option<(Token, Token)>,
|
paren: Option<(Token, Token)>,
|
||||||
}
|
}
|
||||||
|
@ -1691,24 +1725,43 @@ impl Locational for ConstArgs {
|
||||||
// impl_stream!(ConstArgs, ConstKwArg, pos_args);
|
// impl_stream!(ConstArgs, ConstKwArg, pos_args);
|
||||||
|
|
||||||
impl ConstArgs {
|
impl ConstArgs {
|
||||||
pub const fn new(
|
pub fn new(
|
||||||
pos_args: Vec<ConstPosArg>,
|
pos_args: Vec<ConstPosArg>,
|
||||||
|
var_args: Option<ConstPosArg>,
|
||||||
kw_args: Vec<ConstKwArg>,
|
kw_args: Vec<ConstKwArg>,
|
||||||
paren: Option<(Token, Token)>,
|
paren: Option<(Token, Token)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos_args,
|
pos_args,
|
||||||
|
var_args: var_args.map(Box::new),
|
||||||
kw_args,
|
kw_args,
|
||||||
paren,
|
paren,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> (Vec<ConstPosArg>, Vec<ConstKwArg>, Option<(Token, Token)>) {
|
pub fn pos_only(pos_args: Vec<ConstPosArg>, paren: Option<(Token, Token)>) -> Self {
|
||||||
(self.pos_args, self.kw_args, self.paren)
|
Self::new(pos_args, None, vec![], paren)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn empty() -> Self {
|
#[allow(clippy::type_complexity)]
|
||||||
Self::new(vec![], vec![], None)
|
pub fn deconstruct(
|
||||||
|
self,
|
||||||
|
) -> (
|
||||||
|
Vec<ConstPosArg>,
|
||||||
|
Option<ConstPosArg>,
|
||||||
|
Vec<ConstKwArg>,
|
||||||
|
Option<(Token, Token)>,
|
||||||
|
) {
|
||||||
|
(
|
||||||
|
self.pos_args,
|
||||||
|
self.var_args.map(|x| *x),
|
||||||
|
self.kw_args,
|
||||||
|
self.paren,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self::new(vec![], None, vec![], None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
|
@ -1741,12 +1794,13 @@ impl ConstArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn downcast(self) -> Args {
|
pub fn downcast(self) -> Args {
|
||||||
let (pos_args, kw_args, paren) = self.deconstruct();
|
let (pos_args, var_args, kw_args, paren) = self.deconstruct();
|
||||||
Args::new(
|
Args::new(
|
||||||
pos_args
|
pos_args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| PosArg::new(arg.expr.downcast()))
|
.map(|arg| PosArg::new(arg.expr.downcast()))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
var_args.map(|arg| PosArg::new(arg.expr.downcast())),
|
||||||
kw_args
|
kw_args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// TODO t_spec
|
// TODO t_spec
|
||||||
|
@ -1900,7 +1954,7 @@ pub struct SubrTypeSpec {
|
||||||
pub bounds: TypeBoundSpecs,
|
pub bounds: TypeBoundSpecs,
|
||||||
pub lparen: Option<Token>,
|
pub lparen: Option<Token>,
|
||||||
pub non_defaults: Vec<ParamTySpec>,
|
pub non_defaults: Vec<ParamTySpec>,
|
||||||
pub var_args: Option<Box<ParamTySpec>>,
|
pub var_params: Option<Box<ParamTySpec>>,
|
||||||
pub defaults: Vec<DefaultParamTySpec>,
|
pub defaults: Vec<DefaultParamTySpec>,
|
||||||
pub arrow: Token,
|
pub arrow: Token,
|
||||||
pub return_t: Box<TypeSpec>,
|
pub return_t: Box<TypeSpec>,
|
||||||
|
@ -1915,7 +1969,7 @@ impl fmt::Display for SubrTypeSpec {
|
||||||
f,
|
f,
|
||||||
"({}, {}, {}) {} {}",
|
"({}, {}, {}) {} {}",
|
||||||
fmt_vec(&self.non_defaults),
|
fmt_vec(&self.non_defaults),
|
||||||
fmt_option!(pre "...", &self.var_args),
|
fmt_option!(pre "*", &self.var_params),
|
||||||
fmt_vec(&self.defaults),
|
fmt_vec(&self.defaults),
|
||||||
self.arrow.content,
|
self.arrow.content,
|
||||||
self.return_t
|
self.return_t
|
||||||
|
@ -1941,7 +1995,7 @@ impl SubrTypeSpec {
|
||||||
bounds: TypeBoundSpecs,
|
bounds: TypeBoundSpecs,
|
||||||
lparen: Option<Token>,
|
lparen: Option<Token>,
|
||||||
non_defaults: Vec<ParamTySpec>,
|
non_defaults: Vec<ParamTySpec>,
|
||||||
var_args: Option<ParamTySpec>,
|
var_params: Option<ParamTySpec>,
|
||||||
defaults: Vec<DefaultParamTySpec>,
|
defaults: Vec<DefaultParamTySpec>,
|
||||||
arrow: Token,
|
arrow: Token,
|
||||||
return_t: TypeSpec,
|
return_t: TypeSpec,
|
||||||
|
@ -1950,7 +2004,7 @@ impl SubrTypeSpec {
|
||||||
bounds,
|
bounds,
|
||||||
lparen,
|
lparen,
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_args: var_args.map(Box::new),
|
var_params: var_params.map(Box::new),
|
||||||
defaults,
|
defaults,
|
||||||
arrow,
|
arrow,
|
||||||
return_t: Box::new(return_t),
|
return_t: Box::new(return_t),
|
||||||
|
@ -2162,6 +2216,7 @@ impl TypeSpec {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|lit| ConstPosArg::new(ConstExpr::Lit(lit)))
|
.map(|lit| ConstPosArg::new(ConstExpr::Lit(lit)))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
None,
|
||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
|
@ -3044,7 +3099,7 @@ impl DefaultParamSignature {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub non_defaults: Vec<NonDefaultParamSignature>,
|
pub non_defaults: Vec<NonDefaultParamSignature>,
|
||||||
pub var_args: Option<Box<NonDefaultParamSignature>>,
|
pub var_params: Option<Box<NonDefaultParamSignature>>,
|
||||||
pub defaults: Vec<DefaultParamSignature>,
|
pub defaults: Vec<DefaultParamSignature>,
|
||||||
pub parens: Option<(Token, Token)>,
|
pub parens: Option<(Token, Token)>,
|
||||||
}
|
}
|
||||||
|
@ -3055,7 +3110,7 @@ impl fmt::Display for Params {
|
||||||
f,
|
f,
|
||||||
"({}, {}, {})",
|
"({}, {}, {})",
|
||||||
fmt_vec(&self.non_defaults),
|
fmt_vec(&self.non_defaults),
|
||||||
fmt_option!(pre "...", &self.var_args),
|
fmt_option!(pre "...", &self.var_params),
|
||||||
fmt_vec(&self.defaults)
|
fmt_vec(&self.defaults)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3071,7 +3126,7 @@ impl Locational for Params {
|
||||||
}
|
}
|
||||||
match (
|
match (
|
||||||
self.non_defaults.first(),
|
self.non_defaults.first(),
|
||||||
self.var_args.as_ref(),
|
self.var_params.as_ref(),
|
||||||
self.defaults.last(),
|
self.defaults.last(),
|
||||||
) {
|
) {
|
||||||
(Some(l), _, Some(r)) => Location::concat(l, r),
|
(Some(l), _, Some(r)) => Location::concat(l, r),
|
||||||
|
@ -3094,20 +3149,25 @@ type RawParams = (
|
||||||
impl Params {
|
impl Params {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
non_defaults: Vec<NonDefaultParamSignature>,
|
non_defaults: Vec<NonDefaultParamSignature>,
|
||||||
var_args: Option<NonDefaultParamSignature>,
|
var_params: Option<NonDefaultParamSignature>,
|
||||||
defaults: Vec<DefaultParamSignature>,
|
defaults: Vec<DefaultParamSignature>,
|
||||||
parens: Option<(Token, Token)>,
|
parens: Option<(Token, Token)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_args: var_args.map(Box::new),
|
var_params: var_params.map(Box::new),
|
||||||
defaults,
|
defaults,
|
||||||
parens,
|
parens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deconstruct(self) -> RawParams {
|
pub fn deconstruct(self) -> RawParams {
|
||||||
(self.non_defaults, self.var_args, self.defaults, self.parens)
|
(
|
||||||
|
self.non_defaults,
|
||||||
|
self.var_params,
|
||||||
|
self.defaults,
|
||||||
|
self.parens,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -204,7 +204,7 @@ impl Parser {
|
||||||
let mut vars = Vars::empty();
|
let mut vars = Vars::empty();
|
||||||
match tuple {
|
match tuple {
|
||||||
Tuple::Normal(tup) => {
|
Tuple::Normal(tup) => {
|
||||||
let (pos_args, _kw_args, paren) = tup.elems.deconstruct();
|
let (pos_args, _var_args, _kw_args, paren) = tup.elems.deconstruct();
|
||||||
for arg in pos_args {
|
for arg in pos_args {
|
||||||
let sig = self
|
let sig = self
|
||||||
.convert_rhs_to_sig(arg.expr)
|
.convert_rhs_to_sig(arg.expr)
|
||||||
|
@ -312,7 +312,7 @@ impl Parser {
|
||||||
) -> ParseResult<TypeBoundSpecs> {
|
) -> ParseResult<TypeBoundSpecs> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let mut bounds = vec![];
|
let mut bounds = vec![];
|
||||||
let (pos_args, _kw_args, _paren) = type_args.args.deconstruct();
|
let (pos_args, _var_args, _kw_args, _paren) = type_args.args.deconstruct();
|
||||||
for arg in pos_args.into_iter() {
|
for arg in pos_args.into_iter() {
|
||||||
let bound = self
|
let bound = self
|
||||||
.convert_type_arg_to_bound(arg)
|
.convert_type_arg_to_bound(arg)
|
||||||
|
@ -348,7 +348,7 @@ impl Parser {
|
||||||
|
|
||||||
pub(crate) fn convert_args_to_params(&mut self, args: Args) -> ParseResult<Params> {
|
pub(crate) fn convert_args_to_params(&mut self, args: Args) -> ParseResult<Params> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let (pos_args, kw_args, parens) = args.deconstruct();
|
let (pos_args, var_args, kw_args, parens) = args.deconstruct();
|
||||||
let mut params = Params::new(vec![], None, vec![], parens);
|
let mut params = Params::new(vec![], None, vec![], parens);
|
||||||
for (i, arg) in pos_args.into_iter().enumerate() {
|
for (i, arg) in pos_args.into_iter().enumerate() {
|
||||||
let nd_param = self
|
let nd_param = self
|
||||||
|
@ -356,6 +356,12 @@ impl Parser {
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
params.non_defaults.push(nd_param);
|
params.non_defaults.push(nd_param);
|
||||||
}
|
}
|
||||||
|
if let Some(var_args) = var_args {
|
||||||
|
let var_args = self
|
||||||
|
.convert_pos_arg_to_non_default_param(var_args, false)
|
||||||
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
|
params.var_params = Some(Box::new(var_args));
|
||||||
|
}
|
||||||
// TODO: varargs
|
// TODO: varargs
|
||||||
for arg in kw_args.into_iter() {
|
for arg in kw_args.into_iter() {
|
||||||
let d_param = self
|
let d_param = self
|
||||||
|
@ -566,11 +572,17 @@ impl Parser {
|
||||||
match tuple {
|
match tuple {
|
||||||
Tuple::Normal(tup) => {
|
Tuple::Normal(tup) => {
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
let (elems, _, parens) = tup.elems.deconstruct();
|
let (elems, var_args, _, parens) = tup.elems.deconstruct();
|
||||||
for arg in elems.into_iter() {
|
for arg in elems.into_iter() {
|
||||||
params.push(self.convert_pos_arg_to_non_default_param(arg, false)?);
|
params.push(self.convert_pos_arg_to_non_default_param(arg, false)?);
|
||||||
}
|
}
|
||||||
let params = Params::new(params, None, vec![], parens);
|
let var_params = if let Some(var_args) = var_args {
|
||||||
|
let var_params = self.convert_pos_arg_to_non_default_param(var_args, false)?;
|
||||||
|
Some(var_params)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let params = Params::new(params, var_params, vec![], parens);
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
Ok(ParamTuplePattern::new(params))
|
Ok(ParamTuplePattern::new(params))
|
||||||
}
|
}
|
||||||
|
@ -640,6 +652,23 @@ impl Parser {
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
Ok(sig)
|
Ok(sig)
|
||||||
}
|
}
|
||||||
|
Expr::UnaryOp(unary) => match unary.op.kind {
|
||||||
|
TokenKind::PreStar => {
|
||||||
|
let mut exprs = unary.args.into_iter();
|
||||||
|
let param = self
|
||||||
|
.convert_rhs_to_param(*exprs.next().unwrap(), false)
|
||||||
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
|
let params = Params::new(vec![], Some(param), vec![], None);
|
||||||
|
debug_exit_info!(self);
|
||||||
|
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let err = ParseError::simple_syntax_error(line!() as usize, unary.op.loc());
|
||||||
|
self.errs.push(err);
|
||||||
|
debug_exit_info!(self);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
other => {
|
other => {
|
||||||
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
|
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
|
||||||
self.errs.push(err);
|
self.errs.push(err);
|
||||||
|
@ -677,7 +706,7 @@ impl Parser {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
match tuple {
|
match tuple {
|
||||||
Tuple::Normal(tup) => {
|
Tuple::Normal(tup) => {
|
||||||
let (pos_args, kw_args, paren) = tup.elems.deconstruct();
|
let (pos_args, var_args, kw_args, paren) = tup.elems.deconstruct();
|
||||||
let mut params = Params::new(vec![], None, vec![], paren);
|
let mut params = Params::new(vec![], None, vec![], paren);
|
||||||
for (i, arg) in pos_args.into_iter().enumerate() {
|
for (i, arg) in pos_args.into_iter().enumerate() {
|
||||||
let param = self
|
let param = self
|
||||||
|
@ -685,6 +714,12 @@ impl Parser {
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
params.non_defaults.push(param);
|
params.non_defaults.push(param);
|
||||||
}
|
}
|
||||||
|
if let Some(var_args) = var_args {
|
||||||
|
let param = self
|
||||||
|
.convert_pos_arg_to_non_default_param(var_args, false)
|
||||||
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
|
params.var_params = Some(Box::new(param));
|
||||||
|
}
|
||||||
for arg in kw_args {
|
for arg in kw_args {
|
||||||
let param = self
|
let param = self
|
||||||
.convert_kw_arg_to_default_param(arg)
|
.convert_kw_arg_to_default_param(arg)
|
||||||
|
|
|
@ -56,18 +56,19 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugar_args(mut desugar: impl FnMut(Expr) -> Expr, args: Args) -> Args {
|
fn desugar_args(mut desugar: impl FnMut(Expr) -> Expr, args: Args) -> Args {
|
||||||
let (pos_args, kw_args, paren) = args.deconstruct();
|
let (pos_args, var_args, kw_args, paren) = args.deconstruct();
|
||||||
let pos_args = pos_args
|
let pos_args = pos_args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| PosArg::new(desugar(arg.expr)))
|
.map(|arg| PosArg::new(desugar(arg.expr)))
|
||||||
.collect();
|
.collect();
|
||||||
|
let var_args = var_args.map(|arg| PosArg::new(desugar(arg.expr)));
|
||||||
let kw_args = kw_args
|
let kw_args = kw_args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
KwArg::new(arg.keyword, arg.t_spec, desugar(arg.expr)) // TODO: t_spec
|
KwArg::new(arg.keyword, arg.t_spec, desugar(arg.expr)) // TODO: t_spec
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Args::new(pos_args, kw_args, paren)
|
Args::new(pos_args, var_args, kw_args, paren)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_desugar_acc(mut desugar: impl FnMut(Expr) -> Expr, acc: Accessor) -> Accessor {
|
fn perform_desugar_acc(mut desugar: impl FnMut(Expr) -> Expr, acc: Accessor) -> Accessor {
|
||||||
|
@ -138,12 +139,12 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
Expr::Array(array) => match array {
|
Expr::Array(array) => match array {
|
||||||
Array::Normal(arr) => {
|
Array::Normal(arr) => {
|
||||||
let (elems, _, _) = arr.elems.deconstruct();
|
let (elems, _, _, _) = arr.elems.deconstruct();
|
||||||
let elems = elems
|
let elems = elems
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|elem| PosArg::new(desugar(elem.expr)))
|
.map(|elem| PosArg::new(desugar(elem.expr)))
|
||||||
.collect();
|
.collect();
|
||||||
let elems = Args::new(elems, vec![], None);
|
let elems = Args::new(elems, None, vec![], None);
|
||||||
let arr = NormalArray::new(arr.l_sqbr, arr.r_sqbr, elems);
|
let arr = NormalArray::new(arr.l_sqbr, arr.r_sqbr, elems);
|
||||||
Expr::Array(Array::Normal(arr))
|
Expr::Array(Array::Normal(arr))
|
||||||
}
|
}
|
||||||
|
@ -168,24 +169,24 @@ impl Desugarer {
|
||||||
},
|
},
|
||||||
Expr::Tuple(tuple) => match tuple {
|
Expr::Tuple(tuple) => match tuple {
|
||||||
Tuple::Normal(tup) => {
|
Tuple::Normal(tup) => {
|
||||||
let (elems, _, paren) = tup.elems.deconstruct();
|
let (elems, _, _, paren) = tup.elems.deconstruct();
|
||||||
let elems = elems
|
let elems = elems
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|elem| PosArg::new(desugar(elem.expr)))
|
.map(|elem| PosArg::new(desugar(elem.expr)))
|
||||||
.collect();
|
.collect();
|
||||||
let new_tup = Args::new(elems, vec![], paren);
|
let new_tup = Args::new(elems, None, vec![], paren);
|
||||||
let tup = NormalTuple::new(new_tup);
|
let tup = NormalTuple::new(new_tup);
|
||||||
Expr::Tuple(Tuple::Normal(tup))
|
Expr::Tuple(Tuple::Normal(tup))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::Set(set) => match set {
|
Expr::Set(set) => match set {
|
||||||
astSet::Normal(set) => {
|
astSet::Normal(set) => {
|
||||||
let (elems, _, _) = set.elems.deconstruct();
|
let (elems, _, _, _) = set.elems.deconstruct();
|
||||||
let elems = elems
|
let elems = elems
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|elem| PosArg::new(desugar(elem.expr)))
|
.map(|elem| PosArg::new(desugar(elem.expr)))
|
||||||
.collect();
|
.collect();
|
||||||
let elems = Args::new(elems, vec![], None);
|
let elems = Args::new(elems, None, vec![], None);
|
||||||
let set = NormalSet::new(set.l_brace, set.r_brace, elems);
|
let set = NormalSet::new(set.l_brace, set.r_brace, elems);
|
||||||
Expr::Set(astSet::Normal(set))
|
Expr::Set(astSet::Normal(set))
|
||||||
}
|
}
|
||||||
|
@ -393,13 +394,12 @@ impl Desugarer {
|
||||||
let return_t_spec = sig.return_t_spec;
|
let return_t_spec = sig.return_t_spec;
|
||||||
let sig = LambdaSignature::new(sig.params, return_t_spec.clone(), sig.bounds);
|
let sig = LambdaSignature::new(sig.params, return_t_spec.clone(), sig.bounds);
|
||||||
let second_branch = Lambda::new(sig, op, def.body.block, def.body.id);
|
let second_branch = Lambda::new(sig, op, def.body.block, def.body.id);
|
||||||
let args = Args::new(
|
let args = Args::pos_only(
|
||||||
vec![
|
vec![
|
||||||
PosArg::new(Expr::dummy_local("_")), // dummy argument, will be removed in line 56
|
PosArg::new(Expr::dummy_local("_")), // dummy argument, will be removed in line 56
|
||||||
PosArg::new(Expr::Lambda(first_branch)),
|
PosArg::new(Expr::Lambda(first_branch)),
|
||||||
PosArg::new(Expr::Lambda(second_branch)),
|
PosArg::new(Expr::Lambda(second_branch)),
|
||||||
],
|
],
|
||||||
vec![],
|
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let call = match_symbol.call(args);
|
let call = match_symbol.call(args);
|
||||||
|
@ -1075,9 +1075,8 @@ impl Desugarer {
|
||||||
match acc {
|
match acc {
|
||||||
// x[y] => x.__getitem__(y)
|
// x[y] => x.__getitem__(y)
|
||||||
Accessor::Subscr(subscr) => {
|
Accessor::Subscr(subscr) => {
|
||||||
let args = Args::new(
|
let args = Args::pos_only(
|
||||||
vec![PosArg::new(Self::rec_desugar_acc(*subscr.index))],
|
vec![PosArg::new(Self::rec_desugar_acc(*subscr.index))],
|
||||||
vec![],
|
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let line = subscr.obj.ln_begin().unwrap();
|
let line = subscr.obj.ln_begin().unwrap();
|
||||||
|
@ -1094,7 +1093,7 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
// x.0 => x.__Tuple_getitem__(0)
|
// x.0 => x.__Tuple_getitem__(0)
|
||||||
Accessor::TupleAttr(tattr) => {
|
Accessor::TupleAttr(tattr) => {
|
||||||
let args = Args::new(vec![PosArg::new(Expr::Lit(tattr.index))], vec![], None);
|
let args = Args::pos_only(vec![PosArg::new(Expr::Lit(tattr.index))], None);
|
||||||
let line = tattr.obj.ln_begin().unwrap();
|
let line = tattr.obj.ln_begin().unwrap();
|
||||||
let call = Call::new(
|
let call = Call::new(
|
||||||
Self::rec_desugar_acc(*tattr.obj),
|
Self::rec_desugar_acc(*tattr.obj),
|
||||||
|
|
|
@ -14,6 +14,22 @@ use crate::error::{LexError, LexErrors, LexResult, LexerRunnerError, LexerRunner
|
||||||
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
||||||
use TokenKind::*;
|
use TokenKind::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum OpFix {
|
||||||
|
Prefix,
|
||||||
|
Infix,
|
||||||
|
Postfix,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpFix {
|
||||||
|
pub const fn is_prefix(&self) -> bool {
|
||||||
|
matches!(self, Self::Prefix)
|
||||||
|
}
|
||||||
|
pub const fn is_infix(&self) -> bool {
|
||||||
|
matches!(self, Self::Infix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Lexerは使い捨てなので、Runnerを用意
|
/// Lexerは使い捨てなので、Runnerを用意
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct LexerRunner {
|
pub struct LexerRunner {
|
||||||
|
@ -274,7 +290,7 @@ impl Lexer /*<'a>*/ {
|
||||||
|
|
||||||
// +, -, * etc. may be pre/bin
|
// +, -, * etc. may be pre/bin
|
||||||
// and, or, is!, isnot!, in, notin, as, dot, cross may be bin/function
|
// and, or, is!, isnot!, in, notin, as, dot, cross may be bin/function
|
||||||
const fn is_bin_position(&self) -> Option<bool> {
|
fn op_fix(&self) -> Option<OpFix> {
|
||||||
match self.prev_token.category() {
|
match self.prev_token.category() {
|
||||||
// unary: `[ +`, `= +`, `+ +`, `, +`, `:: +`
|
// unary: `[ +`, `= +`, `+ +`, `, +`, `:: +`
|
||||||
TokenCategory::LEnclosure
|
TokenCategory::LEnclosure
|
||||||
|
@ -286,14 +302,17 @@ impl Lexer /*<'a>*/ {
|
||||||
| TokenCategory::LambdaOp
|
| TokenCategory::LambdaOp
|
||||||
| TokenCategory::StrInterpLeft
|
| TokenCategory::StrInterpLeft
|
||||||
| TokenCategory::StrInterpMid
|
| TokenCategory::StrInterpMid
|
||||||
| TokenCategory::BOF => Some(false),
|
| TokenCategory::BOF => Some(OpFix::Prefix),
|
||||||
// bin: `] +`, `1 +`, `true and[true]`, `}aaa"`
|
TokenCategory::REnclosure
|
||||||
TokenCategory::REnclosure | TokenCategory::Literal | TokenCategory::StrInterpRight => {
|
| TokenCategory::Literal
|
||||||
Some(true)
|
| TokenCategory::StrInterpRight
|
||||||
}
|
| TokenCategory::Symbol => match (self.peek_prev_prev_ch(), self.peek_cur_ch()) {
|
||||||
// bin: `fn +1`
|
(Some(' '), Some(' ')) => Some(OpFix::Infix), // x + 1: bin
|
||||||
// NOTE: if semantic analysis shows `fn` is a function, should this be rewritten to be unary?
|
(Some(' '), Some(_)) => Some(OpFix::Prefix), // x +1: unary
|
||||||
TokenCategory::Symbol => Some(true),
|
(Some(_), Some(' ')) => Some(OpFix::Infix), // x+ 1 : bin
|
||||||
|
(Some(_), Some(_)) => Some(OpFix::Infix), // x+1: bin
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,12 +328,12 @@ impl Lexer /*<'a>*/ {
|
||||||
self.chars.get(now).copied()
|
self.chars.get(now).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peek_prev_prev_ch(&self) -> Option<char> {
|
||||||
|
self.chars.get(self.cursor.checked_sub(2)?).copied()
|
||||||
|
}
|
||||||
|
|
||||||
fn peek_prev_ch(&self) -> Option<char> {
|
fn peek_prev_ch(&self) -> Option<char> {
|
||||||
if self.cursor == 0 {
|
self.chars.get(self.cursor.checked_sub(1)?).copied()
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.chars.get(self.cursor - 1).copied()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1264,10 +1283,10 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
}
|
}
|
||||||
Some('?') => self.accept(Try, "?"),
|
Some('?') => self.accept(Try, "?"),
|
||||||
Some('+') => {
|
Some('+') => {
|
||||||
let kind = match self.is_bin_position() {
|
let kind = match self.op_fix() {
|
||||||
Some(true) => Plus,
|
Some(OpFix::Infix) => Plus,
|
||||||
Some(false) => PrePlus,
|
Some(OpFix::Prefix) => PrePlus,
|
||||||
None => {
|
_ => {
|
||||||
let token = self.emit_token(Illegal, "+");
|
let token = self.emit_token(Illegal, "+");
|
||||||
return Some(Err(LexError::simple_syntax_error(0, token.loc())));
|
return Some(Err(LexError::simple_syntax_error(0, token.loc())));
|
||||||
}
|
}
|
||||||
|
@ -1280,9 +1299,9 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
self.accept(FuncArrow, "->")
|
self.accept(FuncArrow, "->")
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
match self.is_bin_position() {
|
match self.op_fix() {
|
||||||
Some(true) => self.accept(Minus, "-"),
|
Some(OpFix::Infix) => self.accept(Minus, "-"),
|
||||||
Some(false) => {
|
Some(OpFix::Prefix) => {
|
||||||
// IntLit (negative number)
|
// IntLit (negative number)
|
||||||
if self
|
if self
|
||||||
.peek_cur_ch()
|
.peek_cur_ch()
|
||||||
|
@ -1294,7 +1313,7 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
self.accept(PreMinus, "-")
|
self.accept(PreMinus, "-")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
let token = self.emit_token(Illegal, "-");
|
let token = self.emit_token(Illegal, "-");
|
||||||
Some(Err(LexError::simple_syntax_error(0, token.loc())))
|
Some(Err(LexError::simple_syntax_error(0, token.loc())))
|
||||||
}
|
}
|
||||||
|
@ -1302,13 +1321,15 @@ impl Iterator for Lexer /*<'a>*/ {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some('*') => match self.peek_cur_ch() {
|
Some('*') => match self.peek_cur_ch() {
|
||||||
|
// TODO: infix/prefix
|
||||||
Some('*') => {
|
Some('*') => {
|
||||||
self.consume();
|
self.consume();
|
||||||
self.accept(Pow, "**")
|
self.accept(Pow, "**")
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let kind = match self.is_bin_position() {
|
let kind = match self.op_fix() {
|
||||||
Some(true) => Star,
|
Some(OpFix::Infix) => Star,
|
||||||
|
Some(OpFix::Prefix) => PreStar,
|
||||||
_ => {
|
_ => {
|
||||||
let token = self.emit_token(Illegal, "*");
|
let token = self.emit_token(Illegal, "*");
|
||||||
return Some(Err(LexError::simple_syntax_error(0, token.loc())));
|
return Some(Err(LexError::simple_syntax_error(0, token.loc())));
|
||||||
|
|
|
@ -555,14 +555,14 @@ impl Parser {
|
||||||
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
|
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
if self.cur_category_is(TC::REnclosure) {
|
if self.cur_category_is(TC::REnclosure) {
|
||||||
let args = Args::new(vec![], vec![], None);
|
let args = Args::empty();
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
return Ok(ArrayInner::Normal(args));
|
return Ok(ArrayInner::Normal(args));
|
||||||
}
|
}
|
||||||
let first = self
|
let first = self
|
||||||
.try_reduce_elem()
|
.try_reduce_elem()
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||||
let mut elems = Args::new(vec![first], vec![], None);
|
let mut elems = Args::pos_only(vec![first], None);
|
||||||
match self.peek_kind() {
|
match self.peek_kind() {
|
||||||
Some(Semi) => {
|
Some(Semi) => {
|
||||||
self.lpop();
|
self.lpop();
|
||||||
|
@ -693,11 +693,11 @@ impl Parser {
|
||||||
Some(RParen) => {
|
Some(RParen) => {
|
||||||
rp = Some(self.lpop());
|
rp = Some(self.lpop());
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
return Ok(Args::new(vec![], vec![], Some((lp.unwrap(), rp.unwrap()))));
|
return Ok(Args::pos_only(vec![], Some((lp.unwrap(), rp.unwrap()))));
|
||||||
}
|
}
|
||||||
Some(RBrace | RSqBr | Dedent) => {
|
Some(RBrace | RSqBr | Dedent) => {
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
return Ok(Args::new(vec![], vec![], None));
|
return Ok(Args::pos_only(vec![], None));
|
||||||
}
|
}
|
||||||
Some(Newline) if style.needs_parens() => {
|
Some(Newline) if style.needs_parens() => {
|
||||||
self.skip();
|
self.skip();
|
||||||
|
@ -712,8 +712,21 @@ impl Parser {
|
||||||
.try_reduce_arg(in_type_args)
|
.try_reduce_arg(in_type_args)
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?
|
.map_err(|_| self.stack_dec(fn_name!()))?
|
||||||
{
|
{
|
||||||
PosOrKwArg::Pos(arg) => Args::new(vec![arg], vec![], None),
|
PosOrKwArg::Pos(PosArg {
|
||||||
PosOrKwArg::Kw(arg) => Args::new(vec![], vec![arg], None),
|
expr: Expr::UnaryOp(unary),
|
||||||
|
}) if unary.op.is(PreStar) => {
|
||||||
|
let pos_args = PosArg::new(unary.deconstruct().1);
|
||||||
|
Args::new(vec![], Some(pos_args), vec![], None)
|
||||||
|
}
|
||||||
|
PosOrKwArg::Pos(PosArg {
|
||||||
|
expr: Expr::TypeAsc(TypeAscription { expr, op, t_spec }),
|
||||||
|
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => {
|
||||||
|
let Expr::UnaryOp(unary) = *expr else { unreachable!() };
|
||||||
|
let var_args = PosArg::new(unary.deconstruct().1.type_asc_expr(op, t_spec));
|
||||||
|
Args::new(vec![], Some(var_args), vec![], None)
|
||||||
|
}
|
||||||
|
PosOrKwArg::Pos(arg) => Args::pos_only(vec![arg], None),
|
||||||
|
PosOrKwArg::Kw(arg) => Args::new(vec![], None, vec![arg], None),
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
match self.peek_kind() {
|
match self.peek_kind() {
|
||||||
|
@ -756,8 +769,8 @@ impl Parser {
|
||||||
}
|
}
|
||||||
if style.needs_parens() && self.cur_is(RParen) {
|
if style.needs_parens() && self.cur_is(RParen) {
|
||||||
let rp = self.lpop();
|
let rp = self.lpop();
|
||||||
let (pos_args, kw_args, _) = args.deconstruct();
|
let (pos_args, var_args, kw_args, _) = args.deconstruct();
|
||||||
args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp)));
|
args = Args::new(pos_args, var_args, kw_args, Some((lp.unwrap(), rp)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if !args.kw_is_empty() {
|
if !args.kw_is_empty() {
|
||||||
|
@ -770,6 +783,20 @@ impl Parser {
|
||||||
.try_reduce_arg(in_type_args)
|
.try_reduce_arg(in_type_args)
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?
|
.map_err(|_| self.stack_dec(fn_name!()))?
|
||||||
{
|
{
|
||||||
|
PosOrKwArg::Pos(PosArg {
|
||||||
|
expr: Expr::UnaryOp(unary),
|
||||||
|
}) if unary.op.is(PreStar) => {
|
||||||
|
args.set_var_args(PosArg::new(unary.deconstruct().1));
|
||||||
|
}
|
||||||
|
PosOrKwArg::Pos(PosArg {
|
||||||
|
expr: Expr::TypeAsc(TypeAscription { expr, op, t_spec }),
|
||||||
|
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) =>
|
||||||
|
{
|
||||||
|
let Expr::UnaryOp(unary) = *expr else { unreachable!() };
|
||||||
|
args.set_var_args(PosArg::new(
|
||||||
|
unary.deconstruct().1.type_asc_expr(op, t_spec),
|
||||||
|
));
|
||||||
|
}
|
||||||
PosOrKwArg::Pos(arg) => {
|
PosOrKwArg::Pos(arg) => {
|
||||||
args.push_pos(arg);
|
args.push_pos(arg);
|
||||||
}
|
}
|
||||||
|
@ -782,12 +809,12 @@ impl Parser {
|
||||||
Some(RParen) => {
|
Some(RParen) => {
|
||||||
if let Some(lp) = lp {
|
if let Some(lp) = lp {
|
||||||
let rp = self.lpop();
|
let rp = self.lpop();
|
||||||
let (pos_args, kw_args, _) = args.deconstruct();
|
let (pos_args, var_args, kw_args, _) = args.deconstruct();
|
||||||
args = Args::new(pos_args, kw_args, Some((lp, rp)));
|
args = Args::new(pos_args, var_args, kw_args, Some((lp, rp)));
|
||||||
} else {
|
} else {
|
||||||
// e.g. f(g 1)
|
// e.g. f(g 1)
|
||||||
let (pos_args, kw_args, _) = args.deconstruct();
|
let (pos_args, var_args, kw_args, _) = args.deconstruct();
|
||||||
args = Args::new(pos_args, kw_args, None);
|
args = Args::new(pos_args, var_args, kw_args, None);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -805,8 +832,8 @@ impl Parser {
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
let (pos_args, kw_args, _) = args.deconstruct();
|
let (pos_args, var_args, kw_args, _) = args.deconstruct();
|
||||||
args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp)));
|
args = Args::new(pos_args, var_args, kw_args, Some((lp.unwrap(), rp)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1659,11 +1686,9 @@ impl Parser {
|
||||||
Signature::Var(var) => {
|
Signature::Var(var) => {
|
||||||
let mut last = def.body.block.pop().unwrap();
|
let mut last = def.body.block.pop().unwrap();
|
||||||
for deco in decos.into_iter() {
|
for deco in decos.into_iter() {
|
||||||
last = deco.into_expr().call_expr(Args::new(
|
last = deco
|
||||||
vec![PosArg::new(last)],
|
.into_expr()
|
||||||
vec![],
|
.call_expr(Args::pos_only(vec![PosArg::new(last)], None));
|
||||||
None,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
def.body.block.push(last);
|
def.body.block.push(last);
|
||||||
let expr = Expr::Def(Def::new(Signature::Var(var), def.body));
|
let expr = Expr::Def(Def::new(Signature::Var(var), def.body));
|
||||||
|
@ -1699,7 +1724,7 @@ impl Parser {
|
||||||
};
|
};
|
||||||
if self.cur_is(RParen) {
|
if self.cur_is(RParen) {
|
||||||
let rparen = self.lpop();
|
let rparen = self.lpop();
|
||||||
let args = Args::new(vec![], vec![], Some((lparen, rparen)));
|
let args = Args::pos_only(vec![], Some((lparen, rparen)));
|
||||||
let unit = Tuple::Normal(NormalTuple::new(args));
|
let unit = Tuple::Normal(NormalTuple::new(args));
|
||||||
debug_exit_info!(self);
|
debug_exit_info!(self);
|
||||||
return Ok(Expr::Tuple(unit));
|
return Ok(Expr::Tuple(unit));
|
||||||
|
@ -2268,7 +2293,7 @@ impl Parser {
|
||||||
len,
|
len,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let mut args = Args::new(vec![PosArg::new(first_elem)], vec![], None);
|
let mut args = Args::pos_only(vec![PosArg::new(first_elem)], None);
|
||||||
loop {
|
loop {
|
||||||
match self.peek_kind() {
|
match self.peek_kind() {
|
||||||
Some(Comma) => {
|
Some(Comma) => {
|
||||||
|
@ -2337,8 +2362,22 @@ impl Parser {
|
||||||
) -> ParseResult<Tuple> {
|
) -> ParseResult<Tuple> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let mut args = match first_elem {
|
let mut args = match first_elem {
|
||||||
PosOrKwArg::Pos(pos) => Args::new(vec![pos], vec![], None),
|
PosOrKwArg::Pos(PosArg {
|
||||||
PosOrKwArg::Kw(kw) => Args::new(vec![], vec![kw], None),
|
expr: Expr::UnaryOp(unary),
|
||||||
|
}) if unary.op.is(PreStar) => {
|
||||||
|
let var_args = Some(PosArg::new(unary.deconstruct().1));
|
||||||
|
Args::new(vec![], var_args, vec![], None)
|
||||||
|
}
|
||||||
|
PosOrKwArg::Pos(PosArg {
|
||||||
|
expr: Expr::TypeAsc(TypeAscription { expr, op, t_spec }),
|
||||||
|
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => {
|
||||||
|
let Expr::UnaryOp(unary) = *expr else { unreachable!() };
|
||||||
|
let expr = unary.deconstruct().1;
|
||||||
|
let var_args = Some(PosArg::new(expr.type_asc_expr(op, t_spec)));
|
||||||
|
Args::new(vec![], var_args, vec![], None)
|
||||||
|
}
|
||||||
|
PosOrKwArg::Pos(pos) => Args::pos_only(vec![pos], None),
|
||||||
|
PosOrKwArg::Kw(kw) => Args::new(vec![], None, vec![kw], None),
|
||||||
};
|
};
|
||||||
#[allow(clippy::while_let_loop)]
|
#[allow(clippy::while_let_loop)]
|
||||||
loop {
|
loop {
|
||||||
|
@ -2360,14 +2399,25 @@ impl Parser {
|
||||||
.try_reduce_arg(false)
|
.try_reduce_arg(false)
|
||||||
.map_err(|_| self.stack_dec(fn_name!()))?
|
.map_err(|_| self.stack_dec(fn_name!()))?
|
||||||
{
|
{
|
||||||
PosOrKwArg::Pos(arg) if args.kw_is_empty() => match arg.expr {
|
PosOrKwArg::Pos(arg) if args.kw_is_empty() && args.var_args.is_none() => {
|
||||||
Expr::Tuple(Tuple::Normal(tup)) if tup.elems.paren.is_none() => {
|
match arg.expr {
|
||||||
args.extend_pos(tup.elems.into_iters().0);
|
Expr::UnaryOp(unary) if unary.op.is(PreStar) => {
|
||||||
|
args.set_var_args(PosArg::new(unary.deconstruct().1));
|
||||||
|
}
|
||||||
|
Expr::TypeAsc(TypeAscription { expr, op, t_spec }) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) =>
|
||||||
|
{
|
||||||
|
let Expr::UnaryOp(unary) = *expr else { unreachable!() };
|
||||||
|
let expr = unary.deconstruct().1;
|
||||||
|
args.set_var_args(PosArg::new(expr.type_asc_expr(op, t_spec)));
|
||||||
|
}
|
||||||
|
Expr::Tuple(Tuple::Normal(tup)) if tup.elems.paren.is_none() => {
|
||||||
|
args.extend_pos(tup.elems.into_iters().0);
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
args.push_pos(PosArg::new(other));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
other => {
|
}
|
||||||
args.push_pos(PosArg::new(other));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PosOrKwArg::Pos(arg) => {
|
PosOrKwArg::Pos(arg) => {
|
||||||
let err = ParseError::syntax_error(
|
let err = ParseError::syntax_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
|
@ -2451,7 +2501,7 @@ impl Parser {
|
||||||
let call = Call::new(
|
let call = Call::new(
|
||||||
str_func,
|
str_func,
|
||||||
None,
|
None,
|
||||||
Args::new(vec![PosArg::new(mid_expr)], vec![], None),
|
Args::pos_only(vec![PosArg::new(mid_expr)], None),
|
||||||
);
|
);
|
||||||
let op = Token::new(
|
let op = Token::new(
|
||||||
Plus,
|
Plus,
|
||||||
|
|
|
@ -48,6 +48,8 @@ pub enum TokenKind {
|
||||||
// PreAt, // @ (unary)
|
// PreAt, // @ (unary)
|
||||||
/// ! (unary)
|
/// ! (unary)
|
||||||
Mutate,
|
Mutate,
|
||||||
|
PreStar, // * (unary)
|
||||||
|
PreDblStar, // ** (unary)
|
||||||
/// ? (postfix)
|
/// ? (postfix)
|
||||||
Try,
|
Try,
|
||||||
/// `+`
|
/// `+`
|
||||||
|
@ -164,8 +166,6 @@ pub enum TokenKind {
|
||||||
VBar,
|
VBar,
|
||||||
/// _
|
/// _
|
||||||
UBar,
|
UBar,
|
||||||
/// ...
|
|
||||||
Spread,
|
|
||||||
/// \n
|
/// \n
|
||||||
Newline,
|
Newline,
|
||||||
/// ;
|
/// ;
|
||||||
|
@ -229,7 +229,9 @@ impl TokenKind {
|
||||||
StrInterpLeft => TokenCategory::StrInterpLeft,
|
StrInterpLeft => TokenCategory::StrInterpLeft,
|
||||||
StrInterpMid => TokenCategory::StrInterpMid,
|
StrInterpMid => TokenCategory::StrInterpMid,
|
||||||
StrInterpRight => TokenCategory::StrInterpRight,
|
StrInterpRight => TokenCategory::StrInterpRight,
|
||||||
PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp,
|
PrePlus | PreMinus | PreBitNot | Mutate | PreStar | PreDblStar | RefOp | RefMutOp => {
|
||||||
|
TokenCategory::UnaryOp
|
||||||
|
}
|
||||||
Try => TokenCategory::PostfixOp,
|
Try => TokenCategory::PostfixOp,
|
||||||
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus
|
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus
|
||||||
| Inclusion => TokenCategory::SpecialBinOp,
|
| Inclusion => TokenCategory::SpecialBinOp,
|
||||||
|
|
|
@ -16,13 +16,13 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Expr::Array(array) => match array {
|
Expr::Array(array) => match array {
|
||||||
Array::Normal(arr) => {
|
Array::Normal(arr) => {
|
||||||
let (elems, _, _) = arr.elems.deconstruct();
|
let (elems, ..) = arr.elems.deconstruct();
|
||||||
let mut const_elems = vec![];
|
let mut const_elems = vec![];
|
||||||
for elem in elems.into_iter() {
|
for elem in elems.into_iter() {
|
||||||
let const_expr = Self::validate_const_expr(elem.expr)?;
|
let const_expr = Self::validate_const_expr(elem.expr)?;
|
||||||
const_elems.push(ConstPosArg::new(const_expr));
|
const_elems.push(ConstPosArg::new(const_expr));
|
||||||
}
|
}
|
||||||
let elems = ConstArgs::new(const_elems, vec![], None);
|
let elems = ConstArgs::new(const_elems, None, vec![], None);
|
||||||
let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
|
let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
|
||||||
Ok(ConstExpr::Array(const_arr))
|
Ok(ConstExpr::Array(const_arr))
|
||||||
}
|
}
|
||||||
|
@ -34,13 +34,13 @@ impl Parser {
|
||||||
},
|
},
|
||||||
Expr::Set(set) => match set {
|
Expr::Set(set) => match set {
|
||||||
Set::Normal(set) => {
|
Set::Normal(set) => {
|
||||||
let (elems, _, _) = set.elems.deconstruct();
|
let (elems, ..) = set.elems.deconstruct();
|
||||||
let mut const_elems = vec![];
|
let mut const_elems = vec![];
|
||||||
for elem in elems.into_iter() {
|
for elem in elems.into_iter() {
|
||||||
let const_expr = Self::validate_const_expr(elem.expr)?;
|
let const_expr = Self::validate_const_expr(elem.expr)?;
|
||||||
const_elems.push(ConstPosArg::new(const_expr));
|
const_elems.push(ConstPosArg::new(const_expr));
|
||||||
}
|
}
|
||||||
let elems = ConstArgs::new(const_elems, vec![], None);
|
let elems = ConstArgs::new(const_elems, None, vec![], None);
|
||||||
let const_set = ConstSet::new(set.l_brace, set.r_brace, elems);
|
let const_set = ConstSet::new(set.l_brace, set.r_brace, elems);
|
||||||
Ok(ConstExpr::Set(const_set))
|
Ok(ConstExpr::Set(const_set))
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,13 @@ impl Parser {
|
||||||
},
|
},
|
||||||
Expr::Tuple(tuple) => match tuple {
|
Expr::Tuple(tuple) => match tuple {
|
||||||
Tuple::Normal(tup) => {
|
Tuple::Normal(tup) => {
|
||||||
let (elems, _, paren) = tup.elems.deconstruct();
|
let (elems, _, _, paren) = tup.elems.deconstruct();
|
||||||
let mut const_elems = vec![];
|
let mut const_elems = vec![];
|
||||||
for elem in elems.into_iter() {
|
for elem in elems.into_iter() {
|
||||||
let const_expr = Self::validate_const_expr(elem.expr)?;
|
let const_expr = Self::validate_const_expr(elem.expr)?;
|
||||||
const_elems.push(ConstPosArg::new(const_expr));
|
const_elems.push(ConstPosArg::new(const_expr));
|
||||||
}
|
}
|
||||||
let elems = ConstArgs::new(const_elems, vec![], paren);
|
let elems = ConstArgs::pos_only(const_elems, paren);
|
||||||
let const_tup = ConstTuple::new(elems);
|
let const_tup = ConstTuple::new(elems);
|
||||||
Ok(ConstExpr::Tuple(const_tup))
|
Ok(ConstExpr::Tuple(const_tup))
|
||||||
}
|
}
|
||||||
|
@ -100,13 +100,13 @@ impl Parser {
|
||||||
"complex const function call",
|
"complex const function call",
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let (pos_args, _, paren) = call.args.deconstruct();
|
let (pos_args, _, _, paren) = call.args.deconstruct();
|
||||||
let mut const_pos_args = vec![];
|
let mut const_pos_args = vec![];
|
||||||
for elem in pos_args.into_iter() {
|
for elem in pos_args.into_iter() {
|
||||||
let const_expr = Self::validate_const_expr(elem.expr)?;
|
let const_expr = Self::validate_const_expr(elem.expr)?;
|
||||||
const_pos_args.push(ConstPosArg::new(const_expr));
|
const_pos_args.push(ConstPosArg::new(const_expr));
|
||||||
}
|
}
|
||||||
let args = ConstArgs::new(const_pos_args, vec![], paren);
|
let args = ConstArgs::pos_only(const_pos_args, paren);
|
||||||
Ok(ConstExpr::App(ConstApp::new(acc, args)))
|
Ok(ConstExpr::App(ConstApp::new(acc, args)))
|
||||||
}
|
}
|
||||||
// TODO: App, Record,
|
// TODO: App, Record,
|
||||||
|
@ -155,12 +155,18 @@ impl Parser {
|
||||||
fn call_to_predecl_type_spec(call: Call) -> Result<PreDeclTypeSpec, ParseError> {
|
fn call_to_predecl_type_spec(call: Call) -> Result<PreDeclTypeSpec, ParseError> {
|
||||||
match *call.obj {
|
match *call.obj {
|
||||||
Expr::Accessor(Accessor::Ident(ident)) => {
|
Expr::Accessor(Accessor::Ident(ident)) => {
|
||||||
let (_pos_args, _kw_args, paren) = call.args.deconstruct();
|
let (_pos_args, _var_args, _kw_args, paren) = call.args.deconstruct();
|
||||||
let mut pos_args = vec![];
|
let mut pos_args = vec![];
|
||||||
for arg in _pos_args.into_iter() {
|
for arg in _pos_args.into_iter() {
|
||||||
let const_expr = Self::validate_const_expr(arg.expr)?;
|
let const_expr = Self::validate_const_expr(arg.expr)?;
|
||||||
pos_args.push(ConstPosArg::new(const_expr));
|
pos_args.push(ConstPosArg::new(const_expr));
|
||||||
}
|
}
|
||||||
|
let var_args = if let Some(var_args) = _var_args {
|
||||||
|
let const_var_args = Self::validate_const_expr(var_args.expr)?;
|
||||||
|
Some(ConstPosArg::new(const_var_args))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let mut kw_args = vec![];
|
let mut kw_args = vec![];
|
||||||
for arg in _kw_args.into_iter() {
|
for arg in _kw_args.into_iter() {
|
||||||
let const_expr = Self::validate_const_expr(arg.expr)?;
|
let const_expr = Self::validate_const_expr(arg.expr)?;
|
||||||
|
@ -168,7 +174,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Ok(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
|
Ok(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
|
||||||
ident,
|
ident,
|
||||||
ConstArgs::new(pos_args, kw_args, paren),
|
ConstArgs::new(pos_args, var_args, kw_args, paren),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
@ -193,11 +199,11 @@ impl Parser {
|
||||||
};
|
};
|
||||||
non_defaults.push(param);
|
non_defaults.push(param);
|
||||||
}
|
}
|
||||||
let var_args =
|
let var_params =
|
||||||
lambda
|
lambda
|
||||||
.sig
|
.sig
|
||||||
.params
|
.params
|
||||||
.var_args
|
.var_params
|
||||||
.map(|var_args| match (var_args.pat, var_args.t_spec) {
|
.map(|var_args| match (var_args.pat, var_args.t_spec) {
|
||||||
(ParamPattern::VarName(name), Some(t_spec_with_op)) => {
|
(ParamPattern::VarName(name), Some(t_spec_with_op)) => {
|
||||||
ParamTySpec::new(Some(name.into_token()), t_spec_with_op.t_spec)
|
ParamTySpec::new(Some(name.into_token()), t_spec_with_op.t_spec)
|
||||||
|
@ -233,7 +239,7 @@ impl Parser {
|
||||||
bounds,
|
bounds,
|
||||||
lparen,
|
lparen,
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_args,
|
var_params,
|
||||||
defaults,
|
defaults,
|
||||||
lambda.op,
|
lambda.op,
|
||||||
return_t,
|
return_t,
|
||||||
|
@ -269,7 +275,7 @@ impl Parser {
|
||||||
let const_expr = Self::validate_const_expr(elem.expr)?;
|
let const_expr = Self::validate_const_expr(elem.expr)?;
|
||||||
elem_ts.push(ConstPosArg::new(const_expr));
|
elem_ts.push(ConstPosArg::new(const_expr));
|
||||||
}
|
}
|
||||||
Ok(TypeSpec::Enum(ConstArgs::new(elem_ts, vec![], paren)))
|
Ok(TypeSpec::Enum(ConstArgs::pos_only(elem_ts, paren)))
|
||||||
}
|
}
|
||||||
Set::WithLength(set) => {
|
Set::WithLength(set) => {
|
||||||
let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
|
let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
|
||||||
|
|
|
@ -129,10 +129,10 @@ The `log` function, which outputs a log (record) of its arguments, can take any
|
||||||
log "Hello", "World", "!" # Hello World !
|
log "Hello", "World", "!" # Hello World !
|
||||||
```
|
```
|
||||||
|
|
||||||
To define such a function, add `...` to a parameter. This way, the function receives arguments as a variable-length array.
|
To define such a function, add `*` to a parameter. This way, the function receives arguments as a variable-length array.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
f ...x =
|
f *x =
|
||||||
for x, i ->
|
for x, i ->
|
||||||
log i
|
log i
|
||||||
|
|
||||||
|
|
|
@ -130,10 +130,10 @@ f x := 1, y := x = ... # NG
|
||||||
log "Hello", "World", "!" # Hello World !
|
log "Hello", "World", "!" # Hello World !
|
||||||
```
|
```
|
||||||
|
|
||||||
このような関数を定義したいときは、仮引数に`...`を付けます。このようにすると、引数を可変長の配列として受け取ることができます。
|
このような関数を定義したいときは、仮引数に`*`を付けます。このようにすると、引数を可変長の配列として受け取ることができます。
|
||||||
|
|
||||||
```python
|
```python
|
||||||
f x: ...Int =
|
f *x: Int =
|
||||||
for x, i ->
|
for x, i ->
|
||||||
log i
|
log i
|
||||||
|
|
||||||
|
|
|
@ -137,10 +137,10 @@ f x := 1, y := x = ... # NG
|
||||||
log "你好", "世界", "!" # 你好 世界 !
|
log "你好", "世界", "!" # 你好 世界 !
|
||||||
```
|
```
|
||||||
|
|
||||||
要定义这样的函数,请将 `...` 添加到参数中。这样,函数将参数作为可变长度数组接收
|
要定义这样的函数,请将 `*` 添加到参数中。这样,函数将参数作为可变长度数组接收
|
||||||
|
|
||||||
```python
|
```python
|
||||||
f ...x =
|
f *x =
|
||||||
for x, i ->
|
for x, i ->
|
||||||
log i
|
log i
|
||||||
|
|
||||||
|
|
|
@ -137,10 +137,10 @@ f x := 1, y := x = ... # NG
|
||||||
log "你好", "世界", "!" # 你好 世界 !
|
log "你好", "世界", "!" # 你好 世界 !
|
||||||
```
|
```
|
||||||
|
|
||||||
要定義這樣的函數,請將 `...` 添加到參數中。這樣,函數將參數作為可變長度數組接收
|
要定義這樣的函數,請將 `*` 添加到參數中。這樣,函數將參數作為可變長度數組接收
|
||||||
|
|
||||||
```python
|
```python
|
||||||
f ...x =
|
f *x =
|
||||||
for x, i ->
|
for x, i ->
|
||||||
log i
|
log i
|
||||||
|
|
||||||
|
|
3
tests/should_ok/var_args.er
Normal file
3
tests/should_ok/var_args.er
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
p! *x: Int = print! x
|
||||||
|
|
||||||
|
p! 1, 2, 3
|
|
@ -239,3 +239,8 @@ fn exec_multiline_invalid_next() -> Result<(), ()> {
|
||||||
fn exec_quantified_err() -> Result<(), ()> {
|
fn exec_quantified_err() -> Result<(), ()> {
|
||||||
expect_failure("tests/should_err/quantified.er", 2)
|
expect_failure("tests/should_err/quantified.er", 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_var_args() -> Result<(), ()> {
|
||||||
|
expect_success("tests/should_ok/var_args.er")
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue