mirror of
https://github.com/Dummi26/mers.git
synced 2025-04-28 18:16:05 +02:00
add function type annotation (Input1 -> Output1, Input2 -> Output2)
This commit is contained in:
parent
c130678caf
commit
6d6853cc9f
@ -50,12 +50,12 @@ impl Function {
|
||||
pub fn get_as_type(&self) -> FunctionT {
|
||||
let out = Arc::clone(&self.out);
|
||||
let info = Arc::clone(&self.info_check);
|
||||
FunctionT(Arc::new(move |a| {
|
||||
FunctionT(Ok(Arc::new(move |a| {
|
||||
let lock = info.lock().unwrap();
|
||||
let mut info = lock.clone();
|
||||
drop(lock);
|
||||
out(a, &mut info)
|
||||
}))
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,11 +87,22 @@ impl MersData for Function {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FunctionT(pub Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>);
|
||||
pub struct FunctionT(
|
||||
pub Result<Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>, Vec<(Type, Type)>>,
|
||||
);
|
||||
impl FunctionT {
|
||||
/// get output type
|
||||
pub fn o(&self, i: &Type) -> Result<Type, CheckError> {
|
||||
match &self.0 {
|
||||
Ok(f) => f(i),
|
||||
Err(v) => v.iter().find(|(a, _)| i.is_included_in(a)).map(|(_, o)| o.clone()).ok_or_else(|| format!("This function, which was defined with an explicit type, cannot be called with an argument of type {i}.").into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl MersType for FunctionT {
|
||||
fn iterable(&self) -> Option<Type> {
|
||||
// if this function can be called with an empty tuple and returns `()` or `(T)`, it can act as an iterator with type `T`.
|
||||
if let Ok(t) = self.0(&Type::empty_tuple()) {
|
||||
if let Ok(t) = self.o(&Type::empty_tuple()) {
|
||||
let mut out = Type::empty();
|
||||
for t in &t.types {
|
||||
if let Some(t) = t.as_any().downcast_ref::<super::tuple::TupleT>() {
|
||||
@ -109,12 +120,39 @@ impl MersType for FunctionT {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
|
||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||
if let Err(s) = &self.0 {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
if let Err(o) = &other.0 {
|
||||
s.iter().all(|(si, so)| {
|
||||
o.iter()
|
||||
.any(|(oi, oo)| si.is_same_type_as(oi) && so.is_same_type_as(oo))
|
||||
}) && o.iter().all(|(oi, oo)| {
|
||||
s.iter()
|
||||
.any(|(si, so)| oi.is_same_type_as(si) && oo.is_same_type_as(so))
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
fn is_included_in_single(&self, _target: &dyn MersType) -> bool {
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
|
||||
if let Some(target) = target.as_any().downcast_ref::<Self>() {
|
||||
if let Err(s) = &target.0 {
|
||||
s.iter()
|
||||
.all(|(i, o)| self.o(i).is_ok_and(|r| r.is_included_in(o)))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn subtypes(&self, acc: &mut Type) {
|
||||
acc.add(Arc::new(self.clone()));
|
||||
}
|
||||
@ -147,11 +185,23 @@ impl Display for Function {
|
||||
}
|
||||
impl Display for FunctionT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match (self.0)(&Type::empty_tuple()) {
|
||||
Ok(t) => write!(f, "Function /* () -> {t} */"),
|
||||
Err(_) => {
|
||||
write!(f, "Function",)
|
||||
match &self.0 {
|
||||
Err(e) => {
|
||||
write!(f, "(")?;
|
||||
for (index, (i, o)) in e.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{i} -> {o}")?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
Ok(_) => match self.o(&Type::empty_tuple()) {
|
||||
Ok(t) => write!(f, "(() -> {t}, ...)"),
|
||||
Err(_) => {
|
||||
write!(f, "(... -> ...)",)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ pub mod error_colors {
|
||||
pub const AsTypeTypeAnnotation: Color = InitTo;
|
||||
|
||||
pub const BadCharInTupleType: Color = Color::Red;
|
||||
pub const BadCharInFunctionType: Color = Color::Red;
|
||||
pub const BadTypeFromParsed: Color = Color::Blue;
|
||||
pub const TypeAnnotationNoClosingBracket: Color = Color::Blue;
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ pub enum ParsedType {
|
||||
Reference(Vec<Self>),
|
||||
Tuple(Vec<Vec<Self>>),
|
||||
Object(Vec<(String, Vec<Self>)>),
|
||||
Function(Vec<(Vec<Self>, Vec<Self>)>),
|
||||
Type(String),
|
||||
Function(Vec<(Self, Self)>),
|
||||
TypeWithInfo(String, String),
|
||||
}
|
||||
|
||||
@ -44,19 +44,20 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
||||
ParsedType::Reference(vec![parse_single_type(src, srca)?])
|
||||
}
|
||||
}
|
||||
// Tuple
|
||||
// Tuple or Function
|
||||
Some('(') => {
|
||||
let pos_in_src = src.get_pos();
|
||||
src.next_char();
|
||||
src.section_begin("parse tuple's inner types".to_string());
|
||||
let mut inner = vec![];
|
||||
let mut inner_t = vec![];
|
||||
let mut inner_f = vec![];
|
||||
src.skip_whitespace();
|
||||
if let Some(')') = src.peek_char() {
|
||||
src.next_char();
|
||||
// empty tuple, don't even start the loop
|
||||
} else {
|
||||
loop {
|
||||
inner.push(parse_type(src, srca)?);
|
||||
let t = parse_type(src, srca)?;
|
||||
src.skip_whitespace();
|
||||
match src.peek_char() {
|
||||
Some(')') => {
|
||||
@ -64,7 +65,48 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
||||
break;
|
||||
}
|
||||
Some(',') => {
|
||||
if inner_f.is_empty() {
|
||||
inner_t.push(t);
|
||||
src.next_char();
|
||||
} else {
|
||||
let pos1 = src.get_pos();
|
||||
src.next_char();
|
||||
return Err(CheckError::new().src(vec![
|
||||
((pos_in_src, src.get_pos(), srca).into(), None),
|
||||
(
|
||||
(pos1, src.get_pos(), srca).into(),
|
||||
Some(error_colors::BadCharInFunctionType),
|
||||
),
|
||||
]).msg(format!("Unexpected character in function type, expected arrow `->` but found `,`."))
|
||||
.msg(format!("If you wanted this to be a tuple type instead, you may have used `Input -> Output` instead of `(Input -> Output)` for a function type somewhere.")));
|
||||
}
|
||||
}
|
||||
Some('-') if src.peek_word() == "->" => {
|
||||
if inner_t.is_empty() {
|
||||
src.next_word();
|
||||
inner_f.push((t, parse_type(src, srca)?));
|
||||
let pos2 = src.get_pos();
|
||||
src.skip_whitespace();
|
||||
match src.next_char() {
|
||||
Some(',') => (),
|
||||
Some(')') => break,
|
||||
_ => return Err(CheckError::new().src(vec![
|
||||
((pos_in_src, src.get_pos(), srca).into(), None),
|
||||
((pos2, src.get_pos(), srca).into(), Some(error_colors::BadCharInFunctionType)),
|
||||
]).msg(format!("Expected comma `,` after `In -> Out` part of function type")))
|
||||
}
|
||||
} else {
|
||||
let pos1 = src.get_pos();
|
||||
src.next_word();
|
||||
return Err(CheckError::new().src(vec![
|
||||
((pos_in_src, src.get_pos(), srca).into(), None),
|
||||
(
|
||||
(pos1, src.get_pos(), srca).into(),
|
||||
Some(error_colors::BadCharInTupleType),
|
||||
),
|
||||
]).msg(format!("Unexpected character in tuple type, expected comma `,` but found arrow `->`."))
|
||||
.msg(format!("If you wanted to write a function type, use `(Input -> Output)` instead of `Input -> Output`.")));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let ppos = src.get_pos();
|
||||
@ -84,7 +126,11 @@ pub fn parse_single_type(src: &mut Source, srca: &Arc<Source>) -> Result<ParsedT
|
||||
}
|
||||
}
|
||||
}
|
||||
ParsedType::Tuple(inner)
|
||||
if inner_f.is_empty() {
|
||||
ParsedType::Tuple(inner_t)
|
||||
} else {
|
||||
ParsedType::Function(inner_f)
|
||||
}
|
||||
}
|
||||
// Object
|
||||
Some('{') => {
|
||||
@ -179,6 +225,10 @@ pub fn type_from_parsed(
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
)),
|
||||
ParsedType::Function(v) => Arc::new(data::function::FunctionT(Err(v
|
||||
.iter()
|
||||
.map(|(i, o)| Ok((type_from_parsed(i, info)?, type_from_parsed(o, info)?)))
|
||||
.collect::<Result<_, CheckError>>()?))),
|
||||
ParsedType::Type(name) => match info
|
||||
.scopes
|
||||
.iter()
|
||||
|
@ -36,7 +36,7 @@ impl Config {
|
||||
let func = &t.0[1];
|
||||
for func_t in func.types.iter() {
|
||||
if let Some(f) = func_t.as_any().downcast_ref::<data::function::FunctionT>() {
|
||||
match (f.0)(&arg) {
|
||||
match f.o(&arg) {
|
||||
Ok(out) => {
|
||||
if !out.is_included_in(&arg) {
|
||||
return Err(format!("Function returns a value of type {out}, which isn't included in the type of the reference, {arg}.").into());
|
||||
@ -150,7 +150,7 @@ impl Config {
|
||||
} else { [v].into_iter().collect() }
|
||||
} else { [v].into_iter().collect() }) {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::function::FunctionT>() {
|
||||
for t in (t.0)(&Type::empty_tuple())?.types {
|
||||
for t in t.o(&Type::empty_tuple())?.types {
|
||||
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
|
||||
if t.0.len() > 1 {
|
||||
return Err(format!("called loop with funcion that might return a tuple of length > 1").into());
|
||||
@ -293,7 +293,7 @@ fn get_try(allow_unused_functions: bool) -> Data {
|
||||
if !skip_checks {
|
||||
func_errors.push((
|
||||
fvi,
|
||||
match ft.0(&arg_type) {
|
||||
match ft.o(&arg_type) {
|
||||
Err(e) => {
|
||||
func_fallible = true;
|
||||
if let Some(errs) =
|
||||
|
@ -53,7 +53,7 @@ impl Config {
|
||||
.collect::<Option<Vec<_>>>(),
|
||||
) {
|
||||
for f in f {
|
||||
let _ret = f.0(&iter)?;
|
||||
let _ret = f.o(&iter)?;
|
||||
// if !ret.is_zero_tuple() {
|
||||
// return Err(format!("for_each function must return (), not {ret}").into());
|
||||
// }
|
||||
@ -325,9 +325,9 @@ impl MersData for Iter {
|
||||
impl IterT {
|
||||
pub fn new(iter: ItersT, data: Type) -> Result<Self, CheckError> {
|
||||
let t = match &iter {
|
||||
ItersT::Map(f) => (f.0)(&data)?,
|
||||
ItersT::Map(f) => f.o(&data)?,
|
||||
ItersT::Filter(f) => {
|
||||
if (f.0)(&data)?.is_included_in(&data::bool::BoolT) {
|
||||
if f.o(&data)?.is_included_in(&data::bool::BoolT) {
|
||||
data.clone()
|
||||
} else {
|
||||
return Err(format!(
|
||||
@ -337,7 +337,7 @@ impl IterT {
|
||||
}
|
||||
}
|
||||
ItersT::FilterMap(f) => {
|
||||
if let Some(v) = (f.0)(&data)?.one_tuple_possible_content() {
|
||||
if let Some(v) = f.o(&data)?.one_tuple_possible_content() {
|
||||
v
|
||||
} else {
|
||||
return Err(
|
||||
@ -346,7 +346,7 @@ impl IterT {
|
||||
}
|
||||
}
|
||||
ItersT::MapWhile(f) => {
|
||||
if let Some(t) = (f.0)(&data)?.one_tuple_possible_content() {
|
||||
if let Some(t) = f.o(&data)?.one_tuple_possible_content() {
|
||||
t
|
||||
} else {
|
||||
return Err(
|
||||
|
@ -36,7 +36,7 @@ impl Config {
|
||||
let mut out = Type::empty();
|
||||
for t in a.types.iter() {
|
||||
if let Some(f) = t.as_any().downcast_ref::<data::function::FunctionT>() {
|
||||
match (f.0)(&Type::empty_tuple()) {
|
||||
match f.o(&Type::empty_tuple()) {
|
||||
Ok(t) => out.add(Arc::new(t)),
|
||||
Err(e) => return Err(CheckError::new().msg(format!("Can't call thread on a function which can't be called on an empty tuple: ")).err(e))
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ impl MersStatement for Chain {
|
||||
.as_any()
|
||||
.downcast_ref::<crate::data::function::FunctionT>()
|
||||
{
|
||||
match (func.0)(&arg) {
|
||||
match func.o(&arg) {
|
||||
Ok(t) => o.add(Arc::new(t)),
|
||||
Err(e) => {
|
||||
return Err(if let Some(_) = &self.as_part_of_include {
|
||||
|
Loading…
Reference in New Issue
Block a user