mers rewrite is starting to be usable

This commit is contained in:
Mark
2023-08-14 17:17:08 +02:00
parent e549b1a5be
commit 2a7cb08596
50 changed files with 1411 additions and 407 deletions

View File

@@ -5,6 +5,6 @@ edition = "2021"
[features]
default = []
default = ["parse"]
parse = ["run"]
run = []

View File

@@ -1,5 +1,10 @@
# mers documentation
## ISSUES
when storing a reference, then reinitializing a variable of the same name, the reference may get the new value although
it would be expected for it to be a reference to the value before it was reinitialized.
## parsing
syntax:

View File

@@ -1,14 +1,24 @@
use std::{any::Any, fmt::Display};
use super::{MersData, MersType};
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Bool(pub bool);
impl MersData for Bool {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
false
}
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> super::Type {
Type::new(BoolT)
}
fn as_any(&self) -> &dyn Any {
self
}
@@ -45,3 +55,8 @@ impl Display for Bool {
write!(f, "{}", self.0)
}
}
impl Display for BoolT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Bool")
}
}

View File

@@ -1,12 +1,14 @@
use super::Data;
use crate::program::run::CheckError;
use super::{Data, MersType, Type};
pub fn assign(from: Data, target: &Data) {
let mut target = target.get_mut();
let target = target.get();
if let Some(r) = target
.mut_any()
.downcast_mut::<crate::data::reference::Reference>()
.as_any()
.downcast_ref::<crate::data::reference::Reference>()
{
*r.0.get_mut() = from.get().clone();
*r.0.lock().unwrap().get_mut() = from.get().clone();
} else {
todo!("assignment to non-reference")
}

View File

@@ -6,9 +6,19 @@ use super::{MersData, MersType, Type};
pub struct Float(pub f64);
impl MersData for Float {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
false
}
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> super::Type {
Type::new(FloatT)
}
fn as_any(&self) -> &dyn Any {
self
}
@@ -45,3 +55,8 @@ impl Display for Float {
write!(f, "{}", self.0)
}
}
impl Display for FloatT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Float")
}
}

View File

@@ -1,36 +1,57 @@
use std::{
any::Any,
fmt::{Debug, Display},
sync::Arc,
sync::{Arc, Mutex},
};
use crate::program::{self, run::Info};
use crate::program::{
self,
run::{CheckError, CheckInfo, Info},
};
use super::{Data, MersData, MersType, Type};
#[derive(Clone)]
pub struct Function {
pub info: Info,
pub out: Arc<dyn Fn(&Type) -> Option<Type>>,
pub run: Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Data>,
pub info: Arc<Info>,
pub info_check: Arc<Mutex<CheckInfo>>,
pub out: Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
pub run: Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Data + Send + Sync>,
}
impl Function {
pub fn with_info(&self, info: program::run::Info) -> Self {
pub fn with_info_run(&self, info: Arc<Info>) -> Self {
Self {
info,
info_check: Arc::clone(&self.info_check),
out: Arc::clone(&self.out),
run: Arc::clone(&self.run),
}
}
pub fn with_info_check(&self, check: CheckInfo) {
*self.info_check.lock().unwrap() = check;
}
pub fn check(&self, arg: &Type) -> Result<Type, CheckError> {
(self.out)(arg, &mut self.info_check.lock().unwrap().clone())
}
pub fn run(&self, arg: Data) -> Data {
(self.run)(arg, &mut self.info.clone())
(self.run)(arg, &mut self.info.as_ref().clone())
}
}
impl MersData for Function {
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> Type {
let out = Arc::clone(&self.out);
let info = Arc::clone(&self.info_check);
Type::new(FunctionT(Arc::new(move |a| {
out(a, &mut info.lock().unwrap().clone())
})))
}
fn as_any(&self) -> &dyn Any {
self
}
@@ -42,7 +63,7 @@ impl MersData for Function {
}
}
pub struct FunctionT(Arc<dyn Fn(&Type) -> Option<Type>>);
pub struct FunctionT(pub Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>);
impl MersType for FunctionT {
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
false
@@ -77,3 +98,8 @@ impl Display for Function {
write!(f, "<function>")
}
}
impl Display for FunctionT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Function")
}
}

View File

@@ -6,9 +6,19 @@ use super::{MersData, MersType, Type};
pub struct Int(pub isize);
impl MersData for Int {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
false
}
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> super::Type {
Type::new(IntT)
}
fn as_any(&self) -> &dyn Any {
self
}
@@ -45,3 +55,8 @@ impl Display for Int {
write!(f, "{}", self.0)
}
}
impl Display for IntT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Int")
}
}

View File

