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 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
View File

View 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)
}
}
}
}

View File

@ -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
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]
default = []
default = ["parse"]
parse = ["run"]
run = []

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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