Add user-defined var-params function

This commit is contained in:
Shunsuke Shibayama 2023-01-26 01:20:35 +09:00
parent 4b08fd21a2
commit 23a7e2caf3
28 changed files with 526 additions and 211 deletions

View file

@ -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));
} }

View file

@ -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) = &params.var_args { .chain(if let Some(var_args) = &params.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);

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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,6 +398,18 @@ impl Context {
} }
}; };
if let Some(decl_pt) = opt_decl_t { if let Some(decl_pt) = opt_decl_t {
if kind.is_var_params() {
let spec_t = unknown_len_array_t(spec_t.clone());
self.sub_unify(
decl_pt.typ(),
&spec_t,
sig.t_spec
.as_ref()
.map(|s| s.loc())
.unwrap_or_else(|| sig.loc()),
None,
)?;
} else {
self.sub_unify( self.sub_unify(
decl_pt.typ(), decl_pt.typ(),
&spec_t, &spec_t,
@ -375,23 +420,25 @@ impl Context {
None, None,
)?; )?;
} }
}
Ok(spec_t) Ok(spec_t)
} }
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,
)) ))

View file

@ -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) = &params.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);
} }
} }

View file

@ -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(),

View file

@ -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]

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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,
); );

View file

@ -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),

View file

@ -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",

View file

@ -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" => {

View file

@ -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]

View file

@ -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)

View file

@ -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),

View file

@ -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_ch(&self) -> Option<char> { fn peek_prev_prev_ch(&self) -> Option<char> {
if self.cursor == 0 { self.chars.get(self.cursor.checked_sub(2)?).copied()
None
} else {
self.chars.get(self.cursor - 1).copied()
} }
fn peek_prev_ch(&self) -> Option<char> {
self.chars.get(self.cursor.checked_sub(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())));

View file

@ -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() => {
match arg.expr {
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() => { Expr::Tuple(Tuple::Normal(tup)) if tup.elems.paren.is_none() => {
args.extend_pos(tup.elems.into_iters().0); args.extend_pos(tup.elems.into_iters().0);
} }
other => { other => {
args.push_pos(PosArg::new(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,

View file

@ -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,

View file

@ -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)?;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,3 @@
p! *x: Int = print! x
p! 1, 2, 3

View file

@ -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")
}