@@ -1,7 +1,7 @@
use std::{
any::Any,
fmt::{Debug, Display},
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
pub mod bool;
@@ -14,10 +14,7 @@ pub mod tuple;
pub mod defs;
pub trait MersData: Any + Debug + Display {
fn matches(&self) -> Option<Data> {
None
}
pub trait MersData: Any + Debug + Display + Send + Sync {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
None
}
@@ -26,18 +23,17 @@ pub trait MersData: Any + Debug + Display {
fn get(&self, i: usize) -> Option<Data> {
self.iterable()?.nth(i)
}
/// If self and other are different types (`other.as_any().downcast_ref::<Self>().is_none()`),
/// this *must* return false.
fn is_eq(&self, other: &dyn MersData) -> bool;
fn clone(&self) -> Box<dyn MersData>;
fn as_type(&self) -> Type;
fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>;
}
pub trait MersType: Any + Debug {
/// If Some((_, false)) is returned, data of this type could match. If it matches, it matches with the type.
/// If Some((_, true)) is returned, data of this type will always match with the type.
fn matches(&self) -> Option<(Type, bool)> {
None
}
pub trait MersType: Any + Debug + Display + Send + Sync {
/// If Some(T), calling `iterable` on the MersData this MersType belongs to
/// Should return Some(I), where I is an Iterator which only returns items of type T.
fn iterable(&self) -> Option<Type> {
@@ -66,18 +62,28 @@ pub trait MersType: Any + Debug {
fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>;
fn is_reference_to(&self) -> Option<&Type> {
None
}
}
#[derive(Debug)]
pub struct Data {
is_mut: bool,
counts: Arc<(AtomicUsize, AtomicUsize)>,
pub data: Arc<RwLock<Box<dyn MersData>>>,
}
impl Data {
pub fn new<T: MersData>(data: T) -> Self {
Self::new_boxed(Box::new(data))
Self::new_boxed(Box::new(data), true)
}
pub fn new_boxed(data: Box<dyn MersData>) -> Self {
pub fn new_boxed(data: Box<dyn MersData>, is_mut: bool) -> Self {
Self {
is_mut,
counts: Arc::new((
AtomicUsize::new(if is_mut { 0 } else { 1 }),
AtomicUsize::new(if is_mut { 1 } else { 0 }),
)),
data: Arc::new(RwLock::new(data)),
}
}
@@ -87,27 +93,116 @@ impl Data {
pub fn one_tuple(v: Self) -> Self {
Self::new(tuple::Tuple(vec![v]))
}
/// Returns true if self is `()`.
pub fn is_zero_tuple(&self) -> bool {
if let Some(tuple) = self
.get()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>()
{
tuple.0.is_empty()
} else {
false
}
}
/// Returns `Some(d)` if and only if self is `(d)`.
pub fn one_tuple_content(&self) -> Option<Data> {
if let Some(data) = self
.get()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>()
.filter(|v| v.len() == 1)
.and_then(|v| v.get(0))
{
Some(data.clone())
} else {
None
}
}
pub fn get(&self) -> RwLockReadGuard<Box<dyn MersData>> {
#[cfg(debug_assertions)]
eprintln!("[mers:data:cow] get");
self.data.read().unwrap()
}
pub fn get_mut(&self) -> RwLockWriteGuard<Box<dyn MersData>> {
pub fn get_mut_unchecked(&self) -> RwLockWriteGuard<Box<dyn MersData>> {
self.data.write().unwrap()
}
pub fn try_get_mut(&self) -> Option<RwLockWriteGuard<Box<dyn MersData>>> {
if self.is_mut && self.counts.0.load(std::sync::atomic::Ordering::Relaxed) == 0 {
Some(self.get_mut_unchecked())
} else {
None
}
}
/// like try_get_mut, but instead of returning `None` this function `get()`s the data and clones it.
/// When cloning data, this transforms `self` into a `Data` with `is_mut: true`, hence the `&mut self` parameter.
pub fn get_mut(&mut self) -> RwLockWriteGuard<Box<dyn MersData>> {
if self.try_get_mut().is_none() {
#[cfg(debug_assertions)]
eprintln!(
"[mers:data:cow] cloning! get_mut called on {}",
if !self.is_mut {
"non-mut value"
} else {
"value with immut references"
}
);
let val = self.get().clone();
*self = Self::new_boxed(val, true);
}
self.get_mut_unchecked()
}
pub fn mkref(&self) -> Self {
if self.is_mut {
self.counts
.1
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Self {
is_mut: true,
counts: Arc::clone(&self.counts),
data: Arc::clone(&self.data),
}
} else {
#[cfg(debug_assertions)]
eprintln!("[mers:data:cow] cloning! mkref called on immutable data");
Self::new_boxed(self.data.read().unwrap().clone(), true)
}
}
}
impl Clone for Data {
fn clone(&self) -> Self {
// todo!("clone for data - requires CoW");
self.counts
.0
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Self {
is_mut: false,
counts: Arc::clone(&self.counts),
data: Arc::clone(&self.data),
}
}
}
impl Drop for Data {
fn drop(&mut self) {
if self.is_mut {
&self.counts.1
} else {
&self.counts.0
}
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
}
}
impl PartialEq for Data {
fn eq(&self, other: &Self) -> bool {
self.get().is_eq(other.get().as_ref())
}
}
#[derive(Clone, Debug)]
pub struct Type {
// TODO: Maybe make sure this is always sorted by (recursive?!?) TypeId,
// that way is_same_type_as can work more efficiently (cuz good code but also branch prediction)
types: Vec<Arc<dyn MersType>>,
pub types: Vec<Arc<dyn MersType>>,
}
impl Type {
pub fn new<T: MersType>(t: T) -> Self {
@@ -118,11 +213,64 @@ impl Type {
pub fn newm(types: Vec<Arc<dyn MersType>>) -> Self {
Self { types }
}
pub fn empty() -> Self {
Self { types: vec![] }
}
pub fn empty_tuple() -> Self {
Self::new(tuple::TupleT(vec![]))
}
pub fn add<T: MersType>(&mut self, new: Box<T>) {
todo!()
/// Returns true if self is `()`.
pub fn is_zero_tuple(&self) -> bool {
let mut o = false;
for t in &self.types {
o = true;
if let Some(tuple) = t.as_any().downcast_ref::<crate::data::tuple::TupleT>() {
if !tuple.0.is_empty() {
return false;
}
} else {
return false;
}
}
o
}
/// Returns `Some(d)` if and only if self is `(d)`.
pub fn one_tuple_content(&self) -> Option<Type> {
let mut o = Self::empty();
for t in &self.types {
if let Some(t) = t
.as_any()
.downcast_ref::<crate::data::tuple::TupleT>()
.filter(|v| v.0.len() == 1)
.and_then(|v| v.0.get(0))
{
o.add(Arc::new(t.clone()));
} else {
return None;
}
}
Some(o)
}
pub fn add(&mut self, new: Arc<dyn MersType>) {
let n = new.as_any();
if let Some(s) = n.downcast_ref::<Self>() {
for t in &s.types {
self.add(Arc::clone(t));
}
} else {
self.types.push(new);
}
}
pub fn dereference(&self) -> Option<Self> {
let mut o = Self::empty();
for t in &self.types {
if let Some(t) = t.is_reference_to() {
o.add(Arc::new(t.clone()));
} else {
return None;
}
}
Some(o)
}
}
@@ -141,7 +289,7 @@ impl MersType for Type {
todo!()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
todo!()
self.types.iter().all(|t| t.is_included_in_single(target))
}
fn as_any(&self) -> &dyn Any {
self
@@ -152,4 +300,45 @@ impl MersType for Type {
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
fn iterable(&self) -> Option<Type> {
let mut o = Self::empty();
for t in self.types.iter() {
if let Some(t) = t.iterable() {
o.add(Arc::new(t));
} else {
return None;
}
}
Some(o)
}
fn get(&self) -> Option<Type> {
let mut o = Self::empty();
for t in self.types.iter() {
if let Some(t) = t.get() {
o.add(Arc::new(t));
} else {
return None;
}
}
Some(o)
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.types.is_empty() {
write!(f, "<unreachable>")
} else {
if self.types.len() > 1 {
write!(f, "{{")?;
}
write!(f, "{}", self.types[0])?;
for t in self.types.iter().skip(1) {
write!(f, "/{t}")?;
}
if self.types.len() > 1 {
write!(f, "}}")?;
}
Ok(())
}
}
}

View File

@@ -1,14 +1,28 @@
use std::{any::Any, fmt::Display, sync::Mutex};
use std::{
any::Any,
fmt::Display,
sync::{Arc, Mutex},
};
use super::{Data, MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Reference(pub Data);
pub struct Reference(pub Arc<Mutex<Data>>);
impl MersData for Reference {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
*other.0.lock().unwrap() == *self.0.lock().unwrap()
} else {
false
}
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> Type {
Type::new(ReferenceT(self.0.lock().unwrap().get().as_type()))
}
fn as_any(&self) -> &dyn Any {
self
}
@@ -31,6 +45,7 @@ impl MersType for ReferenceT {
}
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
// &int isn't included in &(int/float), otherwise we could assign a float to it
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
@@ -42,10 +57,18 @@ impl MersType for ReferenceT {
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
fn is_reference_to(&self) -> Option<&Type> {
Some(&self.0)
}
}
impl Display for Reference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "&{}", self.0.get())
write!(f, "&{}", self.0.lock().unwrap().get())
}
}
impl Display for ReferenceT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "&{}", self.0)
}
}

View File

@@ -6,12 +6,22 @@ use super::{MersData, MersType, Type};
pub struct String(pub std::string::String);
impl MersData for String {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
false
}
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_type(&self) -> super::Type {
Type::new(StringT)
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
@@ -45,3 +55,8 @@ impl Display for String {
write!(f, "{}", self.0)
}
}
impl Display for StringT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "String")
}
}

View File

@@ -1,4 +1,4 @@
use std::{any::Any, fmt::Display};
use std::{any::Any, fmt::Display, sync::Arc};
use super::{Data, MersData, MersType, Type};
@@ -15,15 +15,11 @@ impl Tuple {
}
impl MersData for Tuple {
fn matches(&self) -> Option<Data> {
if let Some(d) = self.0.first() {
if self.0.len() == 1 {
Some(d.clone())
} else {
None
}
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
None
false
}
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
@@ -32,6 +28,9 @@ impl MersData for Tuple {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> Type {
Type::new(TupleT(self.0.iter().map(|v| v.get().as_type()).collect()))
}
fn as_any(&self) -> &dyn Any {
self
}
@@ -46,19 +45,12 @@ impl MersData for Tuple {
#[derive(Debug)]
pub struct TupleT(pub Vec<Type>);
impl MersType for TupleT {
fn matches(&self) -> Option<(Type, bool)> {
if let Some(d) = self.0.first() {
if self.0.len() == 1 {
Some((d.clone(), true))
} else {
None
}
} else {
None
}
}
fn iterable(&self) -> Option<Type> {
Some(todo!("joine types"))
let mut o = Type::empty();
for t in self.0.iter() {
o.add(Arc::new(t.clone()));
}
Some(o)
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
@@ -90,3 +82,16 @@ impl Display for Tuple {
Ok(())
}
}
impl Display for TupleT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "(")?;
for (i, c) in self.0.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", c)?;
}
write!(f, ")")?;
Ok(())
}
}

View File

@@ -0,0 +1 @@

View File

@@ -1,9 +1,6 @@
use std::sync::Arc;
use crate::{
info::Info,
program::{self, parsed::CompInfo},
};
use crate::program;
pub mod errors;
pub mod statements;
@@ -96,7 +93,7 @@ impl Source {
/// Useful for debugging the parser.
pub fn section_begin(&mut self, section: String) -> Arc<String> {
#[cfg(debug_assertions)]
println!("Section begin: {}", &section);
println!("[mers:parse] Section begin: {}", &section);
let arc = Arc::new(section);
self.sections.push(SectionMarker {
section: Arc::clone(&arc),
@@ -141,7 +138,7 @@ impl SectionMarker {
if Arc::strong_count(&self.section) == 1 {
self.end = Some(end);
#[cfg(debug_assertions)]
println!("Section end : {}", &self.section);
println!("[mers:parse] Section end : {}", &self.section);
}
}
}

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use super::Source;
use crate::{
data::{self, Data},
data::Data,
program::{self, parsed::MersStatement},
};
@@ -142,12 +142,6 @@ pub fn parse_no_chain(
},
})
}
"loop" => {
src.section_begin("loop".to_string());
Box::new(program::parsed::r#loop::Loop {
inner: parse(src)?.expect("err: EOF instead of inner statement after loop"),
})
}
"switch" => {
src.section_begin("loop".to_string());
todo!()

View File

@@ -1,17 +1,18 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data, Type},
data::{Data, Type},
info::Local,
program,
};
mod with_base;
mod with_command_running;
mod with_get;
mod with_iters;
mod with_list;
mod with_math;
mod with_prints;
mod with_multithreading;
mod with_stdio;
/// Usage: create an empty Config using Config::new(), use the methods to customize it, then get the Infos using Config::infos()
/// bundle_* for bundles (combines multiple groups or even bundles)
@@ -27,23 +28,30 @@ pub struct Config {
globals: usize,
info_parsed: super::parsed::Info,
info_run: super::run::Info,
info_check: super::run::CheckInfo,
}
impl Config {
/// standard utilitis used in many programs
/// `bundle_base()`
/// `with_stdio()`
/// `with_list()`
/// `with_command_running()`
/// `with_multithreading()`
pub fn bundle_std(self) -> Self {
self.with_command_running().with_list().bundle_base()
self.with_multithreading()
.with_command_running()
.with_list()
.with_stdio()
.bundle_base()
}
/// base utilities used in most programs
/// `with_prints()`
/// `with_base()`
/// `with_math()`
/// `with_get()`
/// `with_iters()`
pub fn bundle_base(self) -> Self {
self.with_iters().with_get().with_math().with_prints()
self.with_iters().with_get().with_math().with_base()
}
pub fn new() -> Self {
@@ -51,12 +59,15 @@ impl Config {
globals: 0,
info_parsed: Default::default(),
info_run: Default::default(),
info_check: Default::default(),
}
}
pub fn add_var(mut self, name: String, val: Data) -> Self {
let t = val.get().as_type();
self.info_parsed.scopes[0].init_var(name, (0, self.globals));
self.info_run.scopes[0].init_var(self.globals, val);
self.info_run.scopes[0].init_var(self.globals, Arc::new(Mutex::new(val)));
self.info_check.scopes[0].init_var(self.globals, t);
self.globals += 1;
self
}
@@ -65,7 +76,7 @@ impl Config {
self
}
pub fn infos(self) -> (super::parsed::Info, super::run::Info) {
(self.info_parsed, self.info_run)
pub fn infos(self) -> (super::parsed::Info, super::run::Info, super::run::CheckInfo) {
(self.info_parsed, self.info_run, self.info_check)
}
}

View File

@@ -0,0 +1,108 @@
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data, MersType, Type},
program::run::{CheckInfo, Info},
};
use super::Config;
impl Config {
/// `deref: fn` clones the value from a reference
/// `eq: fn` returns true if all the values are equal, otherwise false.
/// `loop: fn` runs a function until it returns (T) instead of (), then returns T.
pub fn with_base(self) -> Self {
self.add_var(
"loop".to_string(),
Data::new(data::function::Function {
info: Arc::new(Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| {
dbg!(a);
let mut o = Type::empty();
for t in &a.types {
if let Some(t) = t.as_any().downcast_ref::<data::function::FunctionT>() {
for t in (t.0)(&Type::empty_tuple())?.types {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
if t.0.len() > 1 {
return Err(crate::program::run::CheckError(format!("called loop with funcion that might return a tuple of length > 1")));
} else if let Some(v) = t.0.first() {
o.add(Arc::new(v.clone()))
}
} else {
return Err(crate::program::run::CheckError(format!("called loop with funcion that might return something other than a tuple")));
}
}
} else {
return Err(crate::program::run::CheckError(format!("called loop on a non-function")));
}
}
Ok(o)
}),
run: Arc::new(|a, _i| {
if let Some(r) = a.get().as_any().downcast_ref::<data::function::Function>() {
loop {
if let Some(r) = r.run(Data::empty_tuple()).one_tuple_content() {
break r;
}
}
} else {
unreachable!("called loop on non-function")
}
}),
}),
)
.add_var(
"eq".to_string(),
Data::new(data::function::Function {
info: Arc::new(Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| {
for t in &a.types {
if t.iterable().is_none() {
return Err(crate::program::run::CheckError(format!("called eq on non-iterable")))
}
}
Ok(Type::new(data::bool::BoolT))
}),
run: Arc::new(|a, _i| {
Data::new(data::bool::Bool(if let Some(mut i) = a.get().iterable() {
if let Some(f) = i.next() {
let mut o = true;
for el in i {
if el != f {
o = false;
break;
}
}
o
} else {
false
}
} else {
false
}))
}),
}),
)
.add_var(
"deref".to_string(),
Data::new(data::function::Function {
info: Arc::new(Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| if let Some(v) = a.dereference() { Ok(v) } else { Err(crate::program::run::CheckError(format!("cannot dereference type {a}")))}),
run: Arc::new(|a, _i| {
if let Some(r) = a
.get()
.as_any()
.downcast_ref::<data::reference::Reference>()
{
r.0.lock().unwrap().clone()
} else {
unreachable!("called deref on non-reference")
}
}),
}),
)
}
}

View File

@@ -1,8 +1,12 @@
use std::{fmt::Display, process::Command, sync::Arc};
use std::{
fmt::Display,
process::Command,
sync::{Arc, Mutex},
};
use crate::{
data::{self, Data, MersData, MersType},
program,
data::{self, Data, MersData, MersType, Type},
program::{self, run::CheckInfo},
};
use super::Config;
@@ -16,8 +20,9 @@ impl Config {
self.add_var(
"run_command".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| {
if let Some(cmd) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(cmd), Some(args)) = (cmd.get(0), cmd.get(1)) {
@@ -67,9 +72,19 @@ pub struct RunCommandError(String);
#[derive(Debug)]
pub struct RunCommandErrorT;
impl MersData for RunCommandError {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
false
}
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> data::Type {
Type::new(RunCommandErrorT)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
@@ -102,3 +117,8 @@ impl Display for RunCommandError {
write!(f, "RunCommandError: {}", self.0)
}
}
impl Display for RunCommandErrorT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RunCommandError")
}
}

19
mers_lib/src/program/configs/with_get.rs Normal file → Executable file
View File

@@ -1,8 +1,8 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data},
program,
data::{self, Data, MersType},
program::{self, run::CheckInfo},
};
use super::Config;
@@ -13,8 +13,17 @@ impl Config {
self.add_var(
"get".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| {
if let Some(v) = a.get() {
Ok(v)
} else {
Err(program::run::CheckError(format!(
"called get on non-gettable type {a}"
)))
}
}),
run: Arc::new(|a, _i| {
let a = a.get();
if let (Some(v), Some(i)) = (a.get(0), a.get(1)) {

View File

@@ -1,8 +1,14 @@
use std::{fmt::Display, sync::Arc};
use std::{
fmt::Display,
sync::{Arc, Mutex},
};
use crate::{
data::{self, Data, MersData},
program,
data::{self, Data, MersData, MersType, Type},
program::{
self,
run::{CheckError, CheckInfo},
},
};
use super::Config;
@@ -12,14 +18,51 @@ impl Config {
/// `iter: fn` executes a function once for each element of the iterable
/// `map: fn` maps each value in the iterable to a new one by applying a transformation function
/// `filter: fn` filters the iterable by removing all elements where the filter function doesn't return true
/// `filter_map: fn` combines filter and map via matching
/// `filter_map: fn` combines filter and map
/// `enumerate: fn` transforms an iterator over T into one over (Int, T), where Int is the index of the element
pub fn with_iters(self) -> Self {
self.add_var(
"iter".to_string(),
"for_each".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| {
for a in &a.types {
if let Some(tuple) = a.as_any().downcast_ref::<data::tuple::TupleT>() {
if let (Some(v), Some(f)) = (tuple.0.get(0), tuple.0.get(1)) {
if let (Some(iter), Some(f)) = (
v.iterable(),
f.types
.iter()
.map(|t| {
t.as_any().downcast_ref::<data::function::FunctionT>()
})
.collect::<Option<Vec<_>>>(),
) {
for f in f {
let ret = f.0(&iter)?;
if !ret.is_zero_tuple() {
return Err(CheckError(format!(
"for_each function must return (), not {ret}"
)));
}
}
} else {
return Err(CheckError(format!(
"for_each called on tuple not containing iterable and function"
)));
}
} else {
return Err(CheckError(format!(
"for_each called on tuple with len < 2"
)));
}
} else {
return Err(CheckError(format!("for_each called on non-tuple")));
}
}
Ok(Type::empty_tuple())
}),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@@ -33,14 +76,14 @@ impl Config {
Data::empty_tuple()
} else {
unreachable!(
"iter called on tuple not containing iterable and function"
"for_each called on tuple not containing iterable and function"
)
}
} else {
unreachable!("iter called on tuple with len < 2")
unreachable!("for_each called on tuple with len < 2")
}
} else {
unreachable!("iter called on non-tuple")
unreachable!("for_each called on non-tuple")
}
}),
}),
@@ -48,8 +91,9 @@ impl Config {
.add_var(
"map".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@@ -72,8 +116,9 @@ impl Config {
.add_var(
"filter".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@@ -96,8 +141,9 @@ impl Config {
.add_var(
"filter_map".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@@ -120,8 +166,9 @@ impl Config {
.add_var(
"enumerate".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| Data::new(Iter(Iters::Enumerate, a.clone()))),
}),
)
@@ -140,6 +187,9 @@ pub struct Iter(Iters, Data);
#[derive(Clone, Debug)]
pub struct IterT(Iters);
impl MersData for Iter {
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
Some(match &self.0 {
Iters::Map(f) => {
@@ -162,7 +212,7 @@ impl MersData for Iter {
self.1
.get()
.iterable()?
.filter_map(move |v| f.run(v).get().matches()),
.filter_map(move |v| f.run(v).one_tuple_content()),
)
}
Iters::Enumerate => Box::new(self.1.get().iterable()?.enumerate().map(|(i, v)| {
@@ -171,12 +221,36 @@ impl MersData for Iter {
v,
]))
})),
_ => todo!(),
})
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> data::Type {
Type::new(IterT(self.0.clone()))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn mut_any(&mut self) -> &mut dyn std::any::Any {
self
}
fn to_any(self) -> Box<dyn std::any::Any> {
Box::new(self)
}
}
impl MersType for IterT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
false
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
if let Some(target) = target.as_any().downcast_ref::<Self>() {
// TODO: ?
false
} else {
false
}
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
@@ -192,3 +266,8 @@ impl Display for Iter {
write!(f, "<Iter>")
}
}
impl Display for IterT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Iter>")
}
}

