use crate::err::Error;
use crate::err::Error::TypeError;
use crate::val::{Val, ValType, ValDef, Typed};
use crate::object::ObjRef;
use crate::args::{Args, ArgVec, ArgSpec};
use crate::sym::Symbol;
use std::fmt::Debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArgDecl {
Positional(ValType),
Named(ValDef),
}
#[derive(Debug)]
pub struct FuncDef {
pub name: &'static str,
pub return_type: ValType,
pub args: phf::OrderedMap<&'static str, ArgDecl>,
pub min_args: usize,
pub collect_type: ValType,
pub exec: fn(args: Args) -> Result<Val, Error>,
}
impl Eq for FuncDef {}
impl PartialEq for FuncDef {
fn eq(&self, other: &FuncDef) -> bool {
std::ptr::eq(self as *const FuncDef, other as *const FuncDef)
}
}
pub type Module = phf::Map<&'static str, Symbol>;
pub trait Class {
fn symbols(&self) -> phf::Map<&'static str, Symbol>;
fn class_name(&self) -> &'static str;
}
struct NamedArg {
name: String,
val: Val,
}
struct ArgPrep {
anon: Vec<Val>,
named: Vec<NamedArg>,
extra: Vec<Val>,
}
impl FuncDef {
pub fn is_collect(&self) -> bool {
self.collect_type != ValType::Void
}
fn split_args(&self,
args: Vec<ArgSpec>,
) -> Result<ArgPrep, Error> {
enum State {
Anon,
Named,
Extra,
Unexpected,
}
let mut anon: Vec<Val> = Vec::new();
let mut named: Vec<NamedArg> = Vec::new();
let mut extra: Vec<Val> = Vec::new();
let mut state = State::Anon;
for arg in args {
loop {
match state {
State::Anon => {
if !arg.is_anon() {
state = State::Named;
continue;
} else if anon.len() >= self.min_args {
state = State::Extra;
continue;
} else {
let ArgSpec { name: _, val } = arg;
anon.push(val);
break;
}
},
State::Named => {
if let ArgSpec { name: Some(name), val } = arg {
named.push(NamedArg { name, val });
break;
} else {
state = State::Extra;
continue;
}
},
State::Extra => {
if !self.is_collect() {
println!("ERR: Unexpected extra arguments");
return Err(TypeError);
}else if !arg.is_anon() {
state = State::Unexpected;
continue;
} else {
let ArgSpec { name: _, val } = arg;
extra.push(val);
break;
}
},
State::Unexpected => {
println!("ERR: Unexpected named arguments");
return Err(TypeError);
}
}
}
}
anon.shrink_to_fit();
named.shrink_to_fit();
extra.shrink_to_fit();
Ok(ArgPrep {anon, named, extra})
}
pub fn argvec(&self, this: Option<ObjRef>, args: Vec<ArgSpec>) -> Result<ArgVec, Error> {
let ArgPrep {anon, named, extra} = self.split_args(args)?;
let nr_anon = anon.len();
let nr_named = named.len();
let nr_specified = nr_anon + nr_named;
if nr_specified < self.min_args {
println!("ERR: Not enough specified args: {} ({} + {}) < {}",
nr_specified,
nr_anon,
nr_named,
self.min_args);
return Err(TypeError);
}
if nr_anon > self.args.len() {
println!("ERR: Too many positional args: {} > {}",
nr_anon,
self.args.len());
return Err(TypeError);
}
if self.is_collect() && extra.iter().any(|x| !self.collect_type.compatible_with(x)) {
println!("ERR: Collect argument of wrong type");
return Err(TypeError);
}
let mut args: Vec<Val> = Vec::with_capacity(self.args.len());
for a in anon {
args.push(a);
}
for _ in nr_anon..self.min_args {
args.push(Val::Nil);
}
for dfl in self.args.values().skip(self.min_args) {
if let ArgDecl::Named(val) = dfl {
args.push((*val).into());
} else {
unreachable!();
}
}
for spec in named {
let NamedArg {name, val} = spec;
if let Some(i) = self.args.get_index(&name) {
args[i] = val;
} else {
println!("ERR: Unknown arg: {}", &name);
return Err(TypeError);
}
}
for val in &args[..self.min_args] {
if val.is_nil() {
println!("ERR: Mandatory argument not passed");
return Err(TypeError);
}
}
for ((name, spec), arg) in self.args.entries().zip(args.iter()) {
if !match spec {
ArgDecl::Positional(typ) => { typ.compatible_with(arg) }
ArgDecl::Named(dfl) => { dfl.arg_compatible(arg) },
} {
println!("ERR: Argument type-check failed for {:?}", name);
return Err(TypeError);
}
}
Ok(ArgVec::new(this, args, extra))
}
pub fn args(&self, this: Option<ObjRef>, args: Vec<ArgSpec>) -> Result<Args, Error> {
Ok(self.argvec(this, args)?.into())
}
}