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

@@ -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()
}
}
}