View File

@@ -1,8 +1,11 @@
use std::{fmt::Display, sync::Arc};
use std::{
fmt::Display,
sync::{Arc, Mutex},
};
use crate::{
data::{self, Data, MersData, MersType, Type},
program,
program::{self, run::CheckInfo},
};
use super::Config;
@@ -17,8 +20,17 @@ impl Config {
.add_var(
"as_list".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| {
if let Some(v) = a.iterable() {
Ok(Type::new(ListT(v)))
} else {
Err(program::run::CheckError(format!(
"cannot iterate over type {a}"
)))
}
}),
run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() {
Data::new(List(i.collect()))
@@ -36,12 +48,26 @@ pub struct List(Vec<Data>);
#[derive(Debug)]
pub struct ListT(Type);
impl MersData for List {
fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
other.0 == self.0
} else {
false
}
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
Some(Box::new(self.0.clone().into_iter()))
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> Type {
let mut t = Type::empty();
for el in &self.0 {
t.add(Arc::new(el.get().as_type()));
}
Type::new(ListT(t))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
@@ -88,3 +114,9 @@ impl Display for List {
Ok(())
}
}
impl Display for ListT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}]", self.0)?;
Ok(())
}
}

43
mers_lib/src/program/configs/with_math.rs Normal file → Executable file
View File

