mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
mers rewrite is starting to be usable
This commit is contained in:
parent
e549b1a5be
commit
2a7cb08596
59
README.md
59
README.md
@ -1,12 +1,9 @@
|
||||
# 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,
|
||||
many things will change,
|
||||
and the docs/ are for a completely different language.
|
||||
|
||||
## why mers?
|
||||
## what makes it special
|
||||
|
||||
### 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.
|
||||
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`,
|
||||
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`.
|
||||
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?
|
||||
To keep it simple, mers doesn't have any loops except for `loop`.
|
||||
`loop` simply repeats until the inner expression returns `(T)`, which causes loop to return `T`.
|
||||
To keep it simple, mers doesn't have any loops - just functions you can use to loop.
|
||||
|
||||
**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.
|
||||
|
||||
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 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)`,
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
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
0
mers/src/cfg_globals.rs
Normal file → Executable file
@ -6,11 +6,14 @@ mod cfg_globals;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
/// controls availability of features when compiling/running
|
||||
#[arg(long, value_enum, default_value_t = Configs::Std)]
|
||||
config: Configs,
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
/// perform checks to avoid runtime crashes
|
||||
#[arg(long, default_value_t = Check::Yes)]
|
||||
check: Check,
|
||||
}
|
||||
#[derive(Subcommand)]
|
||||
enum Command {
|
||||
@ -20,6 +23,25 @@ enum Command {
|
||||
Exec { source: String },
|
||||
}
|
||||
#[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 {
|
||||
None,
|
||||
Base,
|
||||
@ -42,20 +64,39 @@ fn main() {
|
||||
Configs::Base => Config::new().bundle_base(),
|
||||
Configs::Std => Config::new().bundle_std(),
|
||||
});
|
||||
let (mut info1, mut info2) = config.infos();
|
||||
match args.command {
|
||||
let (mut info_parsed, mut info_run, mut info_check) = config.infos();
|
||||
let mut source = match args.command {
|
||||
Command::Run { file } => {
|
||||
let str = fs::read_to_string(file).unwrap();
|
||||
let mut src = Source::new(str);
|
||||
let parsed = parse(&mut src).unwrap();
|
||||
let run = parsed.compile(&mut info1, Default::default()).unwrap();
|
||||
run.run(&mut info2);
|
||||
Source::new(str)
|
||||
}
|
||||
Command::Exec { source } => {
|
||||
let mut src = Source::new(source);
|
||||
let parsed = parse(&mut src).unwrap();
|
||||
let run = parsed.compile(&mut info1, Default::default()).unwrap();
|
||||
run.run(&mut info2);
|
||||
Command::Exec { source } => Source::new(source),
|
||||
};
|
||||
let parsed = parse(&mut source).unwrap();
|
||||
#[cfg(debug_assertions)]
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1 @@
|
||||
list := (
|
||||
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
|
||||
("a").{ (a) -> a }
|
||||
|
28
mers/test2.mers
Executable file
28
mers/test2.mers
Executable 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
8
mers/test3.mers
Executable 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
|
@ -5,6 +5,6 @@ edition = "2021"
|
||||
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["parse"]
|
||||
parse = ["run"]
|
||||
run = []
|
||||
|
@ -1,5 +1,10 @@
|
||||
# mers documentation
|
||||
|
||||
## ISSUES
|
||||
|
||||
when storing a reference, then reinitializing a variable of the same name, the reference may get the new value although
|
||||
it would be expected for it to be a reference to the value before it was reinitialized.
|
||||
|
||||
## parsing
|
||||
|
||||
syntax:
|
||||
|
@ -1,14 +1,24 @@
|
||||
use std::{any::Any, fmt::Display};
|
||||
|
||||
use super::{MersData, MersType};
|
||||
use super::{MersData, MersType, Type};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Bool(pub bool);
|
||||
|
||||
impl MersData for Bool {
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
other.0 == self.0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_type(&self) -> super::Type {
|
||||
Type::new(BoolT)
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -45,3 +55,8 @@ impl Display for Bool {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl Display for BoolT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Bool")
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
use super::Data;
|
||||
use crate::program::run::CheckError;
|
||||
|
||||
use super::{Data, MersType, Type};
|
||||
|
||||
pub fn assign(from: Data, target: &Data) {
|
||||
let mut target = target.get_mut();
|
||||
let target = target.get();
|
||||
if let Some(r) = target
|
||||
.mut_any()
|
||||
.downcast_mut::<crate::data::reference::Reference>()
|
||||
.as_any()
|
||||
.downcast_ref::<crate::data::reference::Reference>()
|
||||
{
|
||||
*r.0.get_mut() = from.get().clone();
|
||||
*r.0.lock().unwrap().get_mut() = from.get().clone();
|
||||
} else {
|
||||
todo!("assignment to non-reference")
|
||||
}
|
||||
|
@ -6,9 +6,19 @@ use super::{MersData, MersType, Type};
|
||||
pub struct Float(pub f64);
|
||||
|
||||
impl MersData for Float {
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
other.0 == self.0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_type(&self) -> super::Type {
|
||||
Type::new(FloatT)
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -45,3 +55,8 @@ impl Display for Float {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl Display for FloatT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Float")
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,57 @@
|
||||
use std::{
|
||||
any::Any,
|
||||
fmt::{Debug, Display},
|
||||
sync::Arc,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use crate::program::{self, run::Info};
|
||||
use crate::program::{
|
||||
self,
|
||||
run::{CheckError, CheckInfo, Info},
|
||||
};
|
||||
|
||||
use super::{Data, MersData, MersType, Type};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Function {
|
||||
pub info: Info,
|
||||
pub out: Arc<dyn Fn(&Type) -> Option<Type>>,
|
||||
pub run: Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Data>,
|
||||
pub info: Arc<Info>,
|
||||
pub info_check: Arc<Mutex<CheckInfo>>,
|
||||
pub out: Arc<dyn Fn(&Type, &mut CheckInfo) -> Result<Type, CheckError> + Send + Sync>,
|
||||
pub run: Arc<dyn Fn(Data, &mut crate::program::run::Info) -> Data + Send + Sync>,
|
||||
}
|
||||
impl Function {
|
||||
pub fn with_info(&self, info: program::run::Info) -> Self {
|
||||
pub fn with_info_run(&self, info: Arc<Info>) -> Self {
|
||||
Self {
|
||||
info,
|
||||
info_check: Arc::clone(&self.info_check),
|
||||
out: Arc::clone(&self.out),
|
||||
run: Arc::clone(&self.run),
|
||||
}
|
||||
}
|
||||
pub fn with_info_check(&self, check: CheckInfo) {
|
||||
*self.info_check.lock().unwrap() = check;
|
||||
}
|
||||
pub fn check(&self, arg: &Type) -> Result<Type, CheckError> {
|
||||
(self.out)(arg, &mut self.info_check.lock().unwrap().clone())
|
||||
}
|
||||
pub fn run(&self, arg: Data) -> Data {
|
||||
(self.run)(arg, &mut self.info.clone())
|
||||
(self.run)(arg, &mut self.info.as_ref().clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl MersData for Function {
|
||||
fn is_eq(&self, _other: &dyn MersData) -> bool {
|
||||
false
|
||||
}
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_type(&self) -> Type {
|
||||
let out = Arc::clone(&self.out);
|
||||
let info = Arc::clone(&self.info_check);
|
||||
Type::new(FunctionT(Arc::new(move |a| {
|
||||
out(a, &mut info.lock().unwrap().clone())
|
||||
})))
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -42,7 +63,7 @@ impl MersData for Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionT(Arc<dyn Fn(&Type) -> Option<Type>>);
|
||||
pub struct FunctionT(pub Arc<dyn Fn(&Type) -> Result<Type, CheckError> + Send + Sync>);
|
||||
impl MersType for FunctionT {
|
||||
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
|
||||
false
|
||||
@ -77,3 +98,8 @@ impl Display for Function {
|
||||
write!(f, "<function>")
|
||||
}
|
||||
}
|
||||
impl Display for FunctionT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Function")
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,19 @@ use super::{MersData, MersType, Type};
|
||||
pub struct Int(pub isize);
|
||||
|
||||
impl MersData for Int {
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
other.0 == self.0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_type(&self) -> super::Type {
|
||||
Type::new(IntT)
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -45,3 +55,8 @@ impl Display for Int {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl Display for IntT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Int")
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
any::Any,
|
||||
fmt::{Debug, Display},
|
||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
sync::{atomic::AtomicUsize, Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
};
|
||||
|
||||
pub mod bool;
|
||||
@ -14,10 +14,7 @@ pub mod tuple;
|
||||
|
||||
pub mod defs;
|
||||
|
||||
pub trait MersData: Any + Debug + Display {
|
||||
fn matches(&self) -> Option<Data> {
|
||||
None
|
||||
}
|
||||
pub trait MersData: Any + Debug + Display + Send + Sync {
|
||||
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
|
||||
None
|
||||
}
|
||||
@ -26,18 +23,17 @@ pub trait MersData: Any + Debug + Display {
|
||||
fn get(&self, i: usize) -> Option<Data> {
|
||||
self.iterable()?.nth(i)
|
||||
}
|
||||
/// If self and other are different types (`other.as_any().downcast_ref::<Self>().is_none()`),
|
||||
/// this *must* return false.
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool;
|
||||
fn clone(&self) -> Box<dyn MersData>;
|
||||
fn as_type(&self) -> Type;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn mut_any(&mut self) -> &mut dyn Any;
|
||||
fn to_any(self) -> Box<dyn Any>;
|
||||
}
|
||||
|
||||
pub trait MersType: Any + Debug {
|
||||
/// If Some((_, false)) is returned, data of this type could match. If it matches, it matches with the type.
|
||||
/// If Some((_, true)) is returned, data of this type will always match with the type.
|
||||
fn matches(&self) -> Option<(Type, bool)> {
|
||||
None
|
||||
}
|
||||
pub trait MersType: Any + Debug + Display + Send + Sync {
|
||||
/// If Some(T), calling `iterable` on the MersData this MersType belongs to
|
||||
/// Should return Some(I), where I is an Iterator which only returns items of type T.
|
||||
fn iterable(&self) -> Option<Type> {
|
||||
@ -66,18 +62,28 @@ pub trait MersType: Any + Debug {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn mut_any(&mut self) -> &mut dyn Any;
|
||||
fn to_any(self) -> Box<dyn Any>;
|
||||
fn is_reference_to(&self) -> Option<&Type> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Data {
|
||||
is_mut: bool,
|
||||
counts: Arc<(AtomicUsize, AtomicUsize)>,
|
||||
pub data: Arc<RwLock<Box<dyn MersData>>>,
|
||||
}
|
||||
impl Data {
|
||||
pub fn new<T: MersData>(data: T) -> Self {
|
||||
Self::new_boxed(Box::new(data))
|
||||
Self::new_boxed(Box::new(data), true)
|
||||
}
|
||||
pub fn new_boxed(data: Box<dyn MersData>) -> Self {
|
||||
pub fn new_boxed(data: Box<dyn MersData>, is_mut: bool) -> Self {
|
||||
Self {
|
||||
is_mut,
|
||||
counts: Arc::new((
|
||||
AtomicUsize::new(if is_mut { 0 } else { 1 }),
|
||||
AtomicUsize::new(if is_mut { 1 } else { 0 }),
|
||||
)),
|
||||
data: Arc::new(RwLock::new(data)),
|
||||
}
|
||||
}
|
||||
@ -87,27 +93,116 @@ impl Data {
|
||||
pub fn one_tuple(v: Self) -> Self {
|
||||
Self::new(tuple::Tuple(vec![v]))
|
||||
}
|
||||
/// Returns true if self is `()`.
|
||||
pub fn is_zero_tuple(&self) -> bool {
|
||||
if let Some(tuple) = self
|
||||
.get()
|
||||
.as_any()
|
||||
.downcast_ref::<crate::data::tuple::Tuple>()
|
||||
{
|
||||
tuple.0.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
/// Returns `Some(d)` if and only if self is `(d)`.
|
||||
pub fn one_tuple_content(&self) -> Option<Data> {
|
||||
if let Some(data) = self
|
||||
.get()
|
||||
.as_any()
|
||||
.downcast_ref::<crate::data::tuple::Tuple>()
|
||||
.filter(|v| v.len() == 1)
|
||||
.and_then(|v| v.get(0))
|
||||
{
|
||||
Some(data.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn get(&self) -> RwLockReadGuard<Box<dyn MersData>> {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("[mers:data:cow] get");
|
||||
self.data.read().unwrap()
|
||||
}
|
||||
pub fn get_mut(&self) -> RwLockWriteGuard<Box<dyn MersData>> {
|
||||
pub fn get_mut_unchecked(&self) -> RwLockWriteGuard<Box<dyn MersData>> {
|
||||
self.data.write().unwrap()
|
||||
}
|
||||
pub fn try_get_mut(&self) -> Option<RwLockWriteGuard<Box<dyn MersData>>> {
|
||||
if self.is_mut && self.counts.0.load(std::sync::atomic::Ordering::Relaxed) == 0 {
|
||||
Some(self.get_mut_unchecked())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
/// like try_get_mut, but instead of returning `None` this function `get()`s the data and clones it.
|
||||
/// When cloning data, this transforms `self` into a `Data` with `is_mut: true`, hence the `&mut self` parameter.
|
||||
pub fn get_mut(&mut self) -> RwLockWriteGuard<Box<dyn MersData>> {
|
||||
if self.try_get_mut().is_none() {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!(
|
||||
"[mers:data:cow] cloning! get_mut called on {}",
|
||||
if !self.is_mut {
|
||||
"non-mut value"
|
||||
} else {
|
||||
"value with immut references"
|
||||
}
|
||||
);
|
||||
let val = self.get().clone();
|
||||
*self = Self::new_boxed(val, true);
|
||||
}
|
||||
self.get_mut_unchecked()
|
||||
}
|
||||
pub fn mkref(&self) -> Self {
|
||||
if self.is_mut {
|
||||
self.counts
|
||||
.1
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
Self {
|
||||
is_mut: true,
|
||||
counts: Arc::clone(&self.counts),
|
||||
data: Arc::clone(&self.data),
|
||||
}
|
||||
} else {
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("[mers:data:cow] cloning! mkref called on immutable data");
|
||||
Self::new_boxed(self.data.read().unwrap().clone(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Clone for Data {
|
||||
fn clone(&self) -> Self {
|
||||
// todo!("clone for data - requires CoW");
|
||||
self.counts
|
||||
.0
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
Self {
|
||||
is_mut: false,
|
||||
counts: Arc::clone(&self.counts),
|
||||
data: Arc::clone(&self.data),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Drop for Data {
|
||||
fn drop(&mut self) {
|
||||
if self.is_mut {
|
||||
&self.counts.1
|
||||
} else {
|
||||
&self.counts.0
|
||||
}
|
||||
.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Data {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.get().is_eq(other.get().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Type {
|
||||
// TODO: Maybe make sure this is always sorted by (recursive?!?) TypeId,
|
||||
// that way is_same_type_as can work more efficiently (cuz good code but also branch prediction)
|
||||
types: Vec<Arc<dyn MersType>>,
|
||||
pub types: Vec<Arc<dyn MersType>>,
|
||||
}
|
||||
impl Type {
|
||||
pub fn new<T: MersType>(t: T) -> Self {
|
||||
@ -118,11 +213,64 @@ impl Type {
|
||||
pub fn newm(types: Vec<Arc<dyn MersType>>) -> Self {
|
||||
Self { types }
|
||||
}
|
||||
pub fn empty() -> Self {
|
||||
Self { types: vec![] }
|
||||
}
|
||||
pub fn empty_tuple() -> Self {
|
||||
Self::new(tuple::TupleT(vec![]))
|
||||
}
|
||||
pub fn add<T: MersType>(&mut self, new: Box<T>) {
|
||||
todo!()
|
||||
/// Returns true if self is `()`.
|
||||
pub fn is_zero_tuple(&self) -> bool {
|
||||
let mut o = false;
|
||||
for t in &self.types {
|
||||
o = true;
|
||||
if let Some(tuple) = t.as_any().downcast_ref::<crate::data::tuple::TupleT>() {
|
||||
if !tuple.0.is_empty() {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
o
|
||||
}
|
||||
/// Returns `Some(d)` if and only if self is `(d)`.
|
||||
pub fn one_tuple_content(&self) -> Option<Type> {
|
||||
let mut o = Self::empty();
|
||||
for t in &self.types {
|
||||
if let Some(t) = t
|
||||
.as_any()
|
||||
.downcast_ref::<crate::data::tuple::TupleT>()
|
||||
.filter(|v| v.0.len() == 1)
|
||||
.and_then(|v| v.0.get(0))
|
||||
{
|
||||
o.add(Arc::new(t.clone()));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(o)
|
||||
}
|
||||
pub fn add(&mut self, new: Arc<dyn MersType>) {
|
||||
let n = new.as_any();
|
||||
if let Some(s) = n.downcast_ref::<Self>() {
|
||||
for t in &s.types {
|
||||
self.add(Arc::clone(t));
|
||||
}
|
||||
} else {
|
||||
self.types.push(new);
|
||||
}
|
||||
}
|
||||
pub fn dereference(&self) -> Option<Self> {
|
||||
let mut o = Self::empty();
|
||||
for t in &self.types {
|
||||
if let Some(t) = t.is_reference_to() {
|
||||
o.add(Arc::new(t.clone()));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(o)
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,7 +289,7 @@ impl MersType for Type {
|
||||
todo!()
|
||||
}
|
||||
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
|
||||
todo!()
|
||||
self.types.iter().all(|t| t.is_included_in_single(target))
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
@ -152,4 +300,45 @@ impl MersType for Type {
|
||||
fn to_any(self) -> Box<dyn Any> {
|
||||
Box::new(self)
|
||||
}
|
||||
fn iterable(&self) -> Option<Type> {
|
||||
let mut o = Self::empty();
|
||||
for t in self.types.iter() {
|
||||
if let Some(t) = t.iterable() {
|
||||
o.add(Arc::new(t));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(o)
|
||||
}
|
||||
fn get(&self) -> Option<Type> {
|
||||
let mut o = Self::empty();
|
||||
for t in self.types.iter() {
|
||||
if let Some(t) = t.get() {
|
||||
o.add(Arc::new(t));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(o)
|
||||
}
|
||||
}
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.types.is_empty() {
|
||||
write!(f, "<unreachable>")
|
||||
} else {
|
||||
if self.types.len() > 1 {
|
||||
write!(f, "{{")?;
|
||||
}
|
||||
write!(f, "{}", self.types[0])?;
|
||||
for t in self.types.iter().skip(1) {
|
||||
write!(f, "/{t}")?;
|
||||
}
|
||||
if self.types.len() > 1 {
|
||||
write!(f, "}}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,28 @@
|
||||
use std::{any::Any, fmt::Display, sync::Mutex};
|
||||
use std::{
|
||||
any::Any,
|
||||
fmt::Display,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use super::{Data, MersData, MersType, Type};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Reference(pub Data);
|
||||
pub struct Reference(pub Arc<Mutex<Data>>);
|
||||
|
||||
impl MersData for Reference {
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
*other.0.lock().unwrap() == *self.0.lock().unwrap()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_type(&self) -> Type {
|
||||
Type::new(ReferenceT(self.0.lock().unwrap().get().as_type()))
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -31,6 +45,7 @@ impl MersType for ReferenceT {
|
||||
}
|
||||
}
|
||||
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
|
||||
// &int isn't included in &(int/float), otherwise we could assign a float to it
|
||||
self.is_same_type_as(target)
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
@ -42,10 +57,18 @@ impl MersType for ReferenceT {
|
||||
fn to_any(self) -> Box<dyn Any> {
|
||||
Box::new(self)
|
||||
}
|
||||
fn is_reference_to(&self) -> Option<&Type> {
|
||||
Some(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Reference {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "&{}", self.0.get())
|
||||
write!(f, "&{}", self.0.lock().unwrap().get())
|
||||
}
|
||||
}
|
||||
impl Display for ReferenceT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "&{}", self.0)
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,22 @@ use super::{MersData, MersType, Type};
|
||||
pub struct String(pub std::string::String);
|
||||
|
||||
impl MersData for String {
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
other.0 == self.0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn as_type(&self) -> super::Type {
|
||||
Type::new(StringT)
|
||||
}
|
||||
fn mut_any(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
@ -45,3 +55,8 @@ impl Display for String {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl Display for StringT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "String")
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{any::Any, fmt::Display};
|
||||
use std::{any::Any, fmt::Display, sync::Arc};
|
||||
|
||||
use super::{Data, MersData, MersType, Type};
|
||||
|
||||
@ -15,15 +15,11 @@ impl Tuple {
|
||||
}
|
||||
|
||||
impl MersData for Tuple {
|
||||
fn matches(&self) -> Option<Data> {
|
||||
if let Some(d) = self.0.first() {
|
||||
if self.0.len() == 1 {
|
||||
Some(d.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn is_eq(&self, other: &dyn MersData) -> bool {
|
||||
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
||||
other.0 == self.0
|
||||
} else {
|
||||
None
|
||||
false
|
||||
}
|
||||
}
|
||||
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
|
||||
@ -32,6 +28,9 @@ impl MersData for Tuple {
|
||||
fn clone(&self) -> Box<dyn MersData> {
|
||||
Box::new(Clone::clone(self))
|
||||
}
|
||||
fn as_type(&self) -> Type {
|
||||
Type::new(TupleT(self.0.iter().map(|v| v.get().as_type()).collect()))
|
||||
}
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
@ -46,19 +45,12 @@ impl MersData for Tuple {
|
||||
#[derive(Debug)]
|
||||
pub struct TupleT(pub Vec<Type>);
|
||||
impl MersType for TupleT {
|
||||
fn matches(&self) -> Option<(Type, bool)> {
|
||||
if let Some(d) = self.0.first() {
|
||||
if self.0.len() == 1 {
|
||||
Some((d.clone(), true))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn iterable(&self) -> Option<Type> {
|
||||
Some(todo!("joine types"))
|
||||
let mut o = Type::empty();
|
||||
for t in self.0.iter() {
|
||||
o.add(Arc::new(t.clone()));
|
||||
}
|
||||
Some(o)
|
||||
}
|
||||
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
||||
other.as_any().downcast_ref::<Self>().is_some()
|
||||
@ -90,3 +82,16 @@ impl Display for Tuple {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl Display for TupleT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(")?;
|
||||
for (i, c) in self.0.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", c)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
|
@ -1,9 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
info::Info,
|
||||
program::{self, parsed::CompInfo},
|
||||
};
|
||||
use crate::program;
|
||||
|
||||
pub mod errors;
|
||||
pub mod statements;
|
||||
@ -96,7 +93,7 @@ impl Source {
|
||||
/// Useful for debugging the parser.
|
||||
pub fn section_begin(&mut self, section: String) -> Arc<String> {
|
||||
#[cfg(debug_assertions)]
|
||||
println!("Section begin: {}", §ion);
|
||||
println!("[mers:parse] Section begin: {}", §ion);
|
||||
let arc = Arc::new(section);
|
||||
self.sections.push(SectionMarker {
|
||||
section: Arc::clone(&arc),
|
||||
@ -141,7 +138,7 @@ impl SectionMarker {
|
||||
if Arc::strong_count(&self.section) == 1 {
|
||||
self.end = Some(end);
|
||||
#[cfg(debug_assertions)]
|
||||
println!("Section end : {}", &self.section);
|
||||
println!("[mers:parse] Section end : {}", &self.section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use super::Source;
|
||||
use crate::{
|
||||
data::{self, Data},
|
||||
data::Data,
|
||||
program::{self, parsed::MersStatement},
|
||||
};
|
||||
|
||||
@ -142,12 +142,6 @@ pub fn parse_no_chain(
|
||||
},
|
||||
})
|
||||
}
|
||||
"loop" => {
|
||||
src.section_begin("loop".to_string());
|
||||
Box::new(program::parsed::r#loop::Loop {
|
||||
inner: parse(src)?.expect("err: EOF instead of inner statement after loop"),
|
||||
})
|
||||
}
|
||||
"switch" => {
|
||||
src.section_begin("loop".to_string());
|
||||
todo!()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
108
mers_lib/src/program/configs/with_base.rs
Executable file
108
mers_lib/src/program/configs/with_base.rs
Executable 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")
|
||||
}
|
||||
}),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
@ -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
19
mers_lib/src/program/configs/with_get.rs
Normal file → Executable 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)) {
|
||||
|
@ -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>")
|
||||
}
|
||||
}
|
||||
|
@ -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
43
mers_lib/src/program/configs/with_math.rs
Normal file → Executable 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;
|
||||
|
156
mers_lib/src/program/configs/with_multithreading.rs
Executable file
156
mers_lib/src/program/configs/with_multithreading.rs
Executable 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>")
|
||||
}
|
||||
}
|
@ -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()
|
||||
}),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
92
mers_lib/src/program/configs/with_stdio.rs
Executable file
92
mers_lib/src/program/configs/with_stdio.rs
Executable 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()
|
||||
}),
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
@ -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)?,
|
||||
}))
|
||||
|
@ -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)
|
||||
}),
|
||||
},
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
}))
|
||||
|
@ -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)?,
|
||||
}))
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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(¬hing));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
@ -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(),
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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(¬hing));
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user