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> {
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 {
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 {
tokens.extend(self.gen_from_expr(arg.expr));
}

View file

@ -117,11 +117,12 @@ impl PyCodeGenUnit {
filename: S,
name: T,
firstlineno: u32,
flags: u32,
) -> Self {
Self {
id,
py_version,
codeobj: CodeObj::empty(params, filename, name, firstlineno),
codeobj: CodeObj::empty(params, filename, name, firstlineno, flags),
stack_len: 0,
prev_lineno: firstlineno,
lasti: 0,
@ -878,7 +879,7 @@ impl PyCodeGenerator {
.non_defaults
.iter()
.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("_")]
} else {
vec![]
@ -1048,6 +1049,7 @@ impl PyCodeGenerator {
Str::rc(self.cfg.input.enclosed_name()),
&name,
firstlineno,
0,
));
let mod_name = self.toplevel_block_codeobj().name.clone();
self.emit_load_const(mod_name);
@ -1116,6 +1118,7 @@ impl PyCodeGenerator {
Str::rc(self.cfg.input.enclosed_name()),
ident.inspect(),
ident.ln_begin().unwrap(),
0,
));
self.emit_load_const(ValueObj::None);
self.write_instr(RETURN_VALUE);
@ -1251,7 +1254,12 @@ impl PyCodeGenerator {
self.stack_dec_n(defaults_len - 1);
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;
self.register_cellvars(&mut make_function_flag);
self.emit_load_const(code);
@ -1290,7 +1298,12 @@ impl PyCodeGenerator {
self.stack_dec_n(defaults_len - 1);
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.emit_load_const(code);
if self.py_version.minor < Some(11) {
@ -2650,7 +2663,7 @@ impl PyCodeGenerator {
Expr::Dict(dict) => self.emit_dict(dict),
Expr::Record(rec) => self.emit_record(rec),
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);
}
Expr::Compound(chunks) => self.emit_compound(chunks),
@ -2679,7 +2692,7 @@ impl PyCodeGenerator {
Expr::Dict(dict) => self.emit_dict(dict),
Expr::Record(rec) => self.emit_record(rec),
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);
}
Expr::Compound(chunks) => self.emit_compound(chunks),
@ -2738,6 +2751,7 @@ impl PyCodeGenerator {
Str::rc(self.cfg.input.enclosed_name()),
&name,
firstlineno,
0,
));
let init_stack_len = self.stack_len();
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!());
self.unit_size += 1;
let name = if let Some(name) = opt_name {
@ -2923,6 +2943,7 @@ impl PyCodeGenerator {
Str::rc(self.cfg.input.enclosed_name()),
name,
firstlineno,
flags,
));
let idx_copy_free_vars = if self.py_version.minor >= Some(11) {
let idx_copy_free_vars = self.lasti();
@ -3115,6 +3136,7 @@ impl PyCodeGenerator {
Str::rc(self.cfg.input.enclosed_name()),
"<module>",
1,
0,
));
if self.py_version.minor >= Some(11) {
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::{ConstSubr, HasType, Predicate, SubrKind, Type, UserConstSubr, ValueArgs};
use crate::context::instantiate::ParamKind;
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
use crate::error::{EvalError, EvalErrors, EvalResult, SingleEvalResult};
@ -451,19 +452,19 @@ impl Context {
let pt = self.instantiate_param_ty(
sig,
None,
None,
&mut tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::NonDefault,
)?;
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(
p,
None,
None,
&mut tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::VarParams,
)?;
Some(pt)
} else {
@ -474,10 +475,10 @@ impl Context {
let expr = self.eval_const_expr(&sig.default_val)?;
let pt = self.instantiate_param_ty(
&sig.sig,
Some(expr.t()),
None,
&mut tmp_tv_cache,
RegistrationMode::Normal,
ParamKind::Default(expr.t()),
)?;
default_params.push(pt);
}

View file

@ -37,6 +37,7 @@ use crate::{feature_error, hir};
use RegistrationMode::*;
use Visibility::*;
use super::instantiate::ParamKind;
use super::{ContextKind, MethodInfo};
impl Context {
@ -274,6 +275,7 @@ impl Context {
None,
&mut dummy_tv_cache,
Normal,
ParamKind::NonDefault,
)?;
union_pat_t = self.union(&union_pat_t, &rhs);
}

View file

@ -31,12 +31,38 @@ use crate::unreachable_error;
use TyParamOrdering::*;
use Type::*;
use crate::context::{Context, RegistrationMode};
use crate::context::{Context, DefaultInfo, RegistrationMode};
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
use crate::hir;
use crate::AccessKind;
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
/// 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`.
@ -252,7 +278,13 @@ impl Context {
let opt_decl_t = opt_decl_sig_t
.as_ref()
.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),
Err(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
.as_ref()
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
let pt = match self.instantiate_param_ty(
var_args,
None,
opt_decl_t,
&mut tmp_tv_cache,
mode,
ParamKind::VarParams,
) {
Ok(pt) => pt,
Err(es) => {
@ -288,10 +320,10 @@ impl Context {
.and_then(|subr| subr.default_params.get(n));
match self.instantiate_param_ty(
&p.sig,
Some(default_t),
opt_decl_t,
&mut tmp_tv_cache,
mode,
ParamKind::Default(default_t),
) {
Ok(t) => defaults.push(t),
Err(es) => {
@ -345,6 +377,7 @@ impl Context {
opt_decl_t: Option<&ParamTy>,
tmp_tv_cache: &mut TyVarCache,
mode: RegistrationMode,
kind: ParamKind,
) -> TyCheckResult<Type> {
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)?
@ -365,6 +398,18 @@ impl Context {
}
};
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(
decl_pt.typ(),
&spec_t,
@ -375,23 +420,25 @@ impl Context {
None,
)?;
}
}
Ok(spec_t)
}
pub(crate) fn instantiate_param_ty(
&self,
sig: &NonDefaultParamSignature,
opt_default_t: Option<Type>,
opt_decl_t: Option<&ParamTy>,
tmp_tv_cache: &mut TyVarCache,
mode: RegistrationMode,
kind: ParamKind,
) -> TyCheckResult<ParamTy> {
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode)?;
match (sig.inspect(), opt_default_t) {
(Some(name), Some(default_t)) => Ok(ParamTy::kw_default(name.clone(), t, default_t)),
(Some(name), None) => Ok(ParamTy::kw(name.clone(), t)),
(None, None) => Ok(ParamTy::anonymous(t)),
_ => unreachable!(),
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode, kind.clone())?;
match (sig.inspect(), kind) {
(Some(name), ParamKind::Default(default_t)) => {
Ok(ParamTy::kw_default(name.clone(), t, default_t))
}
(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| {
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
})?;
let var_args = subr
.var_args
let var_params = subr
.var_params
.as_ref()
.map(|p| {
self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode)
@ -947,7 +994,7 @@ impl Context {
Ok(subr_t(
SubrKind::from(subr.arrow.kind),
non_defaults,
var_args,
var_params,
defaults,
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 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::value::{GenTypeObj, TypeObj, ValueObj};
use crate::ty::{HasType, ParamTy, SubrType, Type};
@ -37,7 +39,7 @@ use Mutability::*;
use RegistrationMode::*;
use Visibility::*;
use super::instantiate::TyVarCache;
use super::instantiate::{ParamKind, TyVarCache};
const UBAR: &Str = &Str::ever("_");
@ -240,14 +242,15 @@ impl Context {
fn assign_param(
&mut self,
sig: &ast::NonDefaultParamSignature,
default_val_exists: bool,
opt_decl_t: Option<&ParamTy>,
kind: ParamKind,
) -> TyCheckResult<()> {
let vis = if cfg!(feature = "py_compatible") {
Public
} else {
Private
};
let default = kind.default_info();
match &sig.pat {
// Literal patterns will be desugared to discard patterns
ast::ParamPattern::Lit(_) => unreachable!(),
@ -257,6 +260,7 @@ impl Context {
opt_decl_t,
&mut TyVarCache::new(self.level, self),
Normal,
kind,
)?;
let def_id = DefId(get_hash(&(&self.name, "_")));
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault);
@ -288,8 +292,13 @@ impl Context {
} else {
// ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let spec_t =
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
let spec_t = self.instantiate_param_sig_t(
sig,
opt_decl_t,
&mut dummy_tv_cache,
Normal,
kind,
)?;
if &name.inspect()[..] == "self" {
if let Some(self_t) = self.rec_get_self_t() {
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
@ -297,11 +306,6 @@ impl Context {
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 kind = VarKind::parameter(def_id, default);
let muty = Mutability::from(&name.inspect()[..]);
@ -334,8 +338,13 @@ impl Context {
} else {
// ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let spec_t =
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
let spec_t = self.instantiate_param_sig_t(
sig,
opt_decl_t,
&mut dummy_tv_cache,
Normal,
kind,
)?;
if &name.inspect()[..] == "self" {
if let Some(self_t) = self.rec_get_self_t() {
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 default = if default_val_exists {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
};
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
let vi = VarInfo::new(
spec_t,
@ -379,8 +383,13 @@ impl Context {
} else {
// ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
let spec_t =
self.instantiate_param_sig_t(sig, opt_decl_t, &mut dummy_tv_cache, Normal)?;
let spec_t = self.instantiate_param_sig_t(
sig,
opt_decl_t,
&mut dummy_tv_cache,
Normal,
kind,
)?;
if &name.inspect()[..] == "self" {
if let Some(self_t) = self.rec_get_self_t() {
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 default = if default_val_exists {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
};
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, name))), default);
let vi = VarInfo::new(
spec_t,
@ -433,7 +437,18 @@ impl Context {
.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);
}
}
@ -442,18 +457,22 @@ impl Context {
.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);
}
}
} else {
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);
}
}
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);
}
}

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('!') {
self.errs.push(EffectError::proc_assign_error(
self.cfg.input.clone(),

View file

@ -1637,7 +1637,7 @@ impl DefaultParamSignature {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Params {
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_args: Option<Box<NonDefaultParamSignature>>,
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub parens: Option<(Token, Token)>,
}
@ -1648,7 +1648,7 @@ impl fmt::Display for Params {
f,
"({}, {}, {})",
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
fmt_option!(pre "*", &self.var_params),
fmt_vec(&self.defaults)
)
}
@ -1659,7 +1659,7 @@ impl NoTypeDisplay for Params {
format!(
"({}, {}, {})",
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
fmt_option!(pre "*", &self.var_params),
self.defaults
.iter()
.map(|p| p.to_string_notype())
@ -1678,7 +1678,7 @@ impl Locational for Params {
}
match (
self.non_defaults.first(),
self.var_args.as_ref(),
self.var_params.as_ref(),
self.defaults.last(),
) {
(Some(l), _, Some(r)) => Location::concat(l, r),
@ -1714,7 +1714,7 @@ impl Params {
) -> Self {
Self {
non_defaults,
var_args,
var_params: var_args,
defaults,
parens,
}
@ -1723,14 +1723,19 @@ impl Params {
pub const fn ref_deconstruct(&self) -> RefRawParams {
(
&self.non_defaults,
&self.var_args,
&self.var_params,
&self.defaults,
&self.parens,
)
}
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]

View file

@ -92,7 +92,7 @@ Parameters:
* `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.

View file

@ -26,4 +26,4 @@
.getdoc: (object: Obj) -> Str
.getcomments: (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
.Self: Type
.TypeAlias: Type
.Tuple: (...Type) -> Type
.Union: (...Type) -> Type
.Tuple: (*Type) -> Type
.Union: (*Type) -> Type
.Optional: (Type) -> Type
.Callable: (...Type) -> Type
.Concatenate: (...Type) -> Type
.Callable: (*Type) -> Type
.Concatenate: (*Type) -> Type
.Type: (Type) -> Type
.Literal: (...Obj) -> Type
.Literal: (*Obj) -> Type
.ClassVar: (Type) -> Type
.Final: (Type) -> Type
.Required: (Type) -> Type
.NotRequired: (Type) -> Type
.Annotated: (Type, ...Obj) -> Type
.Annotated: (Type, *Obj) -> Type
.TypeGuard: (Type) -> Type
.Generic: (Type) -> Type
.TypeVar: (Str) -> Type

View file

@ -862,7 +862,7 @@ impl ASTLowerer {
} else {
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(
Vec::with_capacity(pos_args.len()),
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() {
match self.lower_expr(arg.expr) {
Ok(expr) => hir_args.push_kw(hir::KwArg::new(arg.keyword, expr)),
@ -1032,7 +1042,7 @@ impl ASTLowerer {
} else {
let hir_params = hir::Params::new(
params.non_defaults,
params.var_args,
params.var_params,
hir_defaults,
params.parens,
);

View file

@ -216,15 +216,17 @@ impl CodeObj {
filename: S,
name: T,
firstlineno: u32,
flags: u32,
) -> Self {
let name = name.into();
let var_args_defined = (flags & CodeObjFlags::VarArgs as u32 != 0) as u32;
Self {
argcount: params.len() as u32,
argcount: params.len() as u32 - var_args_defined,
posonlyargcount: 0,
kwonlyargcount: 0,
nlocals: params.len() as u32,
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),
consts: Vec::with_capacity(4),
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])
}
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 {
poly(
"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>) {
match self {
Self::Pos { name, ty } => (name, ty, None),
@ -242,7 +257,7 @@ impl LimitedDisplay for SubrType {
if !self.non_default_params.is_empty() {
write!(f, ", ")?;
}
write!(f, "...")?;
write!(f, "*")?;
var_params.typ().limited_fmt(f, limit - 1)?;
}
for pt in self.default_params.iter() {
@ -501,7 +516,7 @@ impl Ownership {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ArgsOwnership {
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)>,
}
@ -519,7 +534,12 @@ impl fmt::Display for ArgsOwnership {
}
}
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() {
write!(f, ", {name} := {o:?}")?;
@ -532,7 +552,7 @@ impl fmt::Display for ArgsOwnership {
impl ArgsOwnership {
pub const fn new(
non_defaults: Vec<(Option<Str>, Ownership)>,
var_params: Option<(Str, Ownership)>,
var_params: Option<(Option<Str>, Ownership)>,
defaults: Vec<(Str, Ownership)>,
) -> Self {
Self {
@ -1295,7 +1315,7 @@ impl Type {
let var_args = subr
.var_params
.as_ref()
.map(|t| (t.name().unwrap().clone(), t.typ().ownership()));
.map(|t| (t.name().cloned(), t.typ().ownership()));
let mut d_args = vec![];
for d_param in subr.default_params.iter() {
let ownership = match d_param.typ() {
@ -1670,7 +1690,6 @@ impl Type {
}
pub fn container_len(&self) -> Option<usize> {
log!(err "{self}");
match self {
Self::Poly { name, params } => match &name[..] {
"Array" => {

View file

@ -159,7 +159,7 @@ impl KwArg {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Args {
pos_args: Vec<PosArg>,
// var_args: Option<Box<PosArg>>,
pub(crate) var_args: Option<Box<PosArg>>,
kw_args: Vec<KwArg>,
pub paren: Option<(Token, Token)>,
}
@ -194,25 +194,44 @@ impl Locational for Args {
// impl_stream!(Args, Arg, args);
impl Args {
pub const fn new(
pub fn new(
pos_args: Vec<PosArg>,
var_args: Option<PosArg>,
kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
}
}
pub const fn empty() -> Self {
Self::new(vec![], vec![], None)
pub fn pos_only(pos_args: Vec<PosArg>, paren: Option<(Token, Token)>) -> Self {
Self::new(pos_args, None, vec![], paren)
}
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
}
// for replacing to hir::Args
pub fn deconstruct(self) -> (Vec<PosArg>, Vec<KwArg>, Option<(Token, Token)>) {
(self.pos_args, self.kw_args, self.paren)
#[allow(clippy::type_complexity)]
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 {
@ -267,6 +286,10 @@ impl Args {
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) {
self.kw_args.push(arg);
}
@ -1015,6 +1038,11 @@ impl BinOp {
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)]
@ -1045,6 +1073,11 @@ impl UnaryOp {
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)]
@ -1660,6 +1693,7 @@ impl ConstKwArg {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ConstArgs {
pos_args: Vec<ConstPosArg>,
var_args: Option<Box<ConstPosArg>>,
kw_args: Vec<ConstKwArg>,
paren: Option<(Token, Token)>,
}
@ -1691,24 +1725,43 @@ impl Locational for ConstArgs {
// impl_stream!(ConstArgs, ConstKwArg, pos_args);
impl ConstArgs {
pub const fn new(
pub fn new(
pos_args: Vec<ConstPosArg>,
var_args: Option<ConstPosArg>,
kw_args: Vec<ConstKwArg>,
paren: Option<(Token, Token)>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
}
}
pub fn deconstruct(self) -> (Vec<ConstPosArg>, Vec<ConstKwArg>, Option<(Token, Token)>) {
(self.pos_args, self.kw_args, self.paren)
pub fn pos_only(pos_args: Vec<ConstPosArg>, paren: Option<(Token, Token)>) -> Self {
Self::new(pos_args, None, vec![], paren)
}
pub const fn empty() -> Self {
Self::new(vec![], vec![], None)
#[allow(clippy::type_complexity)]
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 {
@ -1741,12 +1794,13 @@ impl ConstArgs {
}
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(
pos_args
.into_iter()
.map(|arg| PosArg::new(arg.expr.downcast()))
.collect(),
var_args.map(|arg| PosArg::new(arg.expr.downcast())),
kw_args
.into_iter()
// TODO t_spec
@ -1900,7 +1954,7 @@ pub struct SubrTypeSpec {
pub bounds: TypeBoundSpecs,
pub lparen: Option<Token>,
pub non_defaults: Vec<ParamTySpec>,
pub var_args: Option<Box<ParamTySpec>>,
pub var_params: Option<Box<ParamTySpec>>,
pub defaults: Vec<DefaultParamTySpec>,
pub arrow: Token,
pub return_t: Box<TypeSpec>,
@ -1915,7 +1969,7 @@ impl fmt::Display for SubrTypeSpec {
f,
"({}, {}, {}) {} {}",
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
fmt_option!(pre "*", &self.var_params),
fmt_vec(&self.defaults),
self.arrow.content,
self.return_t
@ -1941,7 +1995,7 @@ impl SubrTypeSpec {
bounds: TypeBoundSpecs,
lparen: Option<Token>,
non_defaults: Vec<ParamTySpec>,
var_args: Option<ParamTySpec>,
var_params: Option<ParamTySpec>,
defaults: Vec<DefaultParamTySpec>,
arrow: Token,
return_t: TypeSpec,
@ -1950,7 +2004,7 @@ impl SubrTypeSpec {
bounds,
lparen,
non_defaults,
var_args: var_args.map(Box::new),
var_params: var_params.map(Box::new),
defaults,
arrow,
return_t: Box::new(return_t),
@ -2162,6 +2216,7 @@ impl TypeSpec {
.into_iter()
.map(|lit| ConstPosArg::new(ConstExpr::Lit(lit)))
.collect(),
None,
vec![],
None,
))
@ -3044,7 +3099,7 @@ impl DefaultParamSignature {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Params {
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_args: Option<Box<NonDefaultParamSignature>>,
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub parens: Option<(Token, Token)>,
}
@ -3055,7 +3110,7 @@ impl fmt::Display for Params {
f,
"({}, {}, {})",
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
fmt_option!(pre "...", &self.var_params),
fmt_vec(&self.defaults)
)
}
@ -3071,7 +3126,7 @@ impl Locational for Params {
}
match (
self.non_defaults.first(),
self.var_args.as_ref(),
self.var_params.as_ref(),
self.defaults.last(),
) {
(Some(l), _, Some(r)) => Location::concat(l, r),
@ -3094,20 +3149,25 @@ type RawParams = (
impl Params {
pub fn new(
non_defaults: Vec<NonDefaultParamSignature>,
var_args: Option<NonDefaultParamSignature>,
var_params: Option<NonDefaultParamSignature>,
defaults: Vec<DefaultParamSignature>,
parens: Option<(Token, Token)>,
) -> Self {
Self {
non_defaults,
var_args: var_args.map(Box::new),
var_params: var_params.map(Box::new),
defaults,
parens,
}
}
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]

View file

@ -204,7 +204,7 @@ impl Parser {
let mut vars = Vars::empty();
match tuple {
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 {
let sig = self
.convert_rhs_to_sig(arg.expr)
@ -312,7 +312,7 @@ impl Parser {
) -> ParseResult<TypeBoundSpecs> {
debug_call_info!(self);
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() {
let bound = self
.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> {
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);
for (i, arg) in pos_args.into_iter().enumerate() {
let nd_param = self
@ -356,6 +356,12 @@ impl Parser {
.map_err(|_| self.stack_dec(fn_name!()))?;
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
for arg in kw_args.into_iter() {
let d_param = self
@ -566,11 +572,17 @@ impl Parser {
match tuple {
Tuple::Normal(tup) => {
let mut params = vec![];
let (elems, _, parens) = tup.elems.deconstruct();
let (elems, var_args, _, parens) = tup.elems.deconstruct();
for arg in elems.into_iter() {
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);
Ok(ParamTuplePattern::new(params))
}
@ -640,6 +652,23 @@ impl Parser {
debug_exit_info!(self);
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 => {
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err);
@ -677,7 +706,7 @@ impl Parser {
debug_call_info!(self);
match tuple {
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);
for (i, arg) in pos_args.into_iter().enumerate() {
let param = self
@ -685,6 +714,12 @@ impl Parser {
.map_err(|_| self.stack_dec(fn_name!()))?;
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 {
let param = self
.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 {
let (pos_args, kw_args, paren) = args.deconstruct();
let (pos_args, var_args, kw_args, paren) = args.deconstruct();
let pos_args = pos_args
.into_iter()
.map(|arg| PosArg::new(desugar(arg.expr)))
.collect();
let var_args = var_args.map(|arg| PosArg::new(desugar(arg.expr)));
let kw_args = kw_args
.into_iter()
.map(|arg| {
KwArg::new(arg.keyword, arg.t_spec, desugar(arg.expr)) // TODO: t_spec
})
.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 {
@ -138,12 +139,12 @@ impl Desugarer {
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _) = arr.elems.deconstruct();
let (elems, _, _, _) = arr.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(desugar(elem.expr)))
.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);
Expr::Array(Array::Normal(arr))
}
@ -168,24 +169,24 @@ impl Desugarer {
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
let (elems, _, paren) = tup.elems.deconstruct();
let (elems, _, _, paren) = tup.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(desugar(elem.expr)))
.collect();
let new_tup = Args::new(elems, vec![], paren);
let new_tup = Args::new(elems, None, vec![], paren);
let tup = NormalTuple::new(new_tup);
Expr::Tuple(Tuple::Normal(tup))
}
},
Expr::Set(set) => match set {
astSet::Normal(set) => {
let (elems, _, _) = set.elems.deconstruct();
let (elems, _, _, _) = set.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(desugar(elem.expr)))
.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);
Expr::Set(astSet::Normal(set))
}
@ -393,13 +394,12 @@ impl Desugarer {
let return_t_spec = sig.return_t_spec;
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 args = Args::new(
let args = Args::pos_only(
vec![
PosArg::new(Expr::dummy_local("_")), // dummy argument, will be removed in line 56
PosArg::new(Expr::Lambda(first_branch)),
PosArg::new(Expr::Lambda(second_branch)),
],
vec![],
None,
);
let call = match_symbol.call(args);
@ -1075,9 +1075,8 @@ impl Desugarer {
match acc {
// x[y] => x.__getitem__(y)
Accessor::Subscr(subscr) => {
let args = Args::new(
let args = Args::pos_only(
vec![PosArg::new(Self::rec_desugar_acc(*subscr.index))],
vec![],
None,
);
let line = subscr.obj.ln_begin().unwrap();
@ -1094,7 +1093,7 @@ impl Desugarer {
}
// x.0 => x.__Tuple_getitem__(0)
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 call = Call::new(
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 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を用意
#[derive(Debug, Default)]
pub struct LexerRunner {
@ -274,7 +290,7 @@ impl Lexer /*<'a>*/ {
// +, -, * etc. may be pre/bin
// 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() {
// unary: `[ +`, `= +`, `+ +`, `, +`, `:: +`
TokenCategory::LEnclosure
@ -286,14 +302,17 @@ impl Lexer /*<'a>*/ {
| TokenCategory::LambdaOp
| TokenCategory::StrInterpLeft
| TokenCategory::StrInterpMid
| TokenCategory::BOF => Some(false),
// bin: `] +`, `1 +`, `true and[true]`, `}aaa"`
TokenCategory::REnclosure | TokenCategory::Literal | TokenCategory::StrInterpRight => {
Some(true)
}
// bin: `fn +1`
// NOTE: if semantic analysis shows `fn` is a function, should this be rewritten to be unary?
TokenCategory::Symbol => Some(true),
| TokenCategory::BOF => Some(OpFix::Prefix),
TokenCategory::REnclosure
| TokenCategory::Literal
| TokenCategory::StrInterpRight
| TokenCategory::Symbol => match (self.peek_prev_prev_ch(), self.peek_cur_ch()) {
(Some(' '), Some(' ')) => Some(OpFix::Infix), // x + 1: bin
(Some(' '), Some(_)) => Some(OpFix::Prefix), // x +1: unary
(Some(_), Some(' ')) => Some(OpFix::Infix), // x+ 1 : bin
(Some(_), Some(_)) => Some(OpFix::Infix), // x+1: bin
_ => None,
},
_ => None,
}
}
@ -309,12 +328,12 @@ impl Lexer /*<'a>*/ {
self.chars.get(now).copied()
}
fn peek_prev_ch(&self) -> Option<char> {
if self.cursor == 0 {
None
} else {
self.chars.get(self.cursor - 1).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> {
self.chars.get(self.cursor.checked_sub(1)?).copied()
}
#[inline]
@ -1264,10 +1283,10 @@ impl Iterator for Lexer /*<'a>*/ {
}
Some('?') => self.accept(Try, "?"),
Some('+') => {
let kind = match self.is_bin_position() {
Some(true) => Plus,
Some(false) => PrePlus,
None => {
let kind = match self.op_fix() {
Some(OpFix::Infix) => Plus,
Some(OpFix::Prefix) => PrePlus,
_ => {
let token = self.emit_token(Illegal, "+");
return Some(Err(LexError::simple_syntax_error(0, token.loc())));
}
@ -1280,9 +1299,9 @@ impl Iterator for Lexer /*<'a>*/ {
self.accept(FuncArrow, "->")
}
_ => {
match self.is_bin_position() {
Some(true) => self.accept(Minus, "-"),
Some(false) => {
match self.op_fix() {
Some(OpFix::Infix) => self.accept(Minus, "-"),
Some(OpFix::Prefix) => {
// IntLit (negative number)
if self
.peek_cur_ch()
@ -1294,7 +1313,7 @@ impl Iterator for Lexer /*<'a>*/ {
self.accept(PreMinus, "-")
}
}
None => {
_ => {
let token = self.emit_token(Illegal, "-");
Some(Err(LexError::simple_syntax_error(0, token.loc())))
}
@ -1302,13 +1321,15 @@ impl Iterator for Lexer /*<'a>*/ {
}
},
Some('*') => match self.peek_cur_ch() {
// TODO: infix/prefix
Some('*') => {
self.consume();
self.accept(Pow, "**")
}
_ => {
let kind = match self.is_bin_position() {
Some(true) => Star,
let kind = match self.op_fix() {
Some(OpFix::Infix) => Star,
Some(OpFix::Prefix) => PreStar,
_ => {
let token = self.emit_token(Illegal, "*");
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> {
debug_call_info!(self);
if self.cur_category_is(TC::REnclosure) {
let args = Args::new(vec![], vec![], None);
let args = Args::empty();
debug_exit_info!(self);
return Ok(ArrayInner::Normal(args));
}
let first = self
.try_reduce_elem()
.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() {
Some(Semi) => {
self.lpop();
@ -693,11 +693,11 @@ impl Parser {
Some(RParen) => {
rp = Some(self.lpop());
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) => {
debug_exit_info!(self);
return Ok(Args::new(vec![], vec![], None));
return Ok(Args::pos_only(vec![], None));
}
Some(Newline) if style.needs_parens() => {
self.skip();
@ -712,8 +712,21 @@ impl Parser {
.try_reduce_arg(in_type_args)
.map_err(|_| self.stack_dec(fn_name!()))?
{
PosOrKwArg::Pos(arg) => Args::new(vec![arg], vec![], None),
PosOrKwArg::Kw(arg) => Args::new(vec![], vec![arg], None),
PosOrKwArg::Pos(PosArg {
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 {
match self.peek_kind() {
@ -756,8 +769,8 @@ impl Parser {
}
if style.needs_parens() && self.cur_is(RParen) {
let rp = self.lpop();
let (pos_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp)));
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, Some((lp.unwrap(), rp)));
break;
}
if !args.kw_is_empty() {
@ -770,6 +783,20 @@ impl Parser {
.try_reduce_arg(in_type_args)
.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) => {
args.push_pos(arg);
}
@ -782,12 +809,12 @@ impl Parser {
Some(RParen) => {
if let Some(lp) = lp {
let rp = self.lpop();
let (pos_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, kw_args, Some((lp, rp)));
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, Some((lp, rp)));
} else {
// e.g. f(g 1)
let (pos_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, kw_args, None);
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, None);
}
break;
}
@ -805,8 +832,8 @@ impl Parser {
debug_exit_info!(self);
return Err(());
}
let (pos_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp)));
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, Some((lp.unwrap(), rp)));
}
break;
}
@ -1659,11 +1686,9 @@ impl Parser {
Signature::Var(var) => {
let mut last = def.body.block.pop().unwrap();
for deco in decos.into_iter() {
last = deco.into_expr().call_expr(Args::new(
vec![PosArg::new(last)],
vec![],
None,
));
last = deco
.into_expr()
.call_expr(Args::pos_only(vec![PosArg::new(last)], None));
}
def.body.block.push(last);
let expr = Expr::Def(Def::new(Signature::Var(var), def.body));
@ -1699,7 +1724,7 @@ impl Parser {
};
if self.cur_is(RParen) {
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));
debug_exit_info!(self);
return Ok(Expr::Tuple(unit));
@ -2268,7 +2293,7 @@ impl Parser {
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 {
match self.peek_kind() {
Some(Comma) => {
@ -2337,8 +2362,22 @@ impl Parser {
) -> ParseResult<Tuple> {
debug_call_info!(self);
let mut args = match first_elem {
PosOrKwArg::Pos(pos) => Args::new(vec![pos], vec![], None),
PosOrKwArg::Kw(kw) => Args::new(vec![], vec![kw], None),
PosOrKwArg::Pos(PosArg {
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)]
loop {
@ -2360,14 +2399,25 @@ impl Parser {
.try_reduce_arg(false)
.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() => {
args.extend_pos(tup.elems.into_iters().0);
}
other => {
args.push_pos(PosArg::new(other));
}
},
}
}
PosOrKwArg::Pos(arg) => {
let err = ParseError::syntax_error(
line!() as usize,
@ -2451,7 +2501,7 @@ impl Parser {
let call = Call::new(
str_func,
None,
Args::new(vec![PosArg::new(mid_expr)], vec![], None),
Args::pos_only(vec![PosArg::new(mid_expr)], None),
);
let op = Token::new(
Plus,

View file

@ -48,6 +48,8 @@ pub enum TokenKind {
// PreAt, // @ (unary)
/// ! (unary)
Mutate,
PreStar, // * (unary)
PreDblStar, // ** (unary)
/// ? (postfix)
Try,
/// `+`
@ -164,8 +166,6 @@ pub enum TokenKind {
VBar,
/// _
UBar,
/// ...
Spread,
/// \n
Newline,
/// ;
@ -229,7 +229,9 @@ impl TokenKind {
StrInterpLeft => TokenCategory::StrInterpLeft,
StrInterpMid => TokenCategory::StrInterpMid,
StrInterpRight => TokenCategory::StrInterpRight,
PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp,
PrePlus | PreMinus | PreBitNot | Mutate | PreStar | PreDblStar | RefOp | RefMutOp => {
TokenCategory::UnaryOp
}
Try => TokenCategory::PostfixOp,
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus
| Inclusion => TokenCategory::SpecialBinOp,

View file

@ -16,13 +16,13 @@ impl Parser {
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _) = arr.elems.deconstruct();
let (elems, ..) = arr.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.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);
Ok(ConstExpr::Array(const_arr))
}
@ -34,13 +34,13 @@ impl Parser {
},
Expr::Set(set) => match set {
Set::Normal(set) => {
let (elems, _, _) = set.elems.deconstruct();
let (elems, ..) = set.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.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);
Ok(ConstExpr::Set(const_set))
}
@ -69,13 +69,13 @@ impl Parser {
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
let (elems, _, paren) = tup.elems.deconstruct();
let (elems, _, _, paren) = tup.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.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);
Ok(ConstExpr::Tuple(const_tup))
}
@ -100,13 +100,13 @@ impl Parser {
"complex const function call",
));
};
let (pos_args, _, paren) = call.args.deconstruct();
let (pos_args, _, _, paren) = call.args.deconstruct();
let mut const_pos_args = vec![];
for elem in pos_args.into_iter() {
let const_expr = Self::validate_const_expr(elem.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)))
}
// TODO: App, Record,
@ -155,12 +155,18 @@ impl Parser {
fn call_to_predecl_type_spec(call: Call) -> Result<PreDeclTypeSpec, ParseError> {
match *call.obj {
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![];
for arg in _pos_args.into_iter() {
let const_expr = Self::validate_const_expr(arg.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![];
for arg in _kw_args.into_iter() {
let const_expr = Self::validate_const_expr(arg.expr)?;
@ -168,7 +174,7 @@ impl Parser {
}
Ok(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
ident,
ConstArgs::new(pos_args, kw_args, paren),
ConstArgs::new(pos_args, var_args, kw_args, paren),
)))
}
_ => todo!(),
@ -193,11 +199,11 @@ impl Parser {
};
non_defaults.push(param);
}
let var_args =
let var_params =
lambda
.sig
.params
.var_args
.var_params
.map(|var_args| match (var_args.pat, var_args.t_spec) {
(ParamPattern::VarName(name), Some(t_spec_with_op)) => {
ParamTySpec::new(Some(name.into_token()), t_spec_with_op.t_spec)
@ -233,7 +239,7 @@ impl Parser {
bounds,
lparen,
non_defaults,
var_args,
var_params,
defaults,
lambda.op,
return_t,
@ -269,7 +275,7 @@ impl Parser {
let const_expr = Self::validate_const_expr(elem.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) => {
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 !
```
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
f ...x =
f *x =
for x, i ->
log i

View file

@ -130,10 +130,10 @@ f x := 1, y := x = ... # NG
log "Hello", "World", "!" # Hello World !
```
このような関数を定義したいときは、仮引数に`...`を付けます。このようにすると、引数を可変長の配列として受け取ることができます。
このような関数を定義したいときは、仮引数に`*`を付けます。このようにすると、引数を可変長の配列として受け取ることができます。
```python
f x: ...Int =
f *x: Int =
for x, i ->
log i

View file

@ -137,10 +137,10 @@ f x := 1, y := x = ... # NG
log "你好", "世界", "" # 你好 世界
```
要定义这样的函数,请将 `...` 添加到参数中。这样,函数将参数作为可变长度数组接收
要定义这样的函数,请将 `*` 添加到参数中。这样,函数将参数作为可变长度数组接收
```python
f ...x =
f *x =
for x, i ->
log i

View file

@ -137,10 +137,10 @@ f x := 1, y := x = ... # NG
log "你好", "世界", "" # 你好 世界
```
要定義這樣的函數,請將 `...` 添加到參數中。這樣,函數將參數作為可變長度數組接收
要定義這樣的函數,請將 `*` 添加到參數中。這樣,函數將參數作為可變長度數組接收
```python
f ...x =
f *x =
for x, 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<(), ()> {
expect_failure("tests/should_err/quantified.er", 2)
}
#[test]
fn exec_var_args() -> Result<(), ()> {
expect_success("tests/should_ok/var_args.er")
}