@@ -1,8 +1,11 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data},
program,
data::{self, Data, Type},
program::{
self,
run::{CheckError, CheckInfo},
},
};
use super::Config;
@@ -13,8 +16,38 @@ impl Config {
self.add_var(
"sum".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| {
let mut ints = false;
let mut floats = false;
for a in &a.types {
if let Some(i) = a.iterable() {
if i.types
.iter()
.all(|t| t.as_any().downcast_ref::<data::int::IntT>().is_some())
{
ints = true;
} else if i.types.iter().all(|t| {
t.as_any().downcast_ref::<data::int::IntT>().is_some()
|| t.as_any().downcast_ref::<data::float::FloatT>().is_some()
}) {
floats = true;
} else {
return Err(CheckError(format!("cannot get sum of iterator over type {i} because it contains types that aren't int/float")))
}
} else {
return Err(CheckError(format!(
"cannot get sum of non-iterable type {a}"
)));
}
}
Ok(match (ints, floats) {
(_, true) => Type::new(data::float::FloatT),
(true, false) => Type::new(data::int::IntT),
(false, false) => Type::empty(),
})
}),
run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() {
let mut sumi = 0;

View File

@@ -0,0 +1,156 @@
use std::{
fmt::{Debug, Display},
sync::{Arc, Mutex},
thread::JoinHandle,
};
use crate::{
data::{self, Data, MersData, MersType, Type},
program::{self, run::CheckInfo},
};
use super::Config;
impl Config {
/// `get: fn` is used to retrieve elements from collections
/// `thread: fn` turns `(func, arg)` into a `Thread`, which will run the function with the argument.
/// `thread_get_result: fn` returns `()` while the thread is running and `(result)` otherwise.
pub fn with_multithreading(self) -> Self {
self.add_type(
"Thread".to_string(),
Type::new(ThreadT(Type::empty_tuple())),
)
.add_var(
"thread".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| {
let a = a.get();
if let (Some(f), Some(arg)) = (
a.get(0).and_then(|v| {
v.get()
.as_any()
.downcast_ref::<data::function::Function>()
.cloned()
}),
a.get(1),
) {
Data::new(Thread(Arc::new(Mutex::new(Ok(std::thread::spawn(
move || f.run(arg),
))))))
} else {
unreachable!("thread called, but arg wasn't a (function, _)");
}
}),
}),
)
.add_var(
"thread_get_result".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| {
let a = a.get();
if let Some(t) = a
.get(0)
.and_then(|v| v.get().as_any().downcast_ref::<Thread>().cloned())
{
let mut t = t.0.lock().unwrap();
if t.as_ref().is_ok_and(|t| t.is_finished()) {
unsafe {
// extract the JoinHandle from the Result by replacing it with uninitialized memory.
#[allow(invalid_value)]
let thread = std::mem::replace(
&mut *t,
std::mem::MaybeUninit::uninit().assume_init(),
)
.unwrap();
// forget about t and its uninitialized memory while replacing it with the new value
std::mem::forget(std::mem::replace(
&mut *t,
Err(thread.join().unwrap()),
));
}
}
match &*t {
Ok(_) => Data::empty_tuple(),
Err(v) => Data::one_tuple(v.clone()),
}
} else {
unreachable!("thread_get_result called, but arg wasn't a Thread");
}
}),
}),
)
}
}
#[derive(Clone)]
pub struct Thread(Arc<Mutex<Result<JoinHandle<Data>, Data>>>);
#[derive(Debug)]
pub struct ThreadT(Type);
impl MersData for Thread {
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_type(&self) -> Type {
unreachable!("can't get type from Thread value! (can't construct Thread with syntax, so this should be fine?)")
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn mut_any(&mut self) -> &mut dyn std::any::Any {
self
}
fn to_any(self) -> Box<dyn std::any::Any> {
Box::new(self)
}
}
impl MersType for ThreadT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
self.0.is_same_type_as(&other.0)
} else {
false
}
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
if let Some(target) = target.as_any().downcast_ref::<Self>() {
self.0.is_included_in_single(&target.0)
} else {
false
}
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn mut_any(&mut self) -> &mut dyn std::any::Any {
self
}
fn to_any(self) -> Box<dyn std::any::Any> {
Box::new(self)
}
}
impl Debug for Thread {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Thread>")
}
}
impl Display for Thread {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Thread>")
}
}
impl Display for ThreadT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Thread>")
}
}

View File

@@ -1,73 +0,0 @@
use std::sync::Arc;
use crate::{
data::{self, Data},
program,
};
use super::Config;
impl Config {
/// `println: fn` prints to stdout and adds a newline to the end
/// `print: fn` prints to stdout
/// `eprintln: fn` prints to stderr and adds a newline to the end
/// `eprint: fn` prints to stderr
/// `debug: fn` debug-prints any value
pub fn with_prints(self) -> Self {
self.add_var(
"debug".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
eprintln!("{:#?}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"eprint".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
eprint!("{}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"eprintln".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
eprintln!("{}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"print".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
print!("{}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"println".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
println!("{}", a.get());
Data::empty_tuple()
}),
}),
)
}
}

View File

@@ -0,0 +1,92 @@
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data, Type},
program::{self, run::CheckInfo},
};
use super::Config;
impl Config {
/// `println: fn` prints to stdout and adds a newline to the end
/// `print: fn` prints to stdout
/// `eprintln: fn` prints to stderr and adds a newline to the end
/// `eprint: fn` prints to stderr
/// `debug: fn` debug-prints any value
/// `read_line: fn` reads a line from stdin and returns it
pub fn with_stdio(self) -> Self {
self.add_var(
"read_line".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| Ok(Type::new(data::string::StringT))),
run: Arc::new(|_a, _i| {
let mut line = String::new();
_ = std::io::stdin().read_line(&mut line);
Data::new(data::string::String(line))
}),
}),
)
.add_var(
"debug".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
eprintln!("{:#?}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"eprint".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
eprint!("{}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"eprintln".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
eprintln!("{}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"print".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
print!("{}", a.get());
Data::empty_tuple()
}),
}),
)
.add_var(
"println".to_string(),
Data::new(data::function::Function {
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
run: Arc::new(|a, _i| {
println!("{}", a.get());
Data::empty_tuple()
}),
}),
)
}
}

View File

@@ -1,4 +1,4 @@
use crate::{info::Local, program};
use crate::program;
use super::{CompInfo, MersStatement};
@@ -15,9 +15,10 @@ impl MersStatement for AssignTo {
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
mut comp: CompInfo,
comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::assign_to::AssignTo {
is_init: false,
target: self.target.compile(info, comp)?,
source: self.source.compile(info, comp)?,
}))

View File

@@ -1,9 +1,8 @@
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use crate::{
data::{self, Data},
info::Local,
program,
data,
program::{self, run::CheckInfo},
};
use super::{CompInfo, MersStatement};
@@ -17,7 +16,7 @@ pub struct Function {
impl MersStatement for Function {
fn has_scope(&self) -> bool {
// TODO: what???
false
true
}
fn compile_custom(
&self,
@@ -25,15 +24,21 @@ impl MersStatement for Function {
mut comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
comp.is_init = true;
let arg = self.arg.compile(info, comp)?;
let arg_target = Arc::new(self.arg.compile(info, comp)?);
comp.is_init = false;
let run = self.run.compile(info, comp)?;
let run = Arc::new(self.run.compile(info, comp)?);
let arg2 = Arc::clone(&arg_target);
let run2 = Arc::clone(&run);
Ok(Box::new(program::run::function::Function {
func_no_info: data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_i| todo!()),
run: Arc::new(move |i, info| {
data::defs::assign(i, &arg.run(info));
info: Arc::new(program::run::Info::neverused()),
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(move |a, i| {
arg2.check(i, Some(a))?;
Ok(run2.check(i, None)?)
}),
run: Arc::new(move |arg, info| {
data::defs::assign(arg, &arg_target.run(info));
run.run(info)
}),
},

View File

@@ -20,7 +20,7 @@ impl MersStatement for If {
) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::r#if::If {
condition: self.condition.compile(info, comp)?,
on_true: self.condition.compile(info, comp)?,
on_true: self.on_true.compile(info, comp)?,
on_false: if let Some(v) = &self.on_false {
Some(v.compile(info, comp)?)
} else {

View File

@@ -1,4 +1,4 @@
use crate::{info::Local, program};
use crate::program;
use super::{CompInfo, MersStatement};
@@ -22,6 +22,7 @@ impl MersStatement for InitTo {
comp.is_init = false;
let source = self.source.compile(info, comp)?;
Ok(Box::new(program::run::assign_to::AssignTo {
is_init: true,
target,
source,
}))

View File

@@ -1,23 +0,0 @@
use crate::program;
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Loop {
pub inner: Box<dyn MersStatement>,
}
impl MersStatement for Loop {
fn has_scope(&self) -> bool {
true
}
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::r#loop::Loop {
inner: self.inner.compile(info, comp)?,
}))
}
}

View File

@@ -15,17 +15,13 @@ pub mod r#if;
#[cfg(feature = "parse")]
pub mod init_to;
#[cfg(feature = "parse")]
pub mod r#loop;
#[cfg(feature = "parse")]
pub mod switch;
#[cfg(feature = "parse")]
pub mod tuple;
#[cfg(feature = "parse")]
pub mod value;
#[cfg(feature = "parse")]
pub mod variable;
pub trait MersStatement: Debug {
pub trait MersStatement: Debug + Send + Sync {
fn has_scope(&self) -> bool;
fn compile_custom(
&self,

View File

@@ -1,27 +0,0 @@
use crate::data::Type;
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Switch {
source: Box<dyn MersStatement>,
arms: Vec<SwitchArm>,
}
#[derive(Debug)]
pub struct SwitchArm {
requires_type: Type,
}
impl MersStatement for Switch {
fn has_scope(&self) -> bool {
true
}
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
comp: CompInfo,
) -> Result<Box<dyn crate::program::run::MersStatement>, String> {
todo!()
}
}

View File

@@ -11,8 +11,8 @@ impl MersStatement for Value {
}
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
comp: CompInfo,
_info: &mut crate::info::Info<super::Local>,
_comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::value::Value {
val: self.0.clone(),

View File

@@ -27,6 +27,7 @@ impl MersStatement for Variable {
)
}
Ok(Box::new(program::run::variable::Variable {
is_init: comp.is_init,
is_ref: comp.is_init || self.is_ref,
var: if let Some(v) = info.get_var(&self.var) {
*v

View File

@@ -1,14 +1,29 @@
use crate::data;
use crate::data::{self, Type};
use super::MersStatement;
use super::{CheckError, CheckInfo, MersStatement};
#[derive(Debug)]
pub struct AssignTo {
pub is_init: bool,
pub target: Box<dyn MersStatement>,
pub source: Box<dyn MersStatement>,
}
impl MersStatement for AssignTo {
fn check_custom(
&self,
info: &mut CheckInfo,
init_to: Option<&Type>,
) -> Result<Type, CheckError> {
if init_to.is_some() {
return Err(CheckError(
"can't init to statement type AssignTo".to_string(),
));
}
let source = self.source.check(info, None)?;
let target = self.target.check(info, Some(&source))?;
Ok(source)
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
let source = self.source.run(info);
let target = self.target.run(info);

View File

@@ -1,12 +1,26 @@
use std::sync::Arc;
use crate::data::Type;
use super::MersStatement;
use super::{CheckError, MersStatement};
#[derive(Debug)]
pub struct Block {
pub statements: Vec<Box<dyn MersStatement>>,
}
impl MersStatement for Block {
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<crate::data::Type, super::CheckError> {
if init_to.is_some() {
return Err(CheckError("can't init to statement type Block".to_string()));
}
let mut o = Type::empty_tuple();
for s in &self.statements {
o = s.check(info, None)?;
}
Ok(o)
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
self.statements
.iter()

View File

@@ -1,8 +1,8 @@
use std::{any::Any, sync::Arc};
use std::sync::Arc;
use crate::data::{function::Function, Data};
use crate::data::{Data, Type};
use super::MersStatement;
use super::{CheckError, MersStatement};
#[derive(Debug)]
pub struct Chain {
@@ -10,6 +10,37 @@ pub struct Chain {
pub chained: Box<dyn MersStatement>,
}
impl MersStatement for Chain {
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<Type, CheckError> {
if init_to.is_some() {
return Err(CheckError("can't init to statement type Chain".to_string()));
}
let arg = self.first.check(info, None)?;
let func = self.chained.check(info, None)?;
let mut o = Type::empty();
for func in &func.types {
if let Some(func) = func
.as_any()
.downcast_ref::<crate::data::function::FunctionT>()
{
match (func.0)(&arg) {
Ok(t) => o.add(Arc::new(t)),
Err(e) =>
return Err(CheckError(format!(
"cannot run this function with this argument (type: {arg}), because it would cause the following error:\n{e}"
))),
}
} else {
return Err(CheckError(format!(
"cannot chain with a non-function ({func})"
)));
}
}
Ok(o)
}
fn run_custom(&self, info: &mut super::Info) -> Data {
let f = self.first.run(info);
let c = self.chained.run(info);

View File

@@ -1,6 +1,8 @@
use crate::data::{self, Data, MersData};
use std::sync::Arc;
use super::MersStatement;
use crate::data::{self, Data, MersData, Type};
use super::{CheckError, MersStatement};
#[derive(Debug)]
pub struct Function {
@@ -8,10 +10,23 @@ pub struct Function {
}
impl MersStatement for Function {
fn has_scope(&self) -> bool {
false
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> {
if init_to.is_some() {
return Err(CheckError(
"can't init to statement type Function".to_string(),
));
}
self.func_no_info.with_info_check(info.clone());
Ok(self.func_no_info.as_type())
}
fn run_custom(&self, info: &mut super::Info) -> Data {
Data::new(self.func_no_info.with_info(info.clone()))
Data::new(self.func_no_info.with_info_run(Arc::new(info.clone())))
}
fn has_scope(&self) -> bool {
true
}
}

View File

@@ -1,4 +1,8 @@
use super::MersStatement;
use std::sync::Arc;
use crate::data::{self, Data, MersType, Type};
use super::{CheckError, MersStatement};
#[derive(Debug)]
pub struct If {
@@ -8,9 +12,45 @@ pub struct If {
}
impl MersStatement for If {
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> {
if init_to.is_some() {
return Err(CheckError("can't init to statement type If".to_string()));
}
if !self
.condition
.check(info, None)?
.is_included_in(&data::bool::BoolT)
{
return Err(CheckError(format!(
"condition in an if-statement must return bool"
)));
}
let mut t = self.on_true.check(info, None)?;
if let Some(f) = &self.on_false {
t.add(Arc::new(f.check(info, None)?));
} else {
t.add(Arc::new(Type::empty_tuple()));
}
Ok(t)
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
self.condition.run(info);
todo!("what now?")
if let Some(data::bool::Bool(true)) = self
.condition
.run(info)
.get()
.as_any()
.downcast_ref::<data::bool::Bool>()
{
self.on_true.run(info)
} else if let Some(on_false) = &self.on_false {
on_false.run(info)
} else {
Data::empty_tuple()
}
}
fn has_scope(&self) -> bool {
true

View File

@@ -1,21 +0,0 @@
use crate::data::MersData;
use super::MersStatement;
#[derive(Debug)]
pub struct Loop {
pub inner: Box<dyn MersStatement>,
}
impl MersStatement for Loop {
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
loop {
if let Some(break_val) = self.inner.run(info).get().matches() {
break break_val;
}
}
}
fn has_scope(&self) -> bool {
true
}
}

View File

@@ -1,4 +1,7 @@
use std::sync::Arc;
use std::{
fmt::{Debug, Display},
sync::{Arc, Mutex},
};
use crate::{
data::{self, Data, Type},
@@ -16,21 +19,31 @@ pub mod function;
#[cfg(feature = "run")]
pub mod r#if;
#[cfg(feature = "run")]
pub mod r#loop;
#[cfg(feature = "run")]
pub mod switch;
#[cfg(feature = "run")]
pub mod tuple;
#[cfg(feature = "run")]
pub mod value;
#[cfg(feature = "run")]
pub mod variable;
pub trait MersStatement: std::fmt::Debug {
pub trait MersStatement: Debug + Send + Sync {
fn check_custom(
&self,
info: &mut CheckInfo,
init_to: Option<&Type>,
) -> Result<Type, CheckError>;
fn run_custom(&self, info: &mut Info) -> Data;
/// if true, local variables etc. will be contained inside their own scope.
fn has_scope(&self) -> bool;
// fn outputs(&self) -> Type;
fn check(&self, info: &mut CheckInfo, assign: Option<&Type>) -> Result<Type, CheckError> {
if self.has_scope() {
info.create_scope();
}
let o = self.check_custom(info, assign);
if self.has_scope() {
info.end_scope();
}
o
}
fn run(&self, info: &mut Info) -> Data {
if self.has_scope() {
info.create_scope();
@@ -43,18 +56,54 @@ pub trait MersStatement: std::fmt::Debug {
}
}
#[derive(Clone, Debug)]
pub struct CheckError(pub String);
impl Display for CheckError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
pub type Info = info::Info<Local>;
pub type CheckInfo = info::Info<CheckLocal>;
#[derive(Default, Clone, Debug)]
pub struct Local {
vars: Vec<Data>,
vars: Vec<Arc<Mutex<Data>>>,
}
#[derive(Default, Clone, Debug)]
pub struct CheckLocal {
vars: Vec<Type>,
}
impl info::Local for Local {
type VariableIdentifier = usize;
type VariableData = Data;
type VariableData = Arc<Mutex<Data>>;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
let nothing = Arc::new(Mutex::new(Data::new(data::bool::Bool(false))));
while self.vars.len() <= id {
self.vars.push(Data::new(data::bool::Bool(false)));
self.vars.push(Arc::clone(&nothing));
}
self.vars[id] = value;
}
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData> {
match self.vars.get(*id) {
Some(v) => Some(v),
None => None,
}
}
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData> {
match self.vars.get_mut(*id) {
Some(v) => Some(v),
None => None,
}
}
}
impl info::Local for CheckLocal {
type VariableIdentifier = usize;
type VariableData = Type;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
while self.vars.len() <= id {
self.vars.push(Type::empty());
}
self.vars[id] = value;
}

View File

@@ -1,23 +0,0 @@
use crate::data::Type;
use super::MersStatement;
#[derive(Debug)]
pub struct Switch {
source: Box<dyn MersStatement>,
arms: Vec<SwitchArm>,
}
#[derive(Debug)]
pub struct SwitchArm {
requires_type: Type,
}
impl MersStatement for Switch {
fn has_scope(&self) -> bool {
true
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
todo!("switch")
}
}

View File

@@ -1,12 +1,61 @@
use crate::data::{self, Data};
use std::sync::Arc;
use super::MersStatement;
use crate::data::{self, tuple::TupleT, Data, Type};
use super::{CheckError, MersStatement};
#[derive(Debug)]
pub struct Tuple {
pub elems: Vec<Box<dyn MersStatement>>,
}
impl MersStatement for Tuple {
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> {
let mut it = if let Some(init_to) = init_to {
let mut vec = (0..self.elems.len())
.map(|_| Type::empty())
.collect::<Vec<_>>();
for t in init_to.types.iter() {
if let Some(t) = t.as_any().downcast_ref::<TupleT>() {
if t.0.len() == self.elems.len() {
for (i, e) in t.0.iter().enumerate() {
vec[i].add(Arc::new(e.clone()));
}
} else {
return Err(CheckError(
format!("can't init to statement type Tuple with value type {t}, which is part of {init_to} - only tuples with the same length ({}) can be assigned to tuples", self.elems.len()),
));
}
} else {
return Err(CheckError(
"can't init to statement type Tuple with value type {t}, which is part of {init_to} - only tuples can be assigned to tuples".to_string(),
));
}
}
Some(vec)
} else {
None
};
Ok(Type::new(data::tuple::TupleT(
self.elems
.iter()
.map(|v| {
v.check(
info,
if let Some(it) = &mut it {
Some(it.pop().unwrap())
} else {
None
}
.as_ref(),
)
})
.collect::<Result<_, _>>()?,
)))
}
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
Data::new(data::tuple::Tuple(
self.elems.iter().map(|s| s.run(info)).collect(),

View File

@@ -1,6 +1,6 @@
use crate::data::{Data, MersData};
use crate::data::{Data, Type};
use super::MersStatement;
use super::{CheckError, MersStatement};
#[derive(Debug)]
pub struct Value {
@@ -11,7 +11,17 @@ impl MersStatement for Value {
fn has_scope(&self) -> bool {
false
}
fn run_custom(&self, info: &mut super::Info) -> Data {
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<crate::data::Type, super::CheckError> {
if init_to.is_some() {
return Err(CheckError("can't init to statement type Value".to_string()));
}
Ok(self.val.get().as_type())
}
fn run_custom(&self, _info: &mut super::Info) -> Data {
self.val.clone()
}
}

View File

@@ -1,9 +1,12 @@
use crate::data::{self, Data};
use std::sync::{Arc, Mutex};
use crate::data::{self, Data, Type};
use super::MersStatement;
#[derive(Debug)]
pub struct Variable {
pub is_init: bool,
pub is_ref: bool,
pub var: (usize, usize),
}
@@ -12,19 +15,44 @@ impl MersStatement for Variable {
fn has_scope(&self) -> bool {
false
}
fn run_custom(&self, info: &mut super::Info) -> Data {
while info.scopes[self.var.0].vars.len() <= self.var.1 {
info.scopes[self.var.0]
.vars
.push(Data::new(data::bool::Bool(false)));
fn check_custom(
&self,
info: &mut super::CheckInfo,
init_to: Option<&Type>,
) -> Result<data::Type, super::CheckError> {
if self.is_init {
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[self.var.1] = init_to
.expect("variable's is_init was true, but check_custom's assign was None? How?")
.clone();
}
if self.is_ref {
Data::new(data::reference::Reference(
Ok(if self.is_ref {
Type::new(data::reference::ReferenceT(
info.scopes[self.var.0].vars[self.var.1].clone(),
))
} else {
// Full-Clones!
Data::new_boxed(info.scopes[self.var.0].vars[self.var.1].get().clone())
info.scopes[self.var.0].vars[self.var.1].clone()
})
}
fn run_custom(&self, info: &mut super::Info) -> Data {
if self.is_init {
let nothing = Arc::new(Mutex::new(Data::new(data::bool::Bool(false))));
while info.scopes[self.var.0].vars.len() <= self.var.1 {
info.scopes[self.var.0].vars.push(Arc::clone(&nothing));
}
info.scopes[self.var.0].vars[self.var.1] = nothing;
}
if self.is_ref {
Data::new(data::reference::Reference(Arc::clone(
&info.scopes[self.var.0].vars[self.var.1],
)))
} else {
info.scopes[self.var.0].vars[self.var.1]
.lock()
.unwrap()
.clone()
}
}
}