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,12 +1,9 @@
# mers # mers
Mers is getting a rewrite! Mers is a high-level programming language.
It is designed to be safe (it doesn't crash at runtime) and as simple as possible.
This means that this README isn't complete, ## what makes it special
many things will change,
and the docs/ are for a completely different language.
## why mers?
### Simplicity ### Simplicity
@ -15,18 +12,21 @@ But this means that many things you may be familiar with simply don't exist in m
because they aren't actually needed. because they aren't actually needed.
This includes: This includes:
**Exceptions**, because errors in mers are values just like any other. **Exceptions**, because errors in mers are just values.
A function to read a UTF-8 text file from disk could have a return type like `String/IOError/UTF8DecodeError`, A function to read a UTF-8 text file from disk could have a return type like `String/IOError/UTF8DecodeError`,
which tells you exactly what errors can happen and also forces you to handle them (see later for mers' type-system). which tells you exactly what errors can happen and also forces you to handle them (see later for mers' type-system).
**Loops**, because, as it turns out, a function which takes an iterable and a function can do this just fine. **Loops**, because, as it turns out, a function which takes an iterable and a function can do this just fine:
```
my_list := (1, 2, 3, "four", "five", 6.5).as_list
(my_list, val -> val.println).for_each
```
Javascript has `forEach`, Rust `for_each`, C# `Each`, and Java has `forEach`. Javascript has `forEach`, Rust `for_each`, C# `Each`, and Java has `forEach`.
At first, it seemed stupid to have a function that does the same thing a `for` or `foreach` loop can already do, At first, it seemed stupid to have a function that does the same thing a `for` or `foreach` loop can already do,
but if a function can do the job, why do we even need a special language construct to do this for us? but if a function can do the job, why do we even need a special language construct to do this for us?
To keep it simple, mers doesn't have any loops except for `loop`. To keep it simple, mers doesn't have any loops - just functions you can use to loop.
`loop` simply repeats until the inner expression returns `(T)`, which causes loop to return `T`.
**Breaks** aren't necessary, since this can be achieved using iterator magic or by returning `(T)` in a `loop`. **Breaks** aren't necessary, since this can be achieved using iterators or by returning `(T)` in a `loop`.
It is also similar to `goto`, because it makes control flow less obvious, so it had to go. It is also similar to `goto`, because it makes control flow less obvious, so it had to go.
The same control flow obfuscation issue exists for **returns**, so these also aren't a thing. The same control flow obfuscation issue exists for **returns**, so these also aren't a thing.
@ -37,18 +37,41 @@ Why? Because we don't need anything else.
A function with no arguments now takes an empty tuple `()`, A function with no arguments now takes an empty tuple `()`,
a function with two arguments now takes a two-length tuple `(a, b)`, a function with two arguments now takes a two-length tuple `(a, b)`,
a function with either zero, one, or three arguments now takes a `()/(a)/(a, b, c)`, a function with either zero, one, or three arguments now takes a `()/(a)/(a, b, c)`,
and a function with n args takes a list, or a list as part of a tuple, or an optional list via `()/<the list>`. and a function with n arguments takes a list, or a list as part of a tuple, or an optional list via `()/<the list>`.
### Types ### Types and Safety
Mers is built around a type-system where a value could be one of multiple types. Mers is built around a type-system where a value could be one of multiple types.
This is basically what dynamic typing allows you to do: This is basically what dynamic typing allows you to do:
```
x := if condition { 12 } else { "something went wrong" } x := if condition { 12 } else { "something went wrong" }
```
This would be valid code. This would be valid code.
However, in mers, the compiler still tracks all the types in your program, However, in mers, the compiler still tracks all the types in your program,
and it will catch every possible crash before the program even runs: and it will catch every possible crash before the program even runs:
If we tried to use `x` as an Int, the compiler would complain since it might be a string. If we tried to use `x` as an int, the compiler would complain since it might be a string, so this does not compile:
```
list := (1, 2, if true 3 else "not an int")
list.sum.println
```
(note: type-checks aren't implemented since the rewrite is just barely functional, but they will be there and fully working soon) Type-safety for functions is different from what you might expect.
You don't need to tell mers what type your function's argument has - you just use it however you want as if mers was a dynamically typed language:
```
sum_doubled := iter -> {
one := iter.sum
(one, one).sum
}
(1, 2, 3).sum_doubled.println
```
We could try to use the function improperly by passing a string instead of an int:
```
(1, 2, "3").sum_doubled.println
```
But mers will catch this and show an error, because the call to `sum` inside of `sum_doubled` would fail.
(note: type-checks aren't implemented for all functions yet, you may need to use `--check no` to get around this and deal with runtime panics for now)
## docs
docs will be available some time. for now, check mers_lib/src/program/configs/*

0
mers/src/cfg_globals.rs Normal file → Executable file
View File

View File

@ -6,11 +6,14 @@ mod cfg_globals;
#[derive(Parser)] #[derive(Parser)]
struct Args { struct Args {
#[command(subcommand)]
command: Command,
/// controls availability of features when compiling/running /// controls availability of features when compiling/running
#[arg(long, value_enum, default_value_t = Configs::Std)] #[arg(long, value_enum, default_value_t = Configs::Std)]
config: Configs, config: Configs,
#[command(subcommand)] /// perform checks to avoid runtime crashes
command: Command, #[arg(long, default_value_t = Check::Yes)]
check: Check,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
enum Command { enum Command {
@ -20,6 +23,25 @@ enum Command {
Exec { source: String }, Exec { source: String },
} }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum Check {
No,
Yes,
Only,
}
impl Display for Check {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::No => "no",
Self::Yes => "yes",
Self::Only => "only",
}
)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum Configs { enum Configs {
None, None,
Base, Base,
@ -42,20 +64,39 @@ fn main() {
Configs::Base => Config::new().bundle_base(), Configs::Base => Config::new().bundle_base(),
Configs::Std => Config::new().bundle_std(), Configs::Std => Config::new().bundle_std(),
}); });
let (mut info1, mut info2) = config.infos(); let (mut info_parsed, mut info_run, mut info_check) = config.infos();
match args.command { let mut source = match args.command {
Command::Run { file } => { Command::Run { file } => {
let str = fs::read_to_string(file).unwrap(); let str = fs::read_to_string(file).unwrap();
let mut src = Source::new(str); Source::new(str)
let parsed = parse(&mut src).unwrap();
let run = parsed.compile(&mut info1, Default::default()).unwrap();
run.run(&mut info2);
} }
Command::Exec { source } => { Command::Exec { source } => Source::new(source),
let mut src = Source::new(source); };
let parsed = parse(&mut src).unwrap(); let parsed = parse(&mut source).unwrap();
let run = parsed.compile(&mut info1, Default::default()).unwrap(); #[cfg(debug_assertions)]
run.run(&mut info2); dbg!(&parsed);
let run = parsed
.compile(&mut info_parsed, Default::default())
.unwrap();
#[cfg(debug_assertions)]
dbg!(&run);
match args.check {
Check::No => {
run.run(&mut info_run);
}
Check::Yes | Check::Only => {
let rt = match run.check(&mut info_check, None) {
Ok(v) => v,
Err(e) => {
eprintln!("check failed: {e}");
std::process::exit(36);
}
};
if args.check == Check::Yes {
run.run(&mut info_run);
} else {
eprintln!("return type is {}", rt)
}
} }
} }
} }

View File

@ -1,27 +1 @@
list := ( ("a").{ (a) -> a }
1,
2,
3,
4,
5,
6,
7,
8,
9,
);
total := 0
(list item -> &total = (total, item).sum).iter
"total: ".print
total.println
"sum: ".print
list.sum.println
iter := (list item -> { item.println 12 }).map
"---".println
list := iter.as_list
list.println
list.sum.println
list.enumerate.as_list.println
"mers cli: ".print
mers_cli.println

28
mers/test2.mers Executable file
View File

@ -0,0 +1,28 @@
list := (
1,
2,
3,
4,
5,
6,
7,
8,
9,
);
total := 0
t := &total
(list, item -> t = (t.deref, item).sum).iter
"total: ".print
total.println
"sum: ".print
list.sum.println
iter := (list item -> { item.println 12 }).map
"---".println
list := iter.as_list
list.println
list.sum.println
list.enumerate.as_list.println
"mers cli: ".print
mers_cli.println

8
mers/test3.mers Executable file
View File

@ -0,0 +1,8 @@
values := ().as_list
counter := 0
counter_ref := &counter
{val -> {
counter_ref = (counter_ref.deref, 1).sum
counter_ref.deref.println
if (counter_ref.deref, 5).eq { (()) } else { () }
}}.loop

View File

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

View File

@ -1,5 +1,10 @@
# mers documentation # 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 ## parsing
syntax: syntax:

View File

@ -1,14 +1,24 @@
use std::{any::Any, fmt::Display}; use std::{any::Any, fmt::Display};
use super::{MersData, MersType}; use super::{MersData, MersType, Type};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Bool(pub bool); pub struct Bool(pub bool);
impl MersData for 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> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) Box::new(Clone::clone(self))
} }
fn as_type(&self) -> super::Type {
Type::new(BoolT)
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
@ -45,3 +55,8 @@ impl Display for Bool {
write!(f, "{}", self.0) 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) { pub fn assign(from: Data, target: &Data) {
let mut target = target.get_mut(); let target = target.get();
if let Some(r) = target if let Some(r) = target
.mut_any() .as_any()
.downcast_mut::<crate::data::reference::Reference>() .downcast_ref::<crate::data::reference::Reference>()
{ {
*r.0.get_mut() = from.get().clone(); *r.0.lock().unwrap().get_mut() = from.get().clone();
} else { } else {
todo!("assignment to non-reference") todo!("assignment to non-reference")
} }

View File

@ -6,9 +6,19 @@ use super::{MersData, MersType, Type};
pub struct Float(pub f64); pub struct Float(pub f64);
impl MersData for Float { 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> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) Box::new(Clone::clone(self))
} }
fn as_type(&self) -> super::Type {
Type::new(FloatT)
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
@ -45,3 +55,8 @@ impl Display for Float {
write!(f, "{}", self.0) 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::{ use std::{
any::Any, any::Any,
fmt::{Debug, Display}, 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}; use super::{Data, MersData, MersType, Type};
#[derive(Clone)] #[derive(Clone)]
pub struct Function { pub struct Function {
pub info: Info, pub info: Arc<Info>,
pub out: Arc<dyn Fn(&Type) -> Option<Type>>, pub info_check: Arc<Mutex<CheckInfo>>,
pub run: Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Data>, 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 { impl Function {
pub fn with_info(&self, info: program::run::Info) -> Self { pub fn with_info_run(&self, info: Arc<Info>) -> Self {
Self { Self {
info, info,
info_check: Arc::clone(&self.info_check),
out: Arc::clone(&self.out), out: Arc::clone(&self.out),
run: Arc::clone(&self.run), 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 { 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 { impl MersData for Function {
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
fn clone(&self) -> Box<dyn MersData> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) 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 { fn as_any(&self) -> &dyn Any {
self 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 { impl MersType for FunctionT {
fn is_same_type_as(&self, _other: &dyn MersType) -> bool { fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
false false
@ -77,3 +98,8 @@ impl Display for Function {
write!(f, "<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); pub struct Int(pub isize);
impl MersData for Int { 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> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) Box::new(Clone::clone(self))
} }
fn as_type(&self) -> super::Type {
Type::new(IntT)
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
@ -45,3 +55,8 @@ impl Display for Int {
write!(f, "{}", self.0) 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::{ use std::{
any::Any, any::Any,
fmt::{Debug, Display}, fmt::{Debug, Display},
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
}; };
pub mod bool; pub mod bool;
@ -14,10 +14,7 @@ pub mod tuple;
pub mod defs; pub mod defs;
pub trait MersData: Any + Debug + Display { pub trait MersData: Any + Debug + Display + Send + Sync {
fn matches(&self) -> Option<Data> {
None
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> { fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
None None
} }
@ -26,18 +23,17 @@ pub trait MersData: Any + Debug + Display {
fn get(&self, i: usize) -> Option<Data> { fn get(&self, i: usize) -> Option<Data> {
self.iterable()?.nth(i) 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 clone(&self) -> Box<dyn MersData>;
fn as_type(&self) -> Type;
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any; fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>; fn to_any(self) -> Box<dyn Any>;
} }
pub trait MersType: Any + Debug { pub trait MersType: Any + Debug + Display + Send + Sync {
/// 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
}
/// If Some(T), calling `iterable` on the MersData this MersType belongs to /// 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. /// Should return Some(I), where I is an Iterator which only returns items of type T.
fn iterable(&self) -> Option<Type> { fn iterable(&self) -> Option<Type> {
@ -66,18 +62,28 @@ pub trait MersType: Any + Debug {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any; fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>; fn to_any(self) -> Box<dyn Any>;
fn is_reference_to(&self) -> Option<&Type> {
None
}
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Data { pub struct Data {
is_mut: bool,
counts: Arc<(AtomicUsize, AtomicUsize)>,
pub data: Arc<RwLock<Box<dyn MersData>>>, pub data: Arc<RwLock<Box<dyn MersData>>>,
} }
impl Data { impl Data {
pub fn new<T: MersData>(data: T) -> Self { 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 { 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)), data: Arc::new(RwLock::new(data)),
} }
} }
@ -87,27 +93,116 @@ impl Data {
pub fn one_tuple(v: Self) -> Self { pub fn one_tuple(v: Self) -> Self {
Self::new(tuple::Tuple(vec![v])) 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>> { pub fn get(&self) -> RwLockReadGuard<Box<dyn MersData>> {
#[cfg(debug_assertions)]
eprintln!("[mers:data:cow] get");
self.data.read().unwrap() 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() 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 { impl Clone for Data {
fn clone(&self) -> Self { fn clone(&self) -> Self {
// todo!("clone for data - requires CoW"); self.counts
.0
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Self { Self {
is_mut: false,
counts: Arc::clone(&self.counts),
data: Arc::clone(&self.data), 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)] #[derive(Clone, Debug)]
pub struct Type { pub struct Type {
// TODO: Maybe make sure this is always sorted by (recursive?!?) TypeId, // 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) // 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 { impl Type {
pub fn new<T: MersType>(t: T) -> Self { pub fn new<T: MersType>(t: T) -> Self {
@ -118,11 +213,64 @@ impl Type {
pub fn newm(types: Vec<Arc<dyn MersType>>) -> Self { pub fn newm(types: Vec<Arc<dyn MersType>>) -> Self {
Self { types } Self { types }
} }
pub fn empty() -> Self {
Self { types: vec![] }
}
pub fn empty_tuple() -> Self { pub fn empty_tuple() -> Self {
Self::new(tuple::TupleT(vec![])) Self::new(tuple::TupleT(vec![]))
} }
pub fn add<T: MersType>(&mut self, new: Box<T>) { /// Returns true if self is `()`.
todo!() 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!() todo!()
} }
fn is_included_in_single(&self, target: &dyn MersType) -> bool { 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 { fn as_any(&self) -> &dyn Any {
self self
@ -152,4 +300,45 @@ impl MersType for Type {
fn to_any(self) -> Box<dyn Any> { fn to_any(self) -> Box<dyn Any> {
Box::new(self) 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}; use super::{Data, MersData, MersType, Type};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Reference(pub Data); pub struct Reference(pub Arc<Mutex<Data>>);
impl MersData for Reference { 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> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) 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 { fn as_any(&self) -> &dyn Any {
self self
} }
@ -31,6 +45,7 @@ impl MersType for ReferenceT {
} }
} }
fn is_included_in_single(&self, target: &dyn MersType) -> bool { 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) self.is_same_type_as(target)
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -42,10 +57,18 @@ impl MersType for ReferenceT {
fn to_any(self) -> Box<dyn Any> { fn to_any(self) -> Box<dyn Any> {
Box::new(self) Box::new(self)
} }
fn is_reference_to(&self) -> Option<&Type> {
Some(&self.0)
}
} }
impl Display for Reference { impl Display for Reference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "&{}", self.0.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); pub struct String(pub std::string::String);
impl MersData for 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> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) Box::new(Clone::clone(self))
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
fn as_type(&self) -> super::Type {
Type::new(StringT)
}
fn mut_any(&mut self) -> &mut dyn Any { fn mut_any(&mut self) -> &mut dyn Any {
self self
} }
@ -45,3 +55,8 @@ impl Display for String {
write!(f, "{}", self.0) 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}; use super::{Data, MersData, MersType, Type};
@ -15,15 +15,11 @@ impl Tuple {
} }
impl MersData for Tuple { impl MersData for Tuple {
fn matches(&self) -> Option<Data> { fn is_eq(&self, other: &dyn MersData) -> bool {
if let Some(d) = self.0.first() { if let Some(other) = other.as_any().downcast_ref::<Self>() {
if self.0.len() == 1 { other.0 == self.0
Some(d.clone())
} else {
None
}
} else { } else {
None false
} }
} }
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> { fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
@ -32,6 +28,9 @@ impl MersData for Tuple {
fn clone(&self) -> Box<dyn MersData> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) 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 { fn as_any(&self) -> &dyn Any {
self self
} }
@ -46,19 +45,12 @@ impl MersData for Tuple {
#[derive(Debug)] #[derive(Debug)]
pub struct TupleT(pub Vec<Type>); pub struct TupleT(pub Vec<Type>);
impl MersType for TupleT { 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> { 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 { fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some() other.as_any().downcast_ref::<Self>().is_some()
@ -90,3 +82,16 @@ impl Display for Tuple {
Ok(()) 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 std::sync::Arc;
use crate::{ use crate::program;
info::Info,
program::{self, parsed::CompInfo},
};
pub mod errors; pub mod errors;
pub mod statements; pub mod statements;
@ -96,7 +93,7 @@ impl Source {
/// Useful for debugging the parser. /// Useful for debugging the parser.
pub fn section_begin(&mut self, section: String) -> Arc<String> { pub fn section_begin(&mut self, section: String) -> Arc<String> {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("Section begin: {}", &section); println!("[mers:parse] Section begin: {}", &section);
let arc = Arc::new(section); let arc = Arc::new(section);
self.sections.push(SectionMarker { self.sections.push(SectionMarker {
section: Arc::clone(&arc), section: Arc::clone(&arc),
@ -141,7 +138,7 @@ impl SectionMarker {
if Arc::strong_count(&self.section) == 1 { if Arc::strong_count(&self.section) == 1 {
self.end = Some(end); self.end = Some(end);
#[cfg(debug_assertions)] #[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 super::Source;
use crate::{ use crate::{
data::{self, Data}, data::Data,
program::{self, parsed::MersStatement}, 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" => { "switch" => {
src.section_begin("loop".to_string()); src.section_begin("loop".to_string());
todo!() todo!()

View File

@ -1,17 +1,18 @@
use std::sync::Arc; use std::sync::{Arc, Mutex};
use crate::{ use crate::{
data::{self, Data, Type}, data::{Data, Type},
info::Local, info::Local,
program,
}; };
mod with_base;
mod with_command_running; mod with_command_running;
mod with_get; mod with_get;
mod with_iters; mod with_iters;
mod with_list; mod with_list;
mod with_math; 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() /// 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) /// bundle_* for bundles (combines multiple groups or even bundles)
@ -27,23 +28,30 @@ pub struct Config {
globals: usize, globals: usize,
info_parsed: super::parsed::Info, info_parsed: super::parsed::Info,
info_run: super::run::Info, info_run: super::run::Info,
info_check: super::run::CheckInfo,
} }
impl Config { impl Config {
/// standard utilitis used in many programs /// standard utilitis used in many programs
/// `bundle_base()` /// `bundle_base()`
/// `with_stdio()`
/// `with_list()` /// `with_list()`
/// `with_command_running()` /// `with_command_running()`
/// `with_multithreading()`
pub fn bundle_std(self) -> Self { 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 /// base utilities used in most programs
/// `with_prints()` /// `with_base()`
/// `with_math()` /// `with_math()`
/// `with_get()` /// `with_get()`
/// `with_iters()` /// `with_iters()`
pub fn bundle_base(self) -> Self { 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 { pub fn new() -> Self {
@ -51,12 +59,15 @@ impl Config {
globals: 0, globals: 0,
info_parsed: Default::default(), info_parsed: Default::default(),
info_run: Default::default(), info_run: Default::default(),
info_check: Default::default(),
} }
} }
pub fn add_var(mut self, name: String, val: Data) -> Self { 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_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.globals += 1;
self self
} }
@ -65,7 +76,7 @@ impl Config {
self self
} }
pub fn infos(self) -> (super::parsed::Info, super::run::Info) { pub fn infos(self) -> (super::parsed::Info, super::run::Info, super::run::CheckInfo) {
(self.info_parsed, self.info_run) (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::{ use crate::{
data::{self, Data, MersData, MersType}, data::{self, Data, MersData, MersType, Type},
program, program::{self, run::CheckInfo},
}; };
use super::Config; use super::Config;
@ -16,8 +20,9 @@ impl Config {
self.add_var( self.add_var(
"run_command".to_string(), "run_command".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), info_check: Arc::new(Mutex::new( CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| { run: Arc::new(|a, _i| {
if let Some(cmd) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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)) { if let (Some(cmd), Some(args)) = (cmd.get(0), cmd.get(1)) {
@ -67,9 +72,19 @@ pub struct RunCommandError(String);
#[derive(Debug)] #[derive(Debug)]
pub struct RunCommandErrorT; pub struct RunCommandErrorT;
impl MersData for RunCommandError { 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> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) Box::new(Clone::clone(self))
} }
fn as_type(&self) -> data::Type {
Type::new(RunCommandErrorT)
}
fn as_any(&self) -> &dyn std::any::Any { fn as_any(&self) -> &dyn std::any::Any {
self self
} }
@ -102,3 +117,8 @@ impl Display for RunCommandError {
write!(f, "RunCommandError: {}", self.0) 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::{ use crate::{
data::{self, Data}, data::{self, Data, MersType},
program, program::{self, run::CheckInfo},
}; };
use super::Config; use super::Config;
@ -13,8 +13,17 @@ impl Config {
self.add_var( self.add_var(
"get".to_string(), "get".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), 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| { run: Arc::new(|a, _i| {
let a = a.get(); let a = a.get();
if let (Some(v), Some(i)) = (a.get(0), a.get(1)) { 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::{ use crate::{
data::{self, Data, MersData}, data::{self, Data, MersData, MersType, Type},
program, program::{
self,
run::{CheckError, CheckInfo},
},
}; };
use super::Config; use super::Config;
@ -12,14 +18,51 @@ impl Config {
/// `iter: fn` executes a function once for each element of the iterable /// `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 /// `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: 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 /// `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 { pub fn with_iters(self) -> Self {
self.add_var( self.add_var(
"iter".to_string(), "for_each".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), 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| { run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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)) { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -33,14 +76,14 @@ impl Config {
Data::empty_tuple() Data::empty_tuple()
} else { } else {
unreachable!( unreachable!(
"iter called on tuple not containing iterable and function" "for_each called on tuple not containing iterable and function"
) )
} }
} else { } else {
unreachable!("iter called on tuple with len < 2") unreachable!("for_each called on tuple with len < 2")
} }
} else { } else {
unreachable!("iter called on non-tuple") unreachable!("for_each called on non-tuple")
} }
}), }),
}), }),
@ -48,8 +91,9 @@ impl Config {
.add_var( .add_var(
"map".to_string(), "map".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| { run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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)) { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -72,8 +116,9 @@ impl Config {
.add_var( .add_var(
"filter".to_string(), "filter".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| { run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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)) { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -96,8 +141,9 @@ impl Config {
.add_var( .add_var(
"filter_map".to_string(), "filter_map".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, i| todo!()),
run: Arc::new(|a, _i| { run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() { 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)) { if let (Some(v), Some(f)) = (tuple.get(0), tuple.get(1)) {
@ -120,8 +166,9 @@ impl Config {
.add_var( .add_var(
"enumerate".to_string(), "enumerate".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), 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()))), run: Arc::new(|a, _i| Data::new(Iter(Iters::Enumerate, a.clone()))),
}), }),
) )
@ -140,6 +187,9 @@ pub struct Iter(Iters, Data);
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IterT(Iters); pub struct IterT(Iters);
impl MersData for Iter { impl MersData for Iter {
fn is_eq(&self, _other: &dyn MersData) -> bool {
false
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> { fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
Some(match &self.0 { Some(match &self.0 {
Iters::Map(f) => { Iters::Map(f) => {
@ -162,7 +212,7 @@ impl MersData for Iter {
self.1 self.1
.get() .get()
.iterable()? .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)| { Iters::Enumerate => Box::new(self.1.get().iterable()?.enumerate().map(|(i, v)| {
@ -171,12 +221,36 @@ impl MersData for Iter {
v, v,
])) ]))
})), })),
_ => todo!(),
}) })
} }
fn clone(&self) -> Box<dyn MersData> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) 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 { fn as_any(&self) -> &dyn std::any::Any {
self self
} }
@ -192,3 +266,8 @@ impl Display for Iter {
write!(f, "<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::{ use crate::{
data::{self, Data, MersData, MersType, Type}, data::{self, Data, MersData, MersType, Type},
program, program::{self, run::CheckInfo},
}; };
use super::Config; use super::Config;
@ -17,8 +20,17 @@ impl Config {
.add_var( .add_var(
"as_list".to_string(), "as_list".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), 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| { run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() { if let Some(i) = a.get().iterable() {
Data::new(List(i.collect())) Data::new(List(i.collect()))
@ -36,12 +48,26 @@ pub struct List(Vec<Data>);
#[derive(Debug)] #[derive(Debug)]
pub struct ListT(Type); pub struct ListT(Type);
impl MersData for List { 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>>> { fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
Some(Box::new(self.0.clone().into_iter())) Some(Box::new(self.0.clone().into_iter()))
} }
fn clone(&self) -> Box<dyn MersData> { fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self)) 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 { fn as_any(&self) -> &dyn std::any::Any {
self self
} }
@ -88,3 +114,9 @@ impl Display for List {
Ok(()) 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::{ use crate::{
data::{self, Data}, data::{self, Data, Type},
program, program::{
self,
run::{CheckError, CheckInfo},
},
}; };
use super::Config; use super::Config;
@ -13,8 +16,38 @@ impl Config {
self.add_var( self.add_var(
"sum".to_string(), "sum".to_string(),
Data::new(data::function::Function { Data::new(data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_a| todo!()), 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| { run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() { if let Some(i) = a.get().iterable() {
let mut sumi = 0; 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}; use super::{CompInfo, MersStatement};
@ -15,9 +15,10 @@ impl MersStatement for AssignTo {
fn compile_custom( fn compile_custom(
&self, &self,
info: &mut crate::info::Info<super::Local>, info: &mut crate::info::Info<super::Local>,
mut comp: CompInfo, comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> { ) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::assign_to::AssignTo { Ok(Box::new(program::run::assign_to::AssignTo {
is_init: false,
target: self.target.compile(info, comp)?, target: self.target.compile(info, comp)?,
source: self.source.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::{ use crate::{
data::{self, Data}, data,
info::Local, program::{self, run::CheckInfo},
program,
}; };
use super::{CompInfo, MersStatement}; use super::{CompInfo, MersStatement};
@ -17,7 +16,7 @@ pub struct Function {
impl MersStatement for Function { impl MersStatement for Function {
fn has_scope(&self) -> bool { fn has_scope(&self) -> bool {
// TODO: what??? // TODO: what???
false true
} }
fn compile_custom( fn compile_custom(
&self, &self,
@ -25,15 +24,21 @@ impl MersStatement for Function {
mut comp: CompInfo, mut comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> { ) -> Result<Box<dyn program::run::MersStatement>, String> {
comp.is_init = true; 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; 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 { Ok(Box::new(program::run::function::Function {
func_no_info: data::function::Function { func_no_info: data::function::Function {
info: program::run::Info::neverused(), info: Arc::new(program::run::Info::neverused()),
out: Arc::new(|_i| todo!()), info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
run: Arc::new(move |i, info| { out: Arc::new(move |a, i| {
data::defs::assign(i, &arg.run(info)); 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) run.run(info)
}), }),
}, },

View File

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

View File

@ -1,4 +1,4 @@
use crate::{info::Local, program}; use crate::program;
use super::{CompInfo, MersStatement}; use super::{CompInfo, MersStatement};
@ -22,6 +22,7 @@ impl MersStatement for InitTo {
comp.is_init = false; comp.is_init = false;
let source = self.source.compile(info, comp)?; let source = self.source.compile(info, comp)?;
Ok(Box::new(program::run::assign_to::AssignTo { Ok(Box::new(program::run::assign_to::AssignTo {
is_init: true,
target, target,
source, 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")] #[cfg(feature = "parse")]
pub mod init_to; pub mod init_to;
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
pub mod r#loop;
#[cfg(feature = "parse")]
pub mod switch;
#[cfg(feature = "parse")]
pub mod tuple; pub mod tuple;
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
pub mod value; pub mod value;
#[cfg(feature = "parse")] #[cfg(feature = "parse")]
pub mod variable; pub mod variable;
pub trait MersStatement: Debug { pub trait MersStatement: Debug + Send + Sync {
fn has_scope(&self) -> bool; fn has_scope(&self) -> bool;
fn compile_custom( fn compile_custom(
&self, &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( fn compile_custom(
&self, &self,
info: &mut crate::info::Info<super::Local>, _info: &mut crate::info::Info<super::Local>,
comp: CompInfo, _comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> { ) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::value::Value { Ok(Box::new(program::run::value::Value {
val: self.0.clone(), val: self.0.clone(),

View File

@ -27,6 +27,7 @@ impl MersStatement for Variable {
) )
} }
Ok(Box::new(program::run::variable::Variable { Ok(Box::new(program::run::variable::Variable {
is_init: comp.is_init,
is_ref: comp.is_init || self.is_ref, is_ref: comp.is_init || self.is_ref,
var: if let Some(v) = info.get_var(&self.var) { var: if let Some(v) = info.get_var(&self.var) {
*v *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)] #[derive(Debug)]
pub struct AssignTo { pub struct AssignTo {
pub is_init: bool,
pub target: Box<dyn MersStatement>, pub target: Box<dyn MersStatement>,
pub source: Box<dyn MersStatement>, pub source: Box<dyn MersStatement>,
} }
impl MersStatement for AssignTo { 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 { fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
let source = self.source.run(info); let source = self.source.run(info);
let target = self.target.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)] #[derive(Debug)]
pub struct Block { pub struct Block {
pub statements: Vec<Box<dyn MersStatement>>, pub statements: Vec<Box<dyn MersStatement>>,
} }
impl MersStatement for Block { 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 { fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
self.statements self.statements
.iter() .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)] #[derive(Debug)]
pub struct Chain { pub struct Chain {
@ -10,6 +10,37 @@ pub struct Chain {
pub chained: Box<dyn MersStatement>, pub chained: Box<dyn MersStatement>,
} }
impl MersStatement for Chain { 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 { fn run_custom(&self, info: &mut super::Info) -> Data {
let f = self.first.run(info); let f = self.first.run(info);
let c = self.chained.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)] #[derive(Debug)]
pub struct Function { pub struct Function {
@ -8,10 +10,23 @@ pub struct Function {
} }
impl MersStatement for Function { impl MersStatement for Function {
fn has_scope(&self) -> bool { fn check_custom(
false &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 { 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)] #[derive(Debug)]
pub struct If { pub struct If {
@ -8,9 +12,45 @@ pub struct If {
} }
impl MersStatement for 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 { fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
self.condition.run(info); if let Some(data::bool::Bool(true)) = self
todo!("what now?") .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 { fn has_scope(&self) -> bool {
true 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::{ use crate::{
data::{self, Data, Type}, data::{self, Data, Type},
@ -16,21 +19,31 @@ pub mod function;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod r#if; pub mod r#if;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod r#loop;
#[cfg(feature = "run")]
pub mod switch;
#[cfg(feature = "run")]
pub mod tuple; pub mod tuple;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod value; pub mod value;
#[cfg(feature = "run")] #[cfg(feature = "run")]
pub mod variable; 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; fn run_custom(&self, info: &mut Info) -> Data;
/// if true, local variables etc. will be contained inside their own scope. /// if true, local variables etc. will be contained inside their own scope.
fn has_scope(&self) -> bool; 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 { fn run(&self, info: &mut Info) -> Data {
if self.has_scope() { if self.has_scope() {
info.create_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 Info = info::Info<Local>;
pub type CheckInfo = info::Info<CheckLocal>;
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
pub struct Local { 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 { impl info::Local for Local {
type VariableIdentifier = usize; type VariableIdentifier = usize;
type VariableData = Data; type VariableData = Arc<Mutex<Data>>;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) { fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
let nothing = Arc::new(Mutex::new(Data::new(data::bool::Bool(false))));
while self.vars.len() <= id { 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; 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)] #[derive(Debug)]
pub struct Tuple { pub struct Tuple {
pub elems: Vec<Box<dyn MersStatement>>, pub elems: Vec<Box<dyn MersStatement>>,
} }
impl MersStatement for Tuple { 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 { fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
Data::new(data::tuple::Tuple( Data::new(data::tuple::Tuple(
self.elems.iter().map(|s| s.run(info)).collect(), 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)] #[derive(Debug)]
pub struct Value { pub struct Value {
@ -11,7 +11,17 @@ impl MersStatement for Value {
fn has_scope(&self) -> bool { fn has_scope(&self) -> bool {
false 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() 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; use super::MersStatement;
#[derive(Debug)] #[derive(Debug)]
pub struct Variable { pub struct Variable {
pub is_init: bool,
pub is_ref: bool, pub is_ref: bool,
pub var: (usize, usize), pub var: (usize, usize),
} }
@ -12,19 +15,44 @@ impl MersStatement for Variable {
fn has_scope(&self) -> bool { fn has_scope(&self) -> bool {
false false
} }
fn run_custom(&self, info: &mut super::Info) -> Data { fn check_custom(
while info.scopes[self.var.0].vars.len() <= self.var.1 { &self,
info.scopes[self.var.0] info: &mut super::CheckInfo,
.vars init_to: Option<&Type>,
.push(Data::new(data::bool::Bool(false))); ) -> 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 { Ok(if self.is_ref {
Data::new(data::reference::Reference( Type::new(data::reference::ReferenceT(
info.scopes[self.var.0].vars[self.var.1].clone(), info.scopes[self.var.0].vars[self.var.1].clone(),
)) ))
} else { } else {
// Full-Clones! info.scopes[self.var.0].vars[self.var.1].clone()
Data::new_boxed(info.scopes[self.var.0].vars[self.var.1].get().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()
} }
} }
} }