mirror of
				https://github.com/Dummi26/mers.git
				synced 2025-11-03 21:16:16 +01:00 
			
		
		
		
	Type Annotations
- Add type annotations: [type] statement - Add type definitions: [[name] type], [[name] := statement] - Add type annotations example (08) - add Quickstart.md, reference it from README
This commit is contained in:
		
							parent
							
								
									b6d708db3d
								
							
						
					
					
						commit
						4144d6cf71
					
				
							
								
								
									
										47
									
								
								Quickstart.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Quickstart.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Hello, World!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					"Hello, World!".println
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					This calls the `println` function with the argument
 | 
				
			||||||
 | 
					`"Hello, World!"` (a string).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`println` then prints the argument (to stdout),
 | 
				
			||||||
 | 
					causing it to show up in your terminal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Hello, Variable!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To declare a variable in mers, use `:=`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					greeting := "Hello, World!"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To retrieve its value, simply write its name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					greeting.println
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Conditions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(todo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Functions represent actions. Many represent transformations from some input to some output.
 | 
				
			||||||
 | 
					They are written as `argument -> action`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					a -> if a false else true
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(todo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Type Annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Custom Types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Defining Custom Types
 | 
				
			||||||
							
								
								
									
										3
									
								
								README.md
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										3
									
								
								README.md
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@ -3,6 +3,9 @@
 | 
				
			|||||||
Mers is a high-level programming language.
 | 
					Mers is a high-level programming language.
 | 
				
			||||||
It is designed to be safe (it doesn't crash at runtime) and as simple as possible.
 | 
					It is designed to be safe (it doesn't crash at runtime) and as simple as possible.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also:
 | 
				
			||||||
 | 
					[Quickstart](Quickstart.md),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## what makes it special
 | 
					## what makes it special
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Simplicity
 | 
					### Simplicity
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										76
									
								
								examples/08_Type_Annotations.mers
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								examples/08_Type_Annotations.mers
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					// Change a statement's output type:
 | 
				
			||||||
 | 
					// `[type] statement`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					my_list := [List<Int/Float>] ().as_list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					&my_list.push(12)
 | 
				
			||||||
 | 
					&my_list.push(0.5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					my_list.println
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This can also be used to cause a compiler error on invalid types:
 | 
				
			||||||
 | 
					// `[type] statement`
 | 
				
			||||||
 | 
					// If `statement` isn't included in `type`, this will cause an error.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					my_list.for_each(v ->
 | 
				
			||||||
 | 
					  v.try((
 | 
				
			||||||
 | 
					    v -> {
 | 
				
			||||||
 | 
					      [Int] v // this won't compile if v isn't a float
 | 
				
			||||||
 | 
					      ("Int: ", v).concat
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    v -> {
 | 
				
			||||||
 | 
					      [Float] v
 | 
				
			||||||
 | 
					      ("Float: ", v).concat
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  )).println
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// These annotations work on all kinds of statements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function that always returns Int/Float
 | 
				
			||||||
 | 
					double := x -> [Int/Float] {
 | 
				
			||||||
 | 
					  (x, x).sum
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function that must take Int/Float, but,
 | 
				
			||||||
 | 
					// if given Int, returns Int, and if given Float, returns Float.
 | 
				
			||||||
 | 
					// Therefore usually nicer than the other `double`
 | 
				
			||||||
 | 
					double := x -> {
 | 
				
			||||||
 | 
					  [Int/Float] x
 | 
				
			||||||
 | 
					  (x, x).sum
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define custom types:
 | 
				
			||||||
 | 
					// `[[MyType] TypeDefinition]`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[City] (Int, Int, Int)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					get_coords := city -> [(Int, Int)] {
 | 
				
			||||||
 | 
					  // only works with values of type City
 | 
				
			||||||
 | 
					  (_, x, y) := [City] city
 | 
				
			||||||
 | 
					  // return the coords
 | 
				
			||||||
 | 
					  (x, y)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_city := (56000, 127, -12)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					("Coords: ", test_city.get_coords).concat.println
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Define custom types that depend on the environment:
 | 
				
			||||||
 | 
					// `[[MyType] := some_statement]`
 | 
				
			||||||
 | 
					// Note: `some_statement` will be compiled and checked, but never executed, since we only care about its type at compile-time, not its actual value at runtime.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					make_list_maybe_none := (val_1, val_2) -> {
 | 
				
			||||||
 | 
					  // ListType is List<T> where T is the type of val_1/val_2/()
 | 
				
			||||||
 | 
					  [[ListType] := (val_1, val_2, ()).as_list]
 | 
				
			||||||
 | 
					  // return a list with that type
 | 
				
			||||||
 | 
					  [ListType] (val_1, val_2).as_list
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					maybe_none_list := ("one", 2).make_list_maybe_none
 | 
				
			||||||
 | 
					maybe_none_list.println
 | 
				
			||||||
 | 
					maybe_none_list // use `--check only` to see the type: `List<String/Int/()>`
 | 
				
			||||||
@ -374,16 +374,16 @@ impl Display for Type {
 | 
				
			|||||||
        if self.types.is_empty() {
 | 
					        if self.types.is_empty() {
 | 
				
			||||||
            write!(f, "<unreachable>")
 | 
					            write!(f, "<unreachable>")
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if self.types.len() > 1 {
 | 
					            // if self.types.len() > 1 {
 | 
				
			||||||
                write!(f, "{{")?;
 | 
					            //     write!(f, "{{")?;
 | 
				
			||||||
            }
 | 
					            // }
 | 
				
			||||||
            write!(f, "{}", self.types[0])?;
 | 
					            write!(f, "{}", self.types[0])?;
 | 
				
			||||||
            for t in self.types.iter().skip(1) {
 | 
					            for t in self.types.iter().skip(1) {
 | 
				
			||||||
                write!(f, "/{t}")?;
 | 
					                write!(f, "/{t}")?;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if self.types.len() > 1 {
 | 
					            // if self.types.len() > 1 {
 | 
				
			||||||
                write!(f, "}}")?;
 | 
					            //     write!(f, "}}")?;
 | 
				
			||||||
            }
 | 
					            // }
 | 
				
			||||||
            Ok(())
 | 
					            Ok(())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -74,6 +74,10 @@ impl Display for Reference {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
impl Display for ReferenceT {
 | 
					impl Display for ReferenceT {
 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        if self.0.types.len() > 1 {
 | 
				
			||||||
 | 
					            write!(f, "&{{{}}}", self.0)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            write!(f, "&{}", self.0)
 | 
					            write!(f, "&{}", self.0)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -63,6 +63,13 @@ pub mod error_colors {
 | 
				
			|||||||
    pub const AssignFrom: Color = InitFrom;
 | 
					    pub const AssignFrom: Color = InitFrom;
 | 
				
			||||||
    pub const AssignTo: Color = InitTo;
 | 
					    pub const AssignTo: Color = InitTo;
 | 
				
			||||||
    pub const AssignTargetNonReference: Color = Color::BrightYellow;
 | 
					    pub const AssignTargetNonReference: Color = Color::BrightYellow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub const AsTypeStatementWithTooBroadType: Color = InitFrom;
 | 
				
			||||||
 | 
					    pub const AsTypeTypeAnnotation: Color = InitTo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub const BadCharInTupleType: Color = Color::Red;
 | 
				
			||||||
 | 
					    pub const BadTypeFromParsed: Color = Color::Blue;
 | 
				
			||||||
 | 
					    pub const TypeAnnotationNoClosingBracket: Color = Color::Blue;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
enum CheckErrorComponent {
 | 
					enum CheckErrorComponent {
 | 
				
			||||||
    Message(String),
 | 
					    Message(String),
 | 
				
			||||||
 | 
				
			|||||||
@ -3,26 +3,27 @@ use std::fmt::Debug;
 | 
				
			|||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct Info<L: Local> {
 | 
					pub struct Info<L: Local> {
 | 
				
			||||||
    pub scopes: Vec<L>,
 | 
					    pub scopes: Vec<L>,
 | 
				
			||||||
 | 
					    pub global: L::Global,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<L: Local> Info<L> {
 | 
					impl<L: Local> Info<L> {
 | 
				
			||||||
    /// Returns self, but completely empty (even without globals).
 | 
					    /// Returns self, but completely empty (even without globals).
 | 
				
			||||||
    /// Only use this if you assume this Info will never be used.
 | 
					    /// Only use this if you assume this Info will never be used.
 | 
				
			||||||
    pub fn neverused() -> Self {
 | 
					    pub fn neverused() -> Self {
 | 
				
			||||||
        Self { scopes: vec![] }
 | 
					        Self {
 | 
				
			||||||
 | 
					            scopes: vec![],
 | 
				
			||||||
 | 
					            global: L::Global::default(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait Local: Default + Debug {
 | 
					pub trait Local: Default + Debug {
 | 
				
			||||||
    type VariableIdentifier;
 | 
					    type VariableIdentifier;
 | 
				
			||||||
    type VariableData;
 | 
					    type VariableData;
 | 
				
			||||||
    // type TypesIdentifier;
 | 
					    type Global: Default + Debug + Clone;
 | 
				
			||||||
    // type TypesType;
 | 
					 | 
				
			||||||
    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData);
 | 
					    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData);
 | 
				
			||||||
    fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
 | 
					    fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
 | 
				
			||||||
    fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
 | 
					    fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
 | 
				
			||||||
    // fn add_type(&mut self, id: Self::TypesIdentifier, new_type: Self::TypesType);
 | 
					 | 
				
			||||||
    // fn get_type(&self, id: Self::TypesIdentifier) -> Option<&Self::TypesType>;
 | 
					 | 
				
			||||||
    fn duplicate(&self) -> Self;
 | 
					    fn duplicate(&self) -> Self;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,6 +40,7 @@ impl<L: Local> Info<L> {
 | 
				
			|||||||
impl<L: Local> Local for Info<L> {
 | 
					impl<L: Local> Local for Info<L> {
 | 
				
			||||||
    type VariableIdentifier = L::VariableIdentifier;
 | 
					    type VariableIdentifier = L::VariableIdentifier;
 | 
				
			||||||
    type VariableData = L::VariableData;
 | 
					    type VariableData = L::VariableData;
 | 
				
			||||||
 | 
					    type Global = ();
 | 
				
			||||||
    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
					    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
				
			||||||
        self.scopes.last_mut().unwrap().init_var(id, value)
 | 
					        self.scopes.last_mut().unwrap().init_var(id, value)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -51,6 +53,7 @@ impl<L: Local> Local for Info<L> {
 | 
				
			|||||||
    fn duplicate(&self) -> Self {
 | 
					    fn duplicate(&self) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
 | 
					            scopes: self.scopes.iter().map(|v| v.duplicate()).collect(),
 | 
				
			||||||
 | 
					            global: self.global.clone(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -59,6 +62,7 @@ impl<L: Local> Default for Info<L> {
 | 
				
			|||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            scopes: vec![L::default()],
 | 
					            scopes: vec![L::default()],
 | 
				
			||||||
 | 
					            global: L::Global::default(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -56,6 +56,17 @@ impl Source {
 | 
				
			|||||||
        let content = std::fs::read_to_string(&path)?;
 | 
					        let content = std::fs::read_to_string(&path)?;
 | 
				
			||||||
        Ok(Self::new(SourceFrom::File(path), content))
 | 
					        Ok(Self::new(SourceFrom::File(path), content))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn new_from_string_raw(source: String) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            src_from: SourceFrom::Unspecified,
 | 
				
			||||||
 | 
					            src_raw_len: source.len(),
 | 
				
			||||||
 | 
					            src_og: source.clone(),
 | 
				
			||||||
 | 
					            src: source,
 | 
				
			||||||
 | 
					            comments: vec![],
 | 
				
			||||||
 | 
					            i: 0,
 | 
				
			||||||
 | 
					            sections: vec![],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn new_from_string(source: String) -> Self {
 | 
					    pub fn new_from_string(source: String) -> Self {
 | 
				
			||||||
        Self::new(SourceFrom::Unspecified, source)
 | 
					        Self::new(SourceFrom::Unspecified, source)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -167,7 +178,7 @@ impl Source {
 | 
				
			|||||||
        Some(ch)
 | 
					        Some(ch)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn word_splitter(ch: char) -> bool {
 | 
					    fn word_splitter(ch: char) -> bool {
 | 
				
			||||||
        ch.is_whitespace() || ".,;[](){}".contains(ch)
 | 
					        ch.is_whitespace() || ".,;[](){}/<".contains(ch)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn peek_word(&self) -> &str {
 | 
					    pub fn peek_word(&self) -> &str {
 | 
				
			||||||
        self.src[self.i..]
 | 
					        self.src[self.i..]
 | 
				
			||||||
 | 
				
			|||||||
@ -4,13 +4,107 @@ use super::{Source, SourcePos};
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    data::Data,
 | 
					    data::Data,
 | 
				
			||||||
    errors::{error_colors, CheckError},
 | 
					    errors::{error_colors, CheckError},
 | 
				
			||||||
    program::{self, parsed::MersStatement},
 | 
					    program::{
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        parsed::{as_type::AsType, MersStatement},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn parse(
 | 
					pub fn parse(
 | 
				
			||||||
    src: &mut Source,
 | 
					    src: &mut Source,
 | 
				
			||||||
) -> Result<Option<Box<dyn program::parsed::MersStatement>>, CheckError> {
 | 
					) -> Result<Option<Box<dyn program::parsed::MersStatement>>, CheckError> {
 | 
				
			||||||
    src.section_begin("statement".to_string());
 | 
					    src.section_begin("statement".to_string());
 | 
				
			||||||
 | 
					    src.skip_whitespace();
 | 
				
			||||||
 | 
					    // type annotation:
 | 
				
			||||||
 | 
					    //  [type] statement // force output type to be `type`
 | 
				
			||||||
 | 
					    //  [[name] type] // define `name` as `type`
 | 
				
			||||||
 | 
					    //  [[name] := statement] // define `name` as the type of `statement` (`statement` is never executed)
 | 
				
			||||||
 | 
					    if matches!(src.peek_char(), Some('[')) {
 | 
				
			||||||
 | 
					        let pos_in_src = src.get_pos();
 | 
				
			||||||
 | 
					        src.next_char();
 | 
				
			||||||
 | 
					        return Ok(Some(if matches!(src.peek_char(), Some('[')) {
 | 
				
			||||||
 | 
					            src.next_char();
 | 
				
			||||||
 | 
					            // [[...
 | 
				
			||||||
 | 
					            let name = src.next_word();
 | 
				
			||||||
 | 
					            let name = name.trim().to_owned();
 | 
				
			||||||
 | 
					            src.skip_whitespace();
 | 
				
			||||||
 | 
					            if !matches!(src.next_char(), Some(']')) {
 | 
				
			||||||
 | 
					                return Err(
 | 
				
			||||||
 | 
					                    CheckError::new().msg(format!("Expected ']' after type name in [[type_name]]"))
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            src.skip_whitespace();
 | 
				
			||||||
 | 
					            if src.peek_word() == ":=" {
 | 
				
			||||||
 | 
					                src.next_word();
 | 
				
			||||||
 | 
					                // [[name] := statement]
 | 
				
			||||||
 | 
					                let statement = match parse(src) {
 | 
				
			||||||
 | 
					                    Ok(Some(v)) => v,
 | 
				
			||||||
 | 
					                    Ok(None) => {
 | 
				
			||||||
 | 
					                        return Err(CheckError::new()
 | 
				
			||||||
 | 
					                            .src(vec![((pos_in_src, src.get_pos()).into(), None)])
 | 
				
			||||||
 | 
					                            .msg(format!("EOF after `[...]` type annotation")))
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    Err(e) => return Err(e),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                if !matches!(src.next_char(), Some(']')) {
 | 
				
			||||||
 | 
					                    return Err(CheckError::new().msg(format!(
 | 
				
			||||||
 | 
					                        "Expected ']' after statement in [[type_name] := statement]"
 | 
				
			||||||
 | 
					                    )));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Box::new(program::parsed::custom_type::CustomType {
 | 
				
			||||||
 | 
					                    pos_in_src: (pos_in_src, src.get_pos()).into(),
 | 
				
			||||||
 | 
					                    name,
 | 
				
			||||||
 | 
					                    source: Err(statement),
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // [[name] type]
 | 
				
			||||||
 | 
					                src.skip_whitespace();
 | 
				
			||||||
 | 
					                let as_type = super::types::parse_type(src)?;
 | 
				
			||||||
 | 
					                src.skip_whitespace();
 | 
				
			||||||
 | 
					                if !matches!(src.next_char(), Some(']')) {
 | 
				
			||||||
 | 
					                    return Err(CheckError::new().msg(format!(
 | 
				
			||||||
 | 
					                        "Expected ']' after type definition in [[type_name] type_definition]"
 | 
				
			||||||
 | 
					                    )));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Box::new(program::parsed::custom_type::CustomType {
 | 
				
			||||||
 | 
					                    pos_in_src: (pos_in_src, src.get_pos()).into(),
 | 
				
			||||||
 | 
					                    name,
 | 
				
			||||||
 | 
					                    source: Ok(as_type),
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // [type] statement
 | 
				
			||||||
 | 
					            src.skip_whitespace();
 | 
				
			||||||
 | 
					            let type_pos_in_src = src.get_pos();
 | 
				
			||||||
 | 
					            let as_type = super::types::parse_type(src)?;
 | 
				
			||||||
 | 
					            let type_pos_in_src = (type_pos_in_src, src.get_pos()).into();
 | 
				
			||||||
 | 
					            src.skip_whitespace();
 | 
				
			||||||
 | 
					            if !matches!(src.next_char(), Some(']')) {
 | 
				
			||||||
 | 
					                return Err(CheckError::new()
 | 
				
			||||||
 | 
					                    .src(vec![(
 | 
				
			||||||
 | 
					                        (pos_in_src, src.get_pos()).into(),
 | 
				
			||||||
 | 
					                        Some(error_colors::TypeAnnotationNoClosingBracket),
 | 
				
			||||||
 | 
					                    )])
 | 
				
			||||||
 | 
					                    .msg(format!("Missing closing bracket ']' after type annotation")));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let statement = match parse(src) {
 | 
				
			||||||
 | 
					                Ok(Some(v)) => v,
 | 
				
			||||||
 | 
					                Ok(None) => {
 | 
				
			||||||
 | 
					                    return Err(CheckError::new()
 | 
				
			||||||
 | 
					                        .src(vec![((pos_in_src, src.get_pos()).into(), None)])
 | 
				
			||||||
 | 
					                        .msg(format!("EOF after `[...]` type annotation")))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            Box::new(AsType {
 | 
				
			||||||
 | 
					                pos_in_src: (pos_in_src, src.get_pos()).into(),
 | 
				
			||||||
 | 
					                statement,
 | 
				
			||||||
 | 
					                as_type,
 | 
				
			||||||
 | 
					                type_pos_in_src,
 | 
				
			||||||
 | 
					                expand_type: true,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    let mut first = if let Some(s) = parse_no_chain(src)? {
 | 
					    let mut first = if let Some(s) = parse_no_chain(src)? {
 | 
				
			||||||
        s
 | 
					        s
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -128,8 +222,8 @@ pub fn parse_multiple(
 | 
				
			|||||||
pub fn parse_no_chain(
 | 
					pub fn parse_no_chain(
 | 
				
			||||||
    src: &mut Source,
 | 
					    src: &mut Source,
 | 
				
			||||||
) -> Result<Option<Box<dyn program::parsed::MersStatement>>, CheckError> {
 | 
					) -> Result<Option<Box<dyn program::parsed::MersStatement>>, CheckError> {
 | 
				
			||||||
    src.section_begin("statement no chain".to_string());
 | 
					 | 
				
			||||||
    src.skip_whitespace();
 | 
					    src.skip_whitespace();
 | 
				
			||||||
 | 
					    src.section_begin("statement no chain".to_string());
 | 
				
			||||||
    match src.peek_char() {
 | 
					    match src.peek_char() {
 | 
				
			||||||
        Some('#') => {
 | 
					        Some('#') => {
 | 
				
			||||||
            let pos_in_src = src.get_pos();
 | 
					            let pos_in_src = src.get_pos();
 | 
				
			||||||
@ -339,6 +433,14 @@ pub fn parse_no_chain(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// expects to be called *after* a " character is consumed from src
 | 
					/// expects to be called *after* a " character is consumed from src
 | 
				
			||||||
pub fn parse_string(src: &mut Source, double_quote: SourcePos) -> Result<String, CheckError> {
 | 
					pub fn parse_string(src: &mut Source, double_quote: SourcePos) -> Result<String, CheckError> {
 | 
				
			||||||
 | 
					    parse_string_custom_end(src, double_quote, '"', '"')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					pub fn parse_string_custom_end(
 | 
				
			||||||
 | 
					    src: &mut Source,
 | 
				
			||||||
 | 
					    opening: SourcePos,
 | 
				
			||||||
 | 
					    opening_char: char,
 | 
				
			||||||
 | 
					    closing_char: char,
 | 
				
			||||||
 | 
					) -> Result<String, CheckError> {
 | 
				
			||||||
    let mut s = String::new();
 | 
					    let mut s = String::new();
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        if let Some(ch) = src.next_char() {
 | 
					        if let Some(ch) = src.next_char() {
 | 
				
			||||||
@ -350,6 +452,7 @@ pub fn parse_string(src: &mut Source, double_quote: SourcePos) -> Result<String,
 | 
				
			|||||||
                    Some('n') => '\n',
 | 
					                    Some('n') => '\n',
 | 
				
			||||||
                    Some('t') => '\t',
 | 
					                    Some('t') => '\t',
 | 
				
			||||||
                    Some('"') => '"',
 | 
					                    Some('"') => '"',
 | 
				
			||||||
 | 
					                    Some(c) if c == closing_char || c == opening_char => c,
 | 
				
			||||||
                    Some(o) => {
 | 
					                    Some(o) => {
 | 
				
			||||||
                        return Err(CheckError::new()
 | 
					                        return Err(CheckError::new()
 | 
				
			||||||
                            .src(vec![(
 | 
					                            .src(vec![(
 | 
				
			||||||
@ -367,7 +470,7 @@ pub fn parse_string(src: &mut Source, double_quote: SourcePos) -> Result<String,
 | 
				
			|||||||
                            .msg(format!("EOF in backslash escape")));
 | 
					                            .msg(format!("EOF in backslash escape")));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            } else if ch == '"' {
 | 
					            } else if ch == closing_char {
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                s.push(ch);
 | 
					                s.push(ch);
 | 
				
			||||||
@ -375,11 +478,27 @@ pub fn parse_string(src: &mut Source, double_quote: SourcePos) -> Result<String,
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return Err(CheckError::new()
 | 
					            return Err(CheckError::new()
 | 
				
			||||||
                .src(vec![(
 | 
					                .src(vec![(
 | 
				
			||||||
                    (double_quote, src.get_pos()).into(),
 | 
					                    (opening, src.get_pos()).into(),
 | 
				
			||||||
                    Some(error_colors::StringEOF),
 | 
					                    Some(error_colors::StringEOF),
 | 
				
			||||||
                )])
 | 
					                )])
 | 
				
			||||||
                .msg(format!("EOF in string literal")));
 | 
					                .msg(format!(
 | 
				
			||||||
 | 
					                    "EOF in string literal{}",
 | 
				
			||||||
 | 
					                    if closing_char != '"' {
 | 
				
			||||||
 | 
					                        format!(
 | 
				
			||||||
 | 
					                            "{opening_char}...{closing_char} (end string with '{closing_char}')"
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        String::new()
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                )));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    Ok(s)
 | 
					    Ok(s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					pub fn to_string_literal(val: &str, end: char) -> String {
 | 
				
			||||||
 | 
					    val.replace("\\", "\\\\")
 | 
				
			||||||
 | 
					        .replace("\r", "\\r")
 | 
				
			||||||
 | 
					        .replace("\n", "\\n")
 | 
				
			||||||
 | 
					        .replace("\"", "\\\"")
 | 
				
			||||||
 | 
					        .replace(end, format!("\\{end}").as_str())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,21 +1,59 @@
 | 
				
			|||||||
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    data::{self, Type},
 | 
				
			||||||
 | 
					    errors::{error_colors, CheckError},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::Source;
 | 
					use super::Source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// multiple types are represented as a `Vec<ParsedType>`.
 | 
					/// multiple types are represented as a `Vec<ParsedType>`.
 | 
				
			||||||
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub enum ParsedType {
 | 
					pub enum ParsedType {
 | 
				
			||||||
 | 
					    Reference(Vec<Self>),
 | 
				
			||||||
    Tuple(Vec<Vec<Self>>),
 | 
					    Tuple(Vec<Vec<Self>>),
 | 
				
			||||||
    Type(String),
 | 
					    Type(String),
 | 
				
			||||||
 | 
					    TypeWithInfo(String, String),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_single_type(src: &mut Source) -> Result<ParsedType, ()> {
 | 
					pub fn parse_single_type(src: &mut Source) -> Result<ParsedType, CheckError> {
 | 
				
			||||||
    src.section_begin("parse single type".to_string());
 | 
					    src.section_begin("parse single type".to_string());
 | 
				
			||||||
    src.skip_whitespace();
 | 
					    src.skip_whitespace();
 | 
				
			||||||
    Ok(match src.peek_char() {
 | 
					    Ok(match src.peek_char() {
 | 
				
			||||||
 | 
					        // Reference
 | 
				
			||||||
 | 
					        Some('&') => {
 | 
				
			||||||
 | 
					            src.next_char();
 | 
				
			||||||
 | 
					            if let Some('{') = src.peek_char() {
 | 
				
			||||||
 | 
					                src.next_char();
 | 
				
			||||||
 | 
					                let types = parse_type(src)?;
 | 
				
			||||||
 | 
					                let nc = src.next_char();
 | 
				
			||||||
 | 
					                if !matches!(nc, Some('}')) {
 | 
				
			||||||
 | 
					                    let nc = if let Some(nc) = nc {
 | 
				
			||||||
 | 
					                        format!("'{nc}'")
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        format!("EOF")
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    return Err(CheckError::new().msg(format!(
 | 
				
			||||||
 | 
					                        "No closing }} in reference type with opening {{! Found {nc} instead"
 | 
				
			||||||
 | 
					                    )));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                ParsedType::Reference(types)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ParsedType::Reference(vec![parse_single_type(src)?])
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        // Tuple
 | 
					        // Tuple
 | 
				
			||||||
        Some('(') => {
 | 
					        Some('(') => {
 | 
				
			||||||
 | 
					            let pos_in_src = src.get_pos();
 | 
				
			||||||
            src.next_char();
 | 
					            src.next_char();
 | 
				
			||||||
            src.section_begin("parse tuple's inner types".to_string());
 | 
					            src.section_begin("parse tuple's inner types".to_string());
 | 
				
			||||||
            let mut inner = vec![];
 | 
					            let mut inner = vec![];
 | 
				
			||||||
 | 
					            src.skip_whitespace();
 | 
				
			||||||
 | 
					            if let Some(')') = src.peek_char() {
 | 
				
			||||||
 | 
					                // empty tuple, don't even start the loop
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
                loop {
 | 
					                loop {
 | 
				
			||||||
 | 
					                    inner.push(parse_type(src)?);
 | 
				
			||||||
                    match src.peek_char() {
 | 
					                    match src.peek_char() {
 | 
				
			||||||
                        Some(')') => {
 | 
					                        Some(')') => {
 | 
				
			||||||
                            src.next_char();
 | 
					                            src.next_char();
 | 
				
			||||||
@ -24,24 +62,52 @@ fn parse_single_type(src: &mut Source) -> Result<ParsedType, ()> {
 | 
				
			|||||||
                        Some(',') => {
 | 
					                        Some(',') => {
 | 
				
			||||||
                            src.next_char();
 | 
					                            src.next_char();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    _ => todo!("err: bad char in tuple inner type"),
 | 
					                        _ => {
 | 
				
			||||||
 | 
					                            let ppos = src.get_pos();
 | 
				
			||||||
 | 
					                            src.next_char();
 | 
				
			||||||
 | 
					                            return Err(CheckError::new()
 | 
				
			||||||
 | 
					                                .src(vec![
 | 
				
			||||||
 | 
					                                    ((pos_in_src, src.get_pos()).into(), None),
 | 
				
			||||||
 | 
					                                    (
 | 
				
			||||||
 | 
					                                        (ppos, src.get_pos()).into(),
 | 
				
			||||||
 | 
					                                        Some(error_colors::BadCharInTupleType),
 | 
				
			||||||
 | 
					                                    ),
 | 
				
			||||||
 | 
					                                ])
 | 
				
			||||||
 | 
					                                .msg(format!(
 | 
				
			||||||
 | 
					                                "Unexpected character in tuple type, expected comma ',' or ')'."
 | 
				
			||||||
 | 
					                            )));
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                inner.push(parse_type(src)?);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ParsedType::Tuple(inner)
 | 
					            ParsedType::Tuple(inner)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Some(_) => ParsedType::Type(src.next_word().to_lowercase()),
 | 
					        Some(_) => {
 | 
				
			||||||
 | 
					            let t = src.next_word().to_owned();
 | 
				
			||||||
 | 
					            src.skip_whitespace();
 | 
				
			||||||
 | 
					            if let Some('<') = src.peek_char() {
 | 
				
			||||||
 | 
					                let pos = src.get_pos();
 | 
				
			||||||
 | 
					                src.next_char();
 | 
				
			||||||
 | 
					                ParsedType::TypeWithInfo(
 | 
				
			||||||
 | 
					                    t,
 | 
				
			||||||
 | 
					                    super::statements::parse_string_custom_end(src, pos, '<', '>')?,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ParsedType::Type(t)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        None => todo!(),
 | 
					        None => todo!(),
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_type(src: &mut Source) -> Result<Vec<ParsedType>, ()> {
 | 
					pub fn parse_type(src: &mut Source) -> Result<Vec<ParsedType>, CheckError> {
 | 
				
			||||||
    src.section_begin("parse single type".to_string());
 | 
					    src.section_begin("parse single type".to_string());
 | 
				
			||||||
    let mut types = vec![];
 | 
					    let mut types = vec![];
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        types.push(parse_single_type(src)?);
 | 
					        types.push(parse_single_type(src)?);
 | 
				
			||||||
        src.skip_whitespace();
 | 
					        src.skip_whitespace();
 | 
				
			||||||
        if let Some('/') = src.peek_char() {
 | 
					        if let Some('/') = src.peek_char() {
 | 
				
			||||||
 | 
					            src.next_char();
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -49,3 +115,49 @@ fn parse_type(src: &mut Source) -> Result<Vec<ParsedType>, ()> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    Ok(types)
 | 
					    Ok(types)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					pub fn type_from_parsed(
 | 
				
			||||||
 | 
					    parsed: &Vec<ParsedType>,
 | 
				
			||||||
 | 
					    info: &crate::program::run::CheckInfo,
 | 
				
			||||||
 | 
					) -> Result<Type, CheckError> {
 | 
				
			||||||
 | 
					    let mut as_type = Type::empty();
 | 
				
			||||||
 | 
					    for t in parsed.iter() {
 | 
				
			||||||
 | 
					        as_type.add(match t {
 | 
				
			||||||
 | 
					            ParsedType::Reference(inner) => {
 | 
				
			||||||
 | 
					                let inner = type_from_parsed(inner, info)?;
 | 
				
			||||||
 | 
					                Arc::new(data::reference::ReferenceT(inner))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ParsedType::Tuple(t) => Arc::new(data::tuple::TupleT(
 | 
				
			||||||
 | 
					                t.iter()
 | 
				
			||||||
 | 
					                    .map(|v| type_from_parsed(v, info))
 | 
				
			||||||
 | 
					                    .collect::<Result<_, _>>()?,
 | 
				
			||||||
 | 
					            )),
 | 
				
			||||||
 | 
					            ParsedType::Type(name) => match info
 | 
				
			||||||
 | 
					                .scopes
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .find_map(|scope| scope.types.iter().find(|v| v.0 == name).map(|(_, v)| v))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Some(Ok(t)) => Arc::clone(t),
 | 
				
			||||||
 | 
					                Some(Err(_)) => {
 | 
				
			||||||
 | 
					                    return Err(CheckError::new().msg(format!(
 | 
				
			||||||
 | 
					                        "Type: specified type without info, but type needs additional info"
 | 
				
			||||||
 | 
					                    )))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                None => return Err(CheckError::new().msg(format!("Unknown type '{name}'"))),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            ParsedType::TypeWithInfo(name, additional_info) => match info
 | 
				
			||||||
 | 
					                .scopes
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .find_map(|scope| scope.types.iter().find(|v| v.0 == name).map(|(_, v)| v))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Some(Ok(t)) => {
 | 
				
			||||||
 | 
					                    return Err(CheckError::new().msg(format!(
 | 
				
			||||||
 | 
					                        "Type: specified type with info, but type {t} doesn't need it"
 | 
				
			||||||
 | 
					                    )))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Some(Err(f)) => f(&additional_info, info)?,
 | 
				
			||||||
 | 
					                None => return Err(CheckError::new().msg(format!("Unknown type '{name}'"))),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(as_type)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,10 @@
 | 
				
			|||||||
use std::sync::{Arc, RwLock};
 | 
					use std::sync::{Arc, RwLock};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    data::{Data, Type},
 | 
					    data::{self, Data, MersType},
 | 
				
			||||||
 | 
					    errors::CheckError,
 | 
				
			||||||
    info::Local,
 | 
					    info::Local,
 | 
				
			||||||
 | 
					    program::run::CheckInfo,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod with_base;
 | 
					mod with_base;
 | 
				
			||||||
@ -58,11 +60,27 @@ impl Config {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new() -> Self {
 | 
					    pub fn new() -> Self {
 | 
				
			||||||
 | 
					        let mut info_check: CheckInfo = Default::default();
 | 
				
			||||||
 | 
					        macro_rules! init_d {
 | 
				
			||||||
 | 
					            ($e:expr) => {
 | 
				
			||||||
 | 
					                let t = $e;
 | 
				
			||||||
 | 
					                info_check
 | 
				
			||||||
 | 
					                    .scopes
 | 
				
			||||||
 | 
					                    .last_mut()
 | 
				
			||||||
 | 
					                    .unwrap()
 | 
				
			||||||
 | 
					                    .types
 | 
				
			||||||
 | 
					                    .insert(t.to_string(), Ok(Arc::new(t)));
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        init_d!(data::bool::BoolT);
 | 
				
			||||||
 | 
					        init_d!(data::int::IntT);
 | 
				
			||||||
 | 
					        init_d!(data::float::FloatT);
 | 
				
			||||||
 | 
					        init_d!(data::string::StringT);
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            globals: 0,
 | 
					            globals: 0,
 | 
				
			||||||
            info_parsed: Default::default(),
 | 
					            info_parsed: Default::default(),
 | 
				
			||||||
            info_run: Default::default(),
 | 
					            info_run: Default::default(),
 | 
				
			||||||
            info_check: Default::default(),
 | 
					            info_check,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -74,8 +92,15 @@ impl Config {
 | 
				
			|||||||
        self.globals += 1;
 | 
					        self.globals += 1;
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn add_type(self, _name: String, _t: Type) -> Self {
 | 
					    pub fn add_type(
 | 
				
			||||||
        // TODO! needed for type syntax in the parser, everything else probably(?) works already
 | 
					        mut self,
 | 
				
			||||||
 | 
					        name: String,
 | 
				
			||||||
 | 
					        t: Result<
 | 
				
			||||||
 | 
					            Arc<dyn MersType>,
 | 
				
			||||||
 | 
					            Arc<dyn Fn(&str, &CheckInfo) -> Result<Arc<dyn MersType>, CheckError> + Send + Sync>,
 | 
				
			||||||
 | 
					        >,
 | 
				
			||||||
 | 
					    ) -> Self {
 | 
				
			||||||
 | 
					        self.info_check.scopes[0].types.insert(name, t);
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ use std::{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    data::{self, Data, MersData, MersType, Type},
 | 
					    data::{self, Data, MersData, MersType, Type},
 | 
				
			||||||
 | 
					    parsing::{statements::to_string_literal, Source},
 | 
				
			||||||
    program::{self, run::CheckInfo},
 | 
					    program::{self, run::CheckInfo},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -20,7 +21,10 @@ impl Config {
 | 
				
			|||||||
    /// `get_mut: fn` like get, but returns a reference to the object
 | 
					    /// `get_mut: fn` like get, but returns a reference to the object
 | 
				
			||||||
    pub fn with_list(self) -> Self {
 | 
					    pub fn with_list(self) -> Self {
 | 
				
			||||||
        // TODO: Type with generics
 | 
					        // TODO: Type with generics
 | 
				
			||||||
        self.add_type("List".to_string(), Type::new(ListT(Type::empty_tuple())))
 | 
					        self.add_type("List".to_string(),
 | 
				
			||||||
 | 
					            Err(Arc::new(|s, i| {
 | 
				
			||||||
 | 
					                let t = crate::parsing::types::parse_type(&mut Source::new_from_string_raw(s.to_owned()))?;
 | 
				
			||||||
 | 
					                Ok(Arc::new(ListT(crate::parsing::types::type_from_parsed(&t, i)?)))})))
 | 
				
			||||||
            .add_var(
 | 
					            .add_var(
 | 
				
			||||||
                "pop".to_string(),
 | 
					                "pop".to_string(),
 | 
				
			||||||
                Data::new(data::function::Function {
 | 
					                Data::new(data::function::Function {
 | 
				
			||||||
@ -202,7 +206,10 @@ impl MersType for ListT {
 | 
				
			|||||||
            .is_some_and(|v| self.0.is_same_type_as(&v.0))
 | 
					            .is_some_and(|v| self.0.is_same_type_as(&v.0))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn is_included_in_single(&self, target: &dyn MersType) -> bool {
 | 
					    fn is_included_in_single(&self, target: &dyn MersType) -> bool {
 | 
				
			||||||
        self.is_same_type_as(target)
 | 
					        target
 | 
				
			||||||
 | 
					            .as_any()
 | 
				
			||||||
 | 
					            .downcast_ref::<Self>()
 | 
				
			||||||
 | 
					            .is_some_and(|v| self.0.is_included_in(&v.0))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn subtypes(&self, acc: &mut Type) {
 | 
					    fn subtypes(&self, acc: &mut Type) {
 | 
				
			||||||
        for t in self.0.subtypes_type().types {
 | 
					        for t in self.0.subtypes_type().types {
 | 
				
			||||||
@ -234,7 +241,7 @@ impl Display for List {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
impl Display for ListT {
 | 
					impl Display for ListT {
 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
        write!(f, "[{}]", self.0)?;
 | 
					        write!(f, "List<{}>", to_string_literal(&self.0.to_string(), '>'))?;
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ use std::{
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    data::{self, Data, MersData, MersType, Type},
 | 
					    data::{self, Data, MersData, MersType, Type},
 | 
				
			||||||
    errors::CheckError,
 | 
					    errors::CheckError,
 | 
				
			||||||
 | 
					    parsing::{statements::to_string_literal, Source},
 | 
				
			||||||
    program::{self, run::CheckInfo},
 | 
					    program::{self, run::CheckInfo},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -19,7 +20,10 @@ impl Config {
 | 
				
			|||||||
    pub fn with_multithreading(self) -> Self {
 | 
					    pub fn with_multithreading(self) -> Self {
 | 
				
			||||||
        self.add_type(
 | 
					        self.add_type(
 | 
				
			||||||
            "Thread".to_string(),
 | 
					            "Thread".to_string(),
 | 
				
			||||||
            Type::new(ThreadT(Type::empty_tuple())),
 | 
					            Err(Arc::new(|s, i| {
 | 
				
			||||||
 | 
					                let t = crate::parsing::types::parse_type(&mut Source::new_from_string_raw(s.to_owned()))?;
 | 
				
			||||||
 | 
					                Ok(Arc::new(ThreadT(crate::parsing::types::type_from_parsed(&t, i)?)))
 | 
				
			||||||
 | 
					            })),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .add_var(
 | 
					        .add_var(
 | 
				
			||||||
            "thread".to_string(),
 | 
					            "thread".to_string(),
 | 
				
			||||||
@ -170,6 +174,6 @@ impl Display for Thread {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
impl Display for ThreadT {
 | 
					impl Display for ThreadT {
 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
        write!(f, "<Thread>")
 | 
					        write!(f, "Thread<{}>", to_string_literal(&self.0.to_string(), '>'))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								mers_lib/src/program/parsed/as_type.rs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										38
									
								
								mers_lib/src/program/parsed/as_type.rs
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    errors::{CheckError, SourceRange},
 | 
				
			||||||
 | 
					    parsing::types::ParsedType,
 | 
				
			||||||
 | 
					    program::{self},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{CompInfo, MersStatement};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct AsType {
 | 
				
			||||||
 | 
					    pub pos_in_src: SourceRange,
 | 
				
			||||||
 | 
					    pub statement: Box<dyn MersStatement>,
 | 
				
			||||||
 | 
					    pub as_type: Vec<ParsedType>,
 | 
				
			||||||
 | 
					    pub type_pos_in_src: SourceRange,
 | 
				
			||||||
 | 
					    pub expand_type: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MersStatement for AsType {
 | 
				
			||||||
 | 
					    fn has_scope(&self) -> bool {
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn compile_custom(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        info: &mut crate::info::Info<super::Local>,
 | 
				
			||||||
 | 
					        comp: CompInfo,
 | 
				
			||||||
 | 
					    ) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
 | 
				
			||||||
 | 
					        Ok(Box::new(program::run::as_type::AsType {
 | 
				
			||||||
 | 
					            pos_in_src: self.pos_in_src,
 | 
				
			||||||
 | 
					            statement: self.statement.compile(info, comp)?,
 | 
				
			||||||
 | 
					            as_type: self.as_type.clone(),
 | 
				
			||||||
 | 
					            type_pos_in_src: self.type_pos_in_src,
 | 
				
			||||||
 | 
					            expand_type: self.expand_type,
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn source_range(&self) -> SourceRange {
 | 
				
			||||||
 | 
					        self.pos_in_src
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								mers_lib/src/program/parsed/custom_type.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								mers_lib/src/program/parsed/custom_type.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					use std::{fmt::Debug, sync::Arc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    errors::{CheckError, SourceRange},
 | 
				
			||||||
 | 
					    parsing::types::{type_from_parsed, ParsedType},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{CompInfo, Info, MersStatement};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct CustomType {
 | 
				
			||||||
 | 
					    pub pos_in_src: SourceRange,
 | 
				
			||||||
 | 
					    pub name: String,
 | 
				
			||||||
 | 
					    pub source: Result<Vec<ParsedType>, Box<dyn MersStatement>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl MersStatement for CustomType {
 | 
				
			||||||
 | 
					    fn compile_custom(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        info: &mut Info,
 | 
				
			||||||
 | 
					        comp: CompInfo,
 | 
				
			||||||
 | 
					    ) -> Result<Box<dyn crate::program::run::MersStatement>, CheckError> {
 | 
				
			||||||
 | 
					        let src = match &self.source {
 | 
				
			||||||
 | 
					            Ok(p) => Ok(p.clone()),
 | 
				
			||||||
 | 
					            Err(s) => Err(s.compile(info, comp)?),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        Ok(Box::new(crate::program::run::custom_type::CustomType {
 | 
				
			||||||
 | 
					            pos_in_src: self.pos_in_src,
 | 
				
			||||||
 | 
					            name: self.name.clone(),
 | 
				
			||||||
 | 
					            source: Box::new(move |ci| match &src {
 | 
				
			||||||
 | 
					                Ok(parsed) => Ok(Ok(Arc::new(type_from_parsed(parsed, ci)?))),
 | 
				
			||||||
 | 
					                Err(statement) => Ok(Ok(Arc::new(statement.check(&mut ci.clone(), None)?))),
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					        }))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn has_scope(&self) -> bool {
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn source_range(&self) -> SourceRange {
 | 
				
			||||||
 | 
					        self.pos_in_src
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Debug for CustomType {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "type {} <...>", self.name)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,6 +5,8 @@ use crate::{
 | 
				
			|||||||
    info,
 | 
					    info,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
 | 
					pub mod as_type;
 | 
				
			||||||
#[cfg(feature = "parse")]
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
pub mod assign_to;
 | 
					pub mod assign_to;
 | 
				
			||||||
#[cfg(feature = "parse")]
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
@ -12,6 +14,8 @@ pub mod block;
 | 
				
			|||||||
#[cfg(feature = "parse")]
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
pub mod chain;
 | 
					pub mod chain;
 | 
				
			||||||
#[cfg(feature = "parse")]
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
 | 
					pub mod custom_type;
 | 
				
			||||||
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
pub mod function;
 | 
					pub mod function;
 | 
				
			||||||
#[cfg(feature = "parse")]
 | 
					#[cfg(feature = "parse")]
 | 
				
			||||||
pub mod r#if;
 | 
					pub mod r#if;
 | 
				
			||||||
@ -70,6 +74,7 @@ pub struct Local {
 | 
				
			|||||||
impl info::Local for Local {
 | 
					impl info::Local for Local {
 | 
				
			||||||
    type VariableIdentifier = String;
 | 
					    type VariableIdentifier = String;
 | 
				
			||||||
    type VariableData = (usize, usize);
 | 
					    type VariableData = (usize, usize);
 | 
				
			||||||
 | 
					    type Global = ();
 | 
				
			||||||
    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
					    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
				
			||||||
        self.vars_count += 1;
 | 
					        self.vars_count += 1;
 | 
				
			||||||
        self.vars.insert(id, value);
 | 
					        self.vars.insert(id, value);
 | 
				
			||||||
 | 
				
			|||||||
@ -22,20 +22,29 @@ impl MersStatement for Variable {
 | 
				
			|||||||
        info: &mut crate::info::Info<super::Local>,
 | 
					        info: &mut crate::info::Info<super::Local>,
 | 
				
			||||||
        comp: CompInfo,
 | 
					        comp: CompInfo,
 | 
				
			||||||
    ) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
 | 
					    ) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
 | 
				
			||||||
 | 
					        let init_and_ignore = comp.is_init && self.var == "_";
 | 
				
			||||||
        if comp.is_init {
 | 
					        if comp.is_init {
 | 
				
			||||||
 | 
					            if !init_and_ignore {
 | 
				
			||||||
                info.init_var(
 | 
					                info.init_var(
 | 
				
			||||||
                    self.var.clone(),
 | 
					                    self.var.clone(),
 | 
				
			||||||
                    (
 | 
					                    (
 | 
				
			||||||
                        info.scopes.len() - 1,
 | 
					                        info.scopes.len() - 1,
 | 
				
			||||||
                        info.scopes.last().unwrap().vars_count,
 | 
					                        info.scopes.last().unwrap().vars_count,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
            )
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(Box::new(program::run::variable::Variable {
 | 
					        Ok(Box::new(program::run::variable::Variable {
 | 
				
			||||||
            pos_in_src: self.pos_in_src,
 | 
					            pos_in_src: self.pos_in_src,
 | 
				
			||||||
            is_init: comp.is_init,
 | 
					            is_init: comp.is_init,
 | 
				
			||||||
            is_ref: comp.is_init || self.is_ref,
 | 
					            is_ref_not_ignore: if comp.is_init {
 | 
				
			||||||
            var: if let Some(v) = info.get_var(&self.var) {
 | 
					                !init_and_ignore
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                self.is_ref
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            var: if init_and_ignore {
 | 
				
			||||||
 | 
					                (usize::MAX, usize::MAX)
 | 
				
			||||||
 | 
					            } else if let Some(v) = info.get_var(&self.var) {
 | 
				
			||||||
                *v
 | 
					                *v
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                return Err(CheckError::new()
 | 
					                return Err(CheckError::new()
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										78
									
								
								mers_lib/src/program/run/as_type.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								mers_lib/src/program/run/as_type.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					use colored::Colorize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    data::{Data, MersType, Type},
 | 
				
			||||||
 | 
					    errors::{error_colors, CheckError, SourceRange},
 | 
				
			||||||
 | 
					    parsing::types::ParsedType,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::MersStatement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct AsType {
 | 
				
			||||||
 | 
					    pub pos_in_src: SourceRange,
 | 
				
			||||||
 | 
					    pub statement: Box<dyn MersStatement>,
 | 
				
			||||||
 | 
					    pub as_type: Vec<ParsedType>,
 | 
				
			||||||
 | 
					    pub type_pos_in_src: SourceRange,
 | 
				
			||||||
 | 
					    /// if false, only return an error if type doesn't fit, but don't expand type if it fits
 | 
				
			||||||
 | 
					    pub expand_type: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MersStatement for AsType {
 | 
				
			||||||
 | 
					    fn check_custom(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        info: &mut super::CheckInfo,
 | 
				
			||||||
 | 
					        init_to: Option<&Type>,
 | 
				
			||||||
 | 
					    ) -> Result<Type, CheckError> {
 | 
				
			||||||
 | 
					        if init_to.is_some() {
 | 
				
			||||||
 | 
					            return Err("can't init to statement type AsType (move type annotations from initialization to statement?)".to_string().into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let return_type = self.statement.check(info, None)?;
 | 
				
			||||||
 | 
					        let as_type =
 | 
				
			||||||
 | 
					            crate::parsing::types::type_from_parsed(&self.as_type, info).map_err(|e| {
 | 
				
			||||||
 | 
					                CheckError::new()
 | 
				
			||||||
 | 
					                    .src(vec![(
 | 
				
			||||||
 | 
					                        self.type_pos_in_src,
 | 
				
			||||||
 | 
					                        Some(error_colors::BadTypeFromParsed),
 | 
				
			||||||
 | 
					                    )])
 | 
				
			||||||
 | 
					                    .err(e)
 | 
				
			||||||
 | 
					            })?;
 | 
				
			||||||
 | 
					        if !return_type.is_included_in(&as_type) {
 | 
				
			||||||
 | 
					            return Err(CheckError::new()
 | 
				
			||||||
 | 
					                .src(vec![
 | 
				
			||||||
 | 
					                    (self.pos_in_src, None),
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        self.type_pos_in_src,
 | 
				
			||||||
 | 
					                        Some(error_colors::AsTypeTypeAnnotation),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        self.statement.source_range(),
 | 
				
			||||||
 | 
					                        Some(error_colors::AsTypeStatementWithTooBroadType),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                ])
 | 
				
			||||||
 | 
					                .msg(format!(
 | 
				
			||||||
 | 
					                    "Type must be included in {}, but the actual type {} isn't.",
 | 
				
			||||||
 | 
					                    as_type
 | 
				
			||||||
 | 
					                        .to_string()
 | 
				
			||||||
 | 
					                        .color(error_colors::AsTypeTypeAnnotation),
 | 
				
			||||||
 | 
					                    return_type
 | 
				
			||||||
 | 
					                        .to_string()
 | 
				
			||||||
 | 
					                        .color(error_colors::AsTypeStatementWithTooBroadType)
 | 
				
			||||||
 | 
					                )));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(if self.expand_type {
 | 
				
			||||||
 | 
					            as_type.clone()
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return_type
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn run_custom(&self, info: &mut super::Info) -> Data {
 | 
				
			||||||
 | 
					        self.statement.run(info)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn has_scope(&self) -> bool {
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn source_range(&self) -> SourceRange {
 | 
				
			||||||
 | 
					        self.pos_in_src
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								mers_lib/src/program/run/custom_type.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								mers_lib/src/program/run/custom_type.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					use std::{fmt::Debug, sync::Arc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    data::{Data, MersType, Type},
 | 
				
			||||||
 | 
					    errors::{CheckError, SourceRange},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::{CheckInfo, Info, MersStatement};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct CustomType {
 | 
				
			||||||
 | 
					    pub pos_in_src: SourceRange,
 | 
				
			||||||
 | 
					    pub name: String,
 | 
				
			||||||
 | 
					    pub source: Box<
 | 
				
			||||||
 | 
					        dyn Fn(
 | 
				
			||||||
 | 
					                &CheckInfo,
 | 
				
			||||||
 | 
					            ) -> Result<
 | 
				
			||||||
 | 
					                Result<
 | 
				
			||||||
 | 
					                    Arc<dyn MersType>,
 | 
				
			||||||
 | 
					                    Arc<
 | 
				
			||||||
 | 
					                        dyn Fn(&str, &CheckInfo) -> Result<Arc<dyn MersType>, CheckError>
 | 
				
			||||||
 | 
					                            + Send
 | 
				
			||||||
 | 
					                            + Sync,
 | 
				
			||||||
 | 
					                    >,
 | 
				
			||||||
 | 
					                >,
 | 
				
			||||||
 | 
					                CheckError,
 | 
				
			||||||
 | 
					            > + Send
 | 
				
			||||||
 | 
					            + Sync,
 | 
				
			||||||
 | 
					    >,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MersStatement for CustomType {
 | 
				
			||||||
 | 
					    fn check_custom(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        info: &mut CheckInfo,
 | 
				
			||||||
 | 
					        init_to: Option<&Type>,
 | 
				
			||||||
 | 
					    ) -> Result<Type, CheckError> {
 | 
				
			||||||
 | 
					        if init_to.is_some() {
 | 
				
			||||||
 | 
					            return Err("can't init to `type` statement".to_string().into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let t = (self.source)(info)?;
 | 
				
			||||||
 | 
					        info.scopes
 | 
				
			||||||
 | 
					            .last_mut()
 | 
				
			||||||
 | 
					            .unwrap()
 | 
				
			||||||
 | 
					            .types
 | 
				
			||||||
 | 
					            .insert(self.name.clone(), t);
 | 
				
			||||||
 | 
					        Ok(Type::empty_tuple())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn run_custom(&self, _info: &mut Info) -> Data {
 | 
				
			||||||
 | 
					        Data::empty_tuple()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn has_scope(&self) -> bool {
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn source_range(&self) -> SourceRange {
 | 
				
			||||||
 | 
					        self.pos_in_src
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Debug for CustomType {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "<CustomType>")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,14 +1,17 @@
 | 
				
			|||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
 | 
					    collections::HashMap,
 | 
				
			||||||
    fmt::Debug,
 | 
					    fmt::Debug,
 | 
				
			||||||
    sync::{Arc, RwLock},
 | 
					    sync::{Arc, RwLock},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    data::{self, Data, Type},
 | 
					    data::{self, Data, MersType, Type},
 | 
				
			||||||
    errors::{CheckError, SourceRange},
 | 
					    errors::{CheckError, SourceRange},
 | 
				
			||||||
    info,
 | 
					    info,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
 | 
					pub mod as_type;
 | 
				
			||||||
#[cfg(feature = "run")]
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
pub mod assign_to;
 | 
					pub mod assign_to;
 | 
				
			||||||
#[cfg(feature = "run")]
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
@ -16,6 +19,8 @@ pub mod block;
 | 
				
			|||||||
#[cfg(feature = "run")]
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
pub mod chain;
 | 
					pub mod chain;
 | 
				
			||||||
#[cfg(feature = "run")]
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
 | 
					pub mod custom_type;
 | 
				
			||||||
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
pub mod function;
 | 
					pub mod function;
 | 
				
			||||||
#[cfg(feature = "run")]
 | 
					#[cfg(feature = "run")]
 | 
				
			||||||
pub mod r#if;
 | 
					pub mod r#if;
 | 
				
			||||||
@ -65,13 +70,26 @@ pub type CheckInfo = info::Info<CheckLocal>;
 | 
				
			|||||||
pub struct Local {
 | 
					pub struct Local {
 | 
				
			||||||
    vars: Vec<Arc<RwLock<Data>>>,
 | 
					    vars: Vec<Arc<RwLock<Data>>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#[derive(Default, Clone, Debug)]
 | 
					#[derive(Default, Clone)]
 | 
				
			||||||
pub struct CheckLocal {
 | 
					pub struct CheckLocal {
 | 
				
			||||||
    vars: Vec<Type>,
 | 
					    vars: Vec<Type>,
 | 
				
			||||||
 | 
					    pub types: HashMap<
 | 
				
			||||||
 | 
					        String,
 | 
				
			||||||
 | 
					        Result<
 | 
				
			||||||
 | 
					            Arc<dyn MersType>,
 | 
				
			||||||
 | 
					            Arc<dyn Fn(&str, &CheckInfo) -> Result<Arc<dyn MersType>, CheckError> + Send + Sync>,
 | 
				
			||||||
 | 
					        >,
 | 
				
			||||||
 | 
					    >,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Debug for CheckLocal {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "CheckLocal {:?}, {:?}", self.vars, self.types.keys())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
impl info::Local for Local {
 | 
					impl info::Local for Local {
 | 
				
			||||||
    type VariableIdentifier = usize;
 | 
					    type VariableIdentifier = usize;
 | 
				
			||||||
    type VariableData = Arc<RwLock<Data>>;
 | 
					    type VariableData = Arc<RwLock<Data>>;
 | 
				
			||||||
 | 
					    type Global = ();
 | 
				
			||||||
    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
					    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
				
			||||||
        let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
 | 
					        let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
 | 
				
			||||||
        while self.vars.len() <= id {
 | 
					        while self.vars.len() <= id {
 | 
				
			||||||
@ -104,6 +122,7 @@ impl info::Local for Local {
 | 
				
			|||||||
impl info::Local for CheckLocal {
 | 
					impl info::Local for CheckLocal {
 | 
				
			||||||
    type VariableIdentifier = usize;
 | 
					    type VariableIdentifier = usize;
 | 
				
			||||||
    type VariableData = Type;
 | 
					    type VariableData = Type;
 | 
				
			||||||
 | 
					    type Global = ();
 | 
				
			||||||
    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
					    fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
 | 
				
			||||||
        while self.vars.len() <= id {
 | 
					        while self.vars.len() <= id {
 | 
				
			||||||
            self.vars.push(Type::empty());
 | 
					            self.vars.push(Type::empty());
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,8 @@ use super::MersStatement;
 | 
				
			|||||||
pub struct Variable {
 | 
					pub struct Variable {
 | 
				
			||||||
    pub pos_in_src: SourceRange,
 | 
					    pub pos_in_src: SourceRange,
 | 
				
			||||||
    pub is_init: bool,
 | 
					    pub is_init: bool,
 | 
				
			||||||
    pub is_ref: bool,
 | 
					    // if `is_init` is true, this must also be true unless using the "ignore" `_` pattern
 | 
				
			||||||
 | 
					    pub is_ref_not_ignore: bool,
 | 
				
			||||||
    pub var: (usize, usize),
 | 
					    pub var: (usize, usize),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -25,14 +26,22 @@ impl MersStatement for Variable {
 | 
				
			|||||||
        init_to: Option<&Type>,
 | 
					        init_to: Option<&Type>,
 | 
				
			||||||
    ) -> Result<data::Type, super::CheckError> {
 | 
					    ) -> Result<data::Type, super::CheckError> {
 | 
				
			||||||
        if self.is_init {
 | 
					        if self.is_init {
 | 
				
			||||||
 | 
					            if self.is_ref_not_ignore {
 | 
				
			||||||
                while info.scopes[self.var.0].vars.len() <= self.var.1 {
 | 
					                while info.scopes[self.var.0].vars.len() <= self.var.1 {
 | 
				
			||||||
                    info.scopes[self.var.0].vars.push(Type::empty());
 | 
					                    info.scopes[self.var.0].vars.push(Type::empty());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                info.scopes[self.var.0].vars[self.var.1] = init_to
 | 
					                info.scopes[self.var.0].vars[self.var.1] = init_to
 | 
				
			||||||
                    .expect("variable's is_init was true, but check_custom's assign was None? How?")
 | 
					                    .expect("variable's is_init was true, but check_custom's assign was None? How?")
 | 
				
			||||||
                    .clone();
 | 
					                    .clone();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return Ok(Type::new(data::reference::ReferenceT(
 | 
				
			||||||
 | 
					                    init_to
 | 
				
			||||||
 | 
					                        .expect("var's is_init was true, but init_to was None???")
 | 
				
			||||||
 | 
					                        .clone(),
 | 
				
			||||||
 | 
					                )));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        let val = if self.is_ref {
 | 
					        }
 | 
				
			||||||
 | 
					        let val = if self.is_ref_not_ignore {
 | 
				
			||||||
            Type::new(data::reference::ReferenceT(
 | 
					            Type::new(data::reference::ReferenceT(
 | 
				
			||||||
                info.scopes[self.var.0].vars[self.var.1].clone(),
 | 
					                info.scopes[self.var.0].vars[self.var.1].clone(),
 | 
				
			||||||
            ))
 | 
					            ))
 | 
				
			||||||
@ -43,13 +52,20 @@ impl MersStatement for Variable {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    fn run_custom(&self, info: &mut super::Info) -> Data {
 | 
					    fn run_custom(&self, info: &mut super::Info) -> Data {
 | 
				
			||||||
        if self.is_init {
 | 
					        if self.is_init {
 | 
				
			||||||
 | 
					            if self.is_ref_not_ignore {
 | 
				
			||||||
                let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
 | 
					                let nothing = Arc::new(RwLock::new(Data::new(data::bool::Bool(false))));
 | 
				
			||||||
                while info.scopes[self.var.0].vars.len() <= self.var.1 {
 | 
					                while info.scopes[self.var.0].vars.len() <= self.var.1 {
 | 
				
			||||||
                    info.scopes[self.var.0].vars.push(Arc::clone(¬hing));
 | 
					                    info.scopes[self.var.0].vars.push(Arc::clone(¬hing));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                info.scopes[self.var.0].vars[self.var.1] = nothing;
 | 
					                info.scopes[self.var.0].vars[self.var.1] = nothing;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // (reference to) data which will never be referenced again
 | 
				
			||||||
 | 
					                return Data::new(data::reference::Reference(Arc::new(RwLock::new(
 | 
				
			||||||
 | 
					                    Data::empty_tuple(),
 | 
				
			||||||
 | 
					                ))));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        if self.is_ref {
 | 
					        }
 | 
				
			||||||
 | 
					        if self.is_ref_not_ignore {
 | 
				
			||||||
            Data::new(data::reference::Reference(Arc::clone(
 | 
					            Data::new(data::reference::Reference(Arc::clone(
 | 
				
			||||||
                &info.scopes[self.var.0].vars[self.var.1],
 | 
					                &info.scopes[self.var.0].vars[self.var.1],
 | 
				
			||||||
            )))
 | 
					            )))
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user