full rewrite, kinda works

This commit is contained in:
Mark
2023-07-28 00:33:15 +02:00
parent 16258c7a0a
commit b81dac682e
96 changed files with 3150 additions and 1982 deletions

4
mers_lib/Cargo.toml Executable file
View File

@@ -0,0 +1,4 @@
[package]
name = "mers_lib"
version = "0.3.0"
edition = "2021"

53
mers_lib/doc.md Executable file
View File

@@ -0,0 +1,53 @@
# mers documentation
## parsing
syntax:
- `// <comment>`
- `/* <comment> */`
operators:
- `<target> := <source>` init
- `<target> = <source>` assign (`<target>` must be a reference)
- `+`
- `-`
- `*`
- `/`
- `%`
- `&`
- `|`
- `&&`
- `||`
keywords (must be between whitespace):
- `if <condition> <statement>`
- `else <statement>` (after `if`)
- `loop <statement>`
- `switch { <arms> }`
- `<arg> -> <statement>`
- `def <name> <: for types, = for comptime> <_>` for compile-time stuff (types, macros, ...)
## details
### functions
A function takes an argument and returns some data:
func := input -> input + 2
3.func.println // 5
(list, 0).get // first element
(val, match -> match.println, [] -> "doesn't match".println).match
### switch
switch <val> {
<type> <func>
}
switch something {
int num -> {"int: " + num}.println
float num -> {"float: " + num}.println
}

15
mers_lib/init_to.rs Executable file
View File

@@ -0,0 +1,15 @@
use crate::data::Data;
use super::MersStatement;
pub struct InitTo {
pub target: Box<dyn MersStatement>,
pub source: Box<dyn MersStatement>,
}
impl MersStatement for InitTo {
fn has_scope(&self) -> bool {
false
}
fn run(&self, info: &mut super::Info) -> Data {}
}

47
mers_lib/src/data/bool.rs Executable file
View File

@@ -0,0 +1,47 @@
use std::{any::Any, fmt::Display};
use super::{MersData, MersType};
#[derive(Debug, Clone)]
pub struct Bool(pub bool);
impl MersData for Bool {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct BoolT;
impl MersType for BoolT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for Bool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

13
mers_lib/src/data/defs.rs Executable file
View File

@@ -0,0 +1,13 @@
use super::Data;
pub fn assign(from: Data, target: &Data) {
let mut target = target.get_mut();
if let Some(r) = target
.mut_any()
.downcast_mut::<crate::data::reference::Reference>()
{
*r.0.get_mut() = from.get().clone();
} else {
todo!("assignment to non-reference")
}
}

47
mers_lib/src/data/float.rs Executable file
View File

@@ -0,0 +1,47 @@
use std::{any::Any, fmt::Display};
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Float(pub f64);
impl MersData for Float {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct FloatT;
impl MersType for FloatT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for Float {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

79
mers_lib/src/data/function.rs Executable file
View File

@@ -0,0 +1,79 @@
use std::{
any::Any,
fmt::{Debug, Display},
sync::Arc,
};
use crate::program::{self, run::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>,
}
impl Function {
pub fn with_info(&self, info: program::run::Info) -> Self {
Self {
info,
out: Arc::clone(&self.out),
run: Arc::clone(&self.run),
}
}
pub fn run(&self, arg: Data) -> Data {
(self.run)(arg, &mut self.info.clone())
}
}
impl MersData for Function {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
pub struct FunctionT(Arc<dyn Fn(&Type) -> Option<Type>>);
impl MersType for FunctionT {
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
false
}
fn is_included_in_single(&self, _target: &dyn MersType) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Debug for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Function")
}
}
impl Debug for FunctionT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FunctionT")
}
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<function>")
}
}

47
mers_lib/src/data/int.rs Executable file
View File

@@ -0,0 +1,47 @@
use std::{any::Any, fmt::Display};
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Int(pub isize);
impl MersData for Int {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct IntT;
impl MersType for IntT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for Int {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

155
mers_lib/src/data/mod.rs Executable file
View File

@@ -0,0 +1,155 @@
use std::{
any::Any,
fmt::{Debug, Display},
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
};
pub mod bool;
pub mod float;
pub mod function;
pub mod int;
pub mod reference;
pub mod string;
pub mod tuple;
pub mod defs;
pub trait MersData: Any + Debug + Display {
fn matches(&self) -> Option<Data> {
None
}
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
None
}
/// By default, uses `iterable` to get an iterator and `nth` to retrieve the nth element.
/// Should have a custom implementation for better performance on most types
fn get(&self, i: usize) -> Option<Data> {
self.iterable()?.nth(i)
}
fn clone(&self) -> Box<dyn MersData>;
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
}
/// 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> {
None
}
/// If Some(T), calling `get` on data of this type may return T, but it might also return None.
/// By default, this returns the same thing as `iterable`, since this is also the default implementation for `MersData::get`.
fn get(&self) -> Option<Type> {
self.iterable()
}
/// If self and other are different types (`other.as_any().downcast_ref::<Self>().is_none()`),
/// this *must* return false.
fn is_same_type_as(&self, other: &dyn MersType) -> bool;
/// This doesn't handle the case where target is Type (is_included_in handles it)
fn is_included_in_single(&self, target: &dyn MersType) -> bool;
fn is_included_in(&self, target: &dyn MersType) -> bool {
if let Some(target) = target.as_any().downcast_ref::<Type>() {
target
.types
.iter()
.any(|t| self.is_included_in_single(t.as_ref()))
} else {
self.is_included_in_single(target)
}
}
fn as_any(&self) -> &dyn Any;
fn mut_any(&mut self) -> &mut dyn Any;
fn to_any(self) -> Box<dyn Any>;
}
#[derive(Debug)]
pub struct Data {
pub data: Arc<RwLock<Box<dyn MersData>>>,
}
impl Data {
pub fn new<T: MersData>(data: T) -> Self {
Self::new_boxed(Box::new(data))
}
pub fn new_boxed(data: Box<dyn MersData>) -> Self {
Self {
data: Arc::new(RwLock::new(data)),
}
}
pub fn empty_tuple() -> Self {
Self::new(tuple::Tuple(vec![]))
}
pub fn one_tuple(v: Self) -> Self {
Self::new(tuple::Tuple(vec![v]))
}
pub fn get(&self) -> RwLockReadGuard<Box<dyn MersData>> {
self.data.read().unwrap()
}
pub fn get_mut(&self) -> RwLockWriteGuard<Box<dyn MersData>> {
self.data.write().unwrap()
}
}
impl Clone for Data {
fn clone(&self) -> Self {
// todo!("clone for data - requires CoW");
Self {
data: Arc::clone(&self.data),
}
}
}
#[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>>,
}
impl Type {
pub fn new<T: MersType>(t: T) -> Self {
Self {
types: vec![Arc::new(t)],
}
}
pub fn newm(types: Vec<Arc<dyn MersType>>) -> Self {
Self { types }
}
pub fn empty_tuple() -> Self {
Self::new(tuple::TupleT(vec![]))
}
pub fn add<T: MersType>(&mut self, new: Box<T>) {
todo!()
}
}
// PROBLEM:
// [int, int]/[int, string]/[string, int]/[string, string]
// is the same type as [int/string, int/string],
// but [int, int]/[int, string]/[string int] isn't.
// somehow, we need to merge these into the simplest form (same outer type, inner types differ)
// before we can implement `Type`
// idea: pick all the ones with the same first type: [int, int]/[int, string] and [string, int]/[string, string]
// then repeat with the second type if possible (here not, but for longer tuples, probably?)
// merge the last existing type in all the collections until we reach the first type again or the last types aren't equal anymore (how to check????)
impl MersType for Type {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
todo!()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
todo!()
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}

51
mers_lib/src/data/reference.rs Executable file
View File

@@ -0,0 +1,51 @@
use std::{any::Any, fmt::Display, sync::Mutex};
use super::{Data, MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Reference(pub Data);
impl MersData for Reference {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct ReferenceT(pub Type);
impl MersType for ReferenceT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
if let Some(o) = other.as_any().downcast_ref::<Self>() {
self.0.is_same_type_as(&o.0)
} else {
false
}
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for Reference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "&{}", self.0.get())
}
}

47
mers_lib/src/data/string.rs Executable file
View File

@@ -0,0 +1,47 @@
use std::{any::Any, fmt::Display};
use super::{MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct String(pub std::string::String);
impl MersData for String {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
#[derive(Debug)]
pub struct StringT;
impl MersType for StringT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for String {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

92
mers_lib/src/data/tuple.rs Executable file
View File

@@ -0,0 +1,92 @@
use std::{any::Any, fmt::Display};
use super::{Data, MersData, MersType, Type};
#[derive(Debug, Clone)]
pub struct Tuple(pub Vec<Data>);
impl Tuple {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get(&self, i: usize) -> Option<&Data> {
self.0.get(i)
}
}
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
}
} else {
None
}
}
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_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
#[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"))
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for Tuple {
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.get())?;
}
write!(f, ")")?;
Ok(())
}
}

58
mers_lib/src/info/mod.rs Executable file
View File

@@ -0,0 +1,58 @@
use std::fmt::Debug;
#[derive(Clone, Debug)]
pub struct Info<L: Local> {
pub scopes: Vec<L>,
}
impl<L: Local> Info<L> {
/// Returns self, but completely empty (even without globals).
/// Only use this if you assume this Info will never be used.
pub fn neverused() -> Self {
Self { scopes: vec![] }
}
}
pub trait Local: Default + Debug {
type VariableIdentifier;
type VariableData;
// type TypesIdentifier;
// type TypesType;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData);
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData>;
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData>;
// fn add_type(&mut self, id: Self::TypesIdentifier, new_type: Self::TypesType);
// fn get_type(&self, id: Self::TypesIdentifier) -> Option<&Self::TypesType>;
}
impl<L: Local> Info<L> {
pub fn create_scope(&mut self) {
self.scopes.push(L::default())
}
/// WARNING: can remove the last scope, which can cause some other functions to panic. Use ONLY after a create_scope()
pub fn end_scope(&mut self) {
self.scopes.pop();
}
}
impl<L: Local> Local for Info<L> {
type VariableIdentifier = L::VariableIdentifier;
type VariableData = L::VariableData;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
self.scopes.last_mut().unwrap().init_var(id, value)
}
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData> {
self.scopes.iter().find_map(|l| l.get_var(id))
}
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData> {
self.scopes.iter_mut().find_map(|l| l.get_var_mut(id))
}
}
impl<L: Local> Default for Info<L> {
fn default() -> Self {
Self {
scopes: vec![L::default()],
}
}
}

12
mers_lib/src/lib.rs Executable file
View File

@@ -0,0 +1,12 @@
pub mod data;
pub mod info;
pub mod parsing;
pub mod program;
pub mod prelude_compile {
pub use crate::parsing::parse;
pub use crate::parsing::Source;
pub use crate::program::configs::Config;
pub use crate::program::parsed::MersStatement as ParsedMersStatement;
pub use crate::program::run::MersStatement as RunMersStatement;
}

0
mers_lib/src/parsing/errors.rs Executable file
View File

156
mers_lib/src/parsing/mod.rs Executable file
View File

@@ -0,0 +1,156 @@
use std::sync::Arc;
use crate::{
info::Info,
program::{self, parsed::CompInfo},
};
pub mod errors;
pub mod statements;
pub mod types;
pub fn parse(src: &mut Source) -> Result<Box<dyn program::parsed::MersStatement>, ()> {
Ok(Box::new(statements::parse_block(src)?))
}
pub struct Source {
src: String,
i: usize,
sections: Vec<SectionMarker>,
}
impl Source {
pub fn new(src: String) -> Self {
Self {
src,
i: 0,
sections: vec![],
}
}
pub fn skip_whitespace(&mut self) {
if let Some(i) = self.src[self.i..].char_indices().find_map(|(i, ch)| {
if !ch.is_whitespace() {
Some(i)
} else {
None
}
}) {
self.i += i;
} else {
self.i = self.src.len();
}
}
fn end_sections(&mut self) {
let pos = self.get_pos();
for section in self.sections.iter_mut() {
section.checked_end(pos);
}
}
pub fn peek_char(&self) -> Option<char> {
self.src[self.i..].chars().next()
}
pub fn next_char(&mut self) -> Option<char> {
self.end_sections();
let ch = self.src[self.i..].chars().next()?;
self.i += ch.len_utf8();
Some(ch)
}
fn word_splitter(ch: char) -> bool {
ch.is_whitespace() || ".,;)}".contains(ch)
}
pub fn peek_word(&self) -> &str {
self.src[self.i..]
.split(Self::word_splitter)
.next()
.unwrap_or("")
}
pub fn next_word(&mut self) -> &str {
self.end_sections();
let word = self.src[self.i..]
.split(Self::word_splitter)
.next()
.unwrap_or("");
self.i += word.len();
word
}
pub fn peek_line(&self) -> &str {
self.src[self.i..].lines().next().unwrap_or("")
}
pub fn next_line(&mut self) -> &str {
self.end_sections();
let line = self.src[self.i..].lines().next().unwrap_or("");
self.i += line.len();
line
}
pub fn get_pos(&self) -> SourcePos {
SourcePos(self.i)
}
pub fn set_pos(&mut self, new: SourcePos) {
self.i = new.0
}
/// Returns a SectionMarker which, when dropped, indicates the end of this section.
/// Useful for debugging the parser.
pub fn section_begin(&mut self, section: String) -> Arc<String> {
#[cfg(debug_assertions)]
println!("Section begin: {}", &section);
let arc = Arc::new(section);
self.sections.push(SectionMarker {
section: Arc::clone(&arc),
start: self.get_pos(),
end: None,
});
arc
}
pub fn sections(&self) -> &Vec<SectionMarker> {
&self.sections
}
}
impl Drop for Source {
fn drop(&mut self) {
self.end_sections()
}
}
/// Returned from Source::begin(), this indicates that parsing of
/// a certain section has not yet finished.
/// Once this is dropped, a section is considered done.
pub struct SectionMarker {
section: Arc<String>,
start: SourcePos,
end: Option<SourcePos>,
}
impl SectionMarker {
pub fn section(&self) -> &str {
&self.section
}
pub fn start(&self) -> &SourcePos {
&self.start
}
pub fn end(&self) -> &Option<SourcePos> {
&self.end
}
/// If this is the only remaining SectionMarker for this section,
/// this method sets its `end` property.
fn checked_end(&mut self, end: SourcePos) {
if self.end.is_none() {
if Arc::strong_count(&self.section) == 1 {
self.end = Some(end);
#[cfg(debug_assertions)]
println!("Section end : {}", &self.section);
}
}
}
}
#[derive(Clone, Copy)]
pub struct SourcePos(usize);
impl SourcePos {
fn diff(&self, rhs: &Self) -> usize {
rhs.0 - self.0
}
}

View File

@@ -0,0 +1,199 @@
use std::sync::Arc;
use super::Source;
use crate::{
data::{self, Data},
program::{self, parsed::MersStatement},
};
pub fn parse(src: &mut Source) -> Result<Option<Box<dyn program::parsed::MersStatement>>, ()> {
src.section_begin("statement".to_string());
let mut first = if let Some(s) = parse_no_chain(src)? {
s
} else {
return Ok(None);
};
src.skip_whitespace();
match src.peek_word() {
":=" => {
src.next_word();
first = Box::new(program::parsed::init_to::InitTo {
target: first,
source: parse(src)?.expect("todo"),
});
}
"=" => {
src.next_word();
first = Box::new(program::parsed::assign_to::AssignTo {
target: first,
source: parse(src)?.expect("todo"),
});
}
"->" => {
src.next_word();
first = Box::new(program::parsed::function::Function {
arg: first,
run: parse(src)?.expect("err: bad eof, fn needs some statement"),
});
}
_ => loop {
src.skip_whitespace();
if let Some('.') = src.peek_char() {
src.next_char();
let chained = parse_no_chain(src)?.expect("err: EOF instead of chain");
first = Box::new(program::parsed::chain::Chain { first, chained });
} else {
break;
}
},
}
if matches!(src.peek_char(), Some(',' | ';')) {
src.next_char();
}
Ok(Some(first))
}
/// Assumes the { has already been parsed
pub fn parse_block(src: &mut Source) -> Result<program::parsed::block::Block, ()> {
Ok(program::parsed::block::Block {
statements: parse_multiple(src, '}')?,
})
}
pub fn parse_tuple(src: &mut Source) -> Result<program::parsed::tuple::Tuple, ()> {
Ok(program::parsed::tuple::Tuple {
elems: parse_multiple(src, ')')?,
})
}
pub fn parse_multiple(src: &mut Source, end: char) -> Result<Vec<Box<dyn MersStatement>>, ()> {
src.section_begin("block".to_string());
let mut statements = vec![];
loop {
src.skip_whitespace();
if matches!(src.peek_char(), Some(e) if e == end) {
src.next_char();
break;
} else if let Some(s) = parse(src)? {
statements.push(s);
} else {
// EOF
break;
}
}
Ok(statements)
}
pub fn parse_no_chain(
src: &mut Source,
) -> Result<Option<Box<dyn program::parsed::MersStatement>>, ()> {
src.section_begin("statement no chain".to_string());
src.skip_whitespace();
match src.peek_char() {
Some('{') => {
src.next_char();
return Ok(Some(Box::new(parse_block(src)?)));
}
Some('(') => {
src.next_char();
return Ok(Some(Box::new(parse_tuple(src)?)));
}
Some('"') => {
src.section_begin("string literal".to_string());
src.next_char();
let mut s = String::new();
loop {
if let Some(ch) = src.next_char() {
if ch == '\\' {
s.push(match src.next_char() {
Some('\\') => '\\',
Some('r') => '\r',
Some('n') => '\n',
Some('t') => '\t',
Some(o) => todo!("err: unknown backslash escape '\\{o}'"),
None => todo!("err: eof in backslash escape"),
});
} else if ch == '"' {
break;
} else {
s.push(ch);
}
} else {
todo!("err: eof in string")
}
}
return Ok(Some(Box::new(program::parsed::value::Value(Data::new(
crate::data::string::String(s),
)))));
}
_ => {}
}
Ok(Some(match src.next_word() {
"if" => {
src.section_begin("if".to_string());
Box::new(program::parsed::r#if::If {
condition: parse(src)?.expect("err: EOF instead of condition"),
on_true: parse(src)?.expect("err: EOF instead of on_true"),
on_false: {
src.skip_whitespace();
if src.peek_word() == "else" {
src.section_begin("else".to_string());
src.next_word();
Some(parse(src)?.expect("err: EOF instead of on_false after else"))
} else {
None
}
},
})
}
"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!()
}
"true" => Box::new(program::parsed::value::Value(Data::new(
crate::data::bool::Bool(true),
))),
"false" => Box::new(program::parsed::value::Value(Data::new(
crate::data::bool::Bool(false),
))),
"" => return Ok(None),
o => {
let o = o.to_string();
src.section_begin("literals, variables, and other non-keyword things".to_string());
if let Ok(n) = o.parse() {
if src.peek_char() == Some('.') {
let here = src.get_pos();
src.next_char();
if let Ok(num) = format!("{o}.{}", src.next_word()).parse() {
Box::new(program::parsed::value::Value(Data::new(
crate::data::float::Float(num),
)))
} else {
src.set_pos(here);
Box::new(program::parsed::value::Value(Data::new(
crate::data::int::Int(n),
)))
}
} else {
Box::new(program::parsed::value::Value(Data::new(
crate::data::int::Int(n),
)))
}
} else {
if let Some('&') = o.chars().next() {
Box::new(program::parsed::variable::Variable {
is_ref: true,
var: o[1..].to_string(),
})
} else {
Box::new(program::parsed::variable::Variable {
is_ref: false,
var: o.to_string(),
})
}
}
}
}))
}

51
mers_lib/src/parsing/types.rs Executable file
View File

@@ -0,0 +1,51 @@
use super::Source;
/// multiple types are represented as a `Vec<ParsedType>`.
pub enum ParsedType {
Tuple(Vec<Vec<Self>>),
Type(String),
}
fn parse_single_type(src: &mut Source) -> Result<ParsedType, ()> {
src.section_begin("parse single type".to_string());
src.skip_whitespace();
Ok(match src.peek_char() {
// Tuple
Some('(') => {
src.next_char();
src.section_begin("parse tuple's inner types".to_string());
let mut inner = vec![];
loop {
match src.peek_char() {
Some(')') => {
src.next_char();
break;
}
Some(',') => {
src.next_char();
}
_ => todo!("err: bad char in tuple inner type"),
}
inner.push(parse_type(src)?);
}
ParsedType::Tuple(inner)
}
Some(_) => ParsedType::Type(src.next_word().to_lowercase()),
None => todo!(),
})
}
fn parse_type(src: &mut Source) -> Result<Vec<ParsedType>, ()> {
src.section_begin("parse single type".to_string());
let mut types = vec![];
loop {
types.push(parse_single_type(src)?);
src.skip_whitespace();
if let Some('/') = src.peek_char() {
continue;
} else {
break;
}
}
Ok(types)
}

View File

@@ -0,0 +1,198 @@
use std::sync::Arc;
use crate::{
data::{self, Data, Type},
info::Local,
program,
};
mod with_command_running;
mod with_iters;
mod with_list;
/// 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)
/// with_* for usage-oriented groups
/// add_* to add custom things
///
/// For doc-comments:
/// Description
/// `bundle_std()`
/// `type` - description
/// `var: type` - description
pub struct Config {
globals: usize,
info_parsed: super::parsed::Info,
info_run: super::run::Info,
}
impl Config {
pub fn new() -> Self {
Self {
globals: 0,
info_parsed: Default::default(),
info_run: Default::default(),
}
}
/// standard utilitis used in many programs
/// `bundle_base()`
/// `with_list()`
/// `with_command_running()`
pub fn bundle_std(self) -> Self {
self.with_command_running().with_list().bundle_base()
}
/// base utilities used in most programs
/// `with_prints()`
/// `with_math()`
/// `with_get()`
/// `with_iters()`
pub fn bundle_base(self) -> Self {
self.with_iters().with_get().with_math().with_prints()
}
/// `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()
}),
}),
)
}
/// `sum: fn` returns the sum of all the numbers in the tuple
pub fn with_math(self) -> Self {
self.add_var(
"sum".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
let mut sumi = 0;
let mut sumf = 0.0;
let mut usef = false;
for val in &tuple.0 {
if let Some(i) = val.get().as_any().downcast_ref::<data::int::Int>() {
sumi += i.0;
} else if let Some(i) =
val.get().as_any().downcast_ref::<data::float::Float>()
{
sumf += i.0;
usef = true;
}
}
if usef {
Data::new(data::float::Float(sumi as f64 + sumf))
} else {
Data::new(data::int::Int(sumi))
}
} else {
unreachable!("sum called on non-tuple")
}
}),
}),
)
}
/// `get: fn` is used to retrieve elements from collections
pub fn with_get(self) -> Self {
self.add_var(
"get".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
if let Some(tuple) = a.get().as_any().downcast_ref::<data::tuple::Tuple>() {
if let (Some(v), Some(i)) = (tuple.get(0), tuple.get(1)) {
if let Some(i) = i.get().as_any().downcast_ref::<data::int::Int>() {
if let Ok(i) = i.0.try_into() {
if let Some(v) = v.get().get(i) {
Data::one_tuple(v)
} else {
Data::empty_tuple()
}
} else {
Data::empty_tuple()
}
} else {
unreachable!("get called with non-int index")
}
} else {
unreachable!("get called on tuple with len < 2")
}
} else {
unreachable!("get called on non-tuple, arg must be (_, index)")
}
}),
}),
)
}
pub fn add_var(mut self, name: String, val: Data) -> Self {
self.info_parsed.scopes[0].init_var(name, (0, self.globals));
self.info_run.scopes[0].init_var(self.globals, val);
self.globals += 1;
self
}
pub fn add_type(mut self, name: String, t: Type) -> Self {
// TODO! needed for type syntax in the parser, everything else probably(?) works already
self
}
pub fn infos(self) -> (super::parsed::Info, super::run::Info) {
(self.info_parsed, self.info_run)
}
}

View File

@@ -0,0 +1,104 @@
use std::{fmt::Display, process::Command, sync::Arc};
use crate::{
data::{self, Data, MersData, MersType},
program,
};
use super::Config;
impl Config {
/// adds utilities to run commands installed on the system and get their output.
/// `run_command: fn` runs a command with arguments.
/// Args: (cmd, args) where cmd is a string and args is an Iterable over strings
/// `RunCommandError` holds the error if the command can't be executed
pub fn with_command_running(self) -> Self {
self.add_var(
"run_command".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| 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)) {
if let (Some(cmd), Some(args)) = (
cmd.get().as_any().downcast_ref::<data::string::String>(),
args.get().iterable(),
) {
match Command::new(&cmd.0)
.args(args.map(|v| v.get().to_string()))
.output()
{
Ok(output) => {
let status = if let Some(code) = output.status.code() {
Data::new(data::int::Int(code as _))
} else {
Data::empty_tuple()
};
let stdout =
String::from_utf8_lossy(&output.stdout).into_owned();
let stderr =
String::from_utf8_lossy(&output.stderr).into_owned();
Data::new(data::tuple::Tuple(vec![
status,
Data::new(data::string::String(stdout)),
Data::new(data::string::String(stderr)),
]))
}
Err(e) => Data::new(RunCommandError(e.to_string())),
}
} else {
unreachable!("run_command called with arguments other than (String, <Iterable>).")
}
} else {
unreachable!("run_command called with too few arguments")
}
} else {
unreachable!("run_command called with non-tuple argument")
}
}),
}),
)
}
}
#[derive(Clone, Debug)]
pub struct RunCommandError(String);
#[derive(Debug)]
pub struct RunCommandErrorT;
impl MersData for RunCommandError {
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
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 RunCommandErrorT {
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other.as_any().downcast_ref::<Self>().is_some()
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
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 Display for RunCommandError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RunCommandError: {}", self.0)
}
}

View File

@@ -0,0 +1,175 @@
use std::{fmt::Display, sync::Arc};
use crate::{
data::{self, Data, MersData},
program,
};
use super::Config;
impl Config {
/// Adds functions to deal with iterables
/// `iter: fn` executes a function once for each element of the iterable
pub fn with_iters(self) -> Self {
self.add_var(
"iter".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| 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)) {
if let (Some(iter), Some(f)) = (
v.get().iterable(),
f.get().as_any().downcast_ref::<data::function::Function>(),
) {
for v in iter {
f.run(v);
}
Data::empty_tuple()
} else {
unreachable!(
"iter called on tuple not containing iterable and function"
)
}
} else {
unreachable!("iter called on tuple with len < 2")
}
} else {
unreachable!("iter called on non-tuple")
}
}),
}),
)
.add_var(
"map".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| 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)) {
if let Some(f) =
f.get().as_any().downcast_ref::<data::function::Function>()
{
Data::new(Iter(Iters::Map(Clone::clone(f)), v.clone()))
} else {
unreachable!("iter called on tuple not containing function")
}
} else {
unreachable!("iter called on tuple with len < 2")
}
} else {
unreachable!("iter called on non-tuple")
}
}),
}),
)
.add_var(
"filter".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| 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)) {
if let Some(f) =
f.get().as_any().downcast_ref::<data::function::Function>()
{
Data::new(Iter(Iters::Filter(Clone::clone(f)), v.clone()))
} else {
unreachable!("iter called on tuple not containing function")
}
} else {
unreachable!("iter called on tuple with len < 2")
}
} else {
unreachable!("iter called on non-tuple")
}
}),
}),
)
.add_var(
"filter_map".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| 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)) {
if let Some(f) =
f.get().as_any().downcast_ref::<data::function::Function>()
{
Data::new(Iter(Iters::FilterMap(Clone::clone(f)), v.clone()))
} else {
unreachable!("iter called on tuple not containing function")
}
} else {
unreachable!("iter called on tuple with len < 2")
}
} else {
unreachable!("iter called on non-tuple")
}
}),
}),
)
}
}
#[derive(Clone, Debug)]
pub enum Iters {
Map(data::function::Function),
Filter(data::function::Function),
FilterMap(data::function::Function),
}
#[derive(Clone, Debug)]
pub struct Iter(Iters, Data);
#[derive(Clone, Debug)]
pub struct IterT(Iters);
impl MersData for Iter {
fn iterable(&self) -> Option<Box<dyn Iterator<Item = Data>>> {
Some(match &self.0 {
Iters::Map(f) => {
let f = Clone::clone(f);
Box::new(self.1.get().iterable()?.map(move |v| f.run(v)))
}
Iters::Filter(f) => {
let f = Clone::clone(f);
Box::new(self.1.get().iterable()?.filter(move |v| {
f.run(v.clone())
.get()
.as_any()
.downcast_ref::<data::bool::Bool>()
.is_some_and(|b| b.0)
}))
}
Iters::FilterMap(f) => {
let f = Clone::clone(f);
Box::new(
self.1
.get()
.iterable()?
.filter_map(move |v| f.run(v).get().matches()),
)
}
_ => todo!(),
})
}
fn clone(&self) -> Box<dyn MersData> {
Box::new(Clone::clone(self))
}
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 Display for Iter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Iter>")
}
}

View File

@@ -0,0 +1,90 @@
use std::{fmt::Display, sync::Arc};
use crate::{
data::{self, Data, MersData, MersType, Type},
program,
};
use super::Config;
impl Config {
/// Adds a simple list type
/// `List` can store a variable number of items
/// `as_list: fn` turns a tuple into a list
pub fn with_list(self) -> Self {
// TODO: Type with generics
self.add_type("List".to_string(), Type::new(ListT(Type::empty_tuple())))
.add_var(
"as_list".to_string(),
Data::new(data::function::Function {
info: program::run::Info::neverused(),
out: Arc::new(|_a| todo!()),
run: Arc::new(|a, _i| {
if let Some(i) = a.get().iterable() {
Data::new(List(i.collect()))
} else {
unreachable!("as_list called on non-iterable")
}
}),
}),
)
}
}
#[derive(Clone, Debug)]
pub struct List(Vec<Data>);
#[derive(Debug)]
pub struct ListT(Type);
impl MersData for List {
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_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 ListT {
fn iterable(&self) -> Option<Type> {
Some(self.0.clone())
}
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
other
.as_any()
.downcast_ref::<Self>()
.is_some_and(|v| self.0.is_same_type_as(&v.0))
}
fn is_included_in_single(&self, target: &dyn MersType) -> bool {
self.is_same_type_as(target)
}
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 Display for List {
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.get())?;
}
write!(f, "]")?;
Ok(())
}
}

3
mers_lib/src/program/mod.rs Executable file
View File

@@ -0,0 +1,3 @@
pub mod configs;
pub mod parsed;
pub mod run;

View File

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

View File

@@ -0,0 +1,26 @@
use crate::{info, program};
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Block {
pub statements: Vec<Box<dyn MersStatement>>,
}
impl MersStatement for Block {
fn has_scope(&self) -> bool {
true
}
fn compile_custom(
&self,
info: &mut info::Info<super::Local>,
comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::block::Block {
statements: self
.statements
.iter()
.map(|v| v.compile(info, comp))
.collect::<Result<Vec<_>, _>>()?,
}))
}
}

View File

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

View File

@@ -0,0 +1,42 @@
use std::sync::Arc;
use crate::{
data::{self, Data},
info::Local,
program,
};
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Function {
pub arg: Box<dyn MersStatement>,
pub run: Box<dyn MersStatement>,
}
impl MersStatement for Function {
fn has_scope(&self) -> bool {
// TODO: what???
false
}
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
mut comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
comp.is_init = true;
let arg = self.arg.compile(info, comp)?;
comp.is_init = false;
let run = self.run.compile(info, comp)?;
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));
run.run(info)
}),
},
}))
}
}

View File

@@ -0,0 +1,31 @@
use crate::program;
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct If {
pub condition: Box<dyn MersStatement>,
pub on_true: Box<dyn MersStatement>,
pub on_false: Option<Box<dyn MersStatement>>,
}
impl MersStatement for If {
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#if::If {
condition: self.condition.compile(info, comp)?,
on_true: self.condition.compile(info, comp)?,
on_false: if let Some(v) = &self.on_false {
Some(v.compile(info, comp)?)
} else {
None
},
}))
}
}

View File

@@ -0,0 +1,29 @@
use crate::{info::Local, program};
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct InitTo {
pub target: Box<dyn MersStatement>,
pub source: Box<dyn MersStatement>,
}
impl MersStatement for InitTo {
fn has_scope(&self) -> bool {
false
}
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
mut comp: CompInfo,
) -> Result<Box<dyn crate::program::run::MersStatement>, String> {
comp.is_init = true;
let target = self.target.compile(info, comp)?;
comp.is_init = false;
let source = self.source.compile(info, comp)?;
Ok(Box::new(program::run::assign_to::AssignTo {
target,
source,
}))
}
}

View File

@@ -0,0 +1,23 @@
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

@@ -0,0 +1,68 @@
use std::{collections::HashMap, fmt::Debug};
use crate::info;
pub mod assign_to;
pub mod block;
pub mod chain;
pub mod function;
pub mod r#if;
pub mod init_to;
pub mod r#loop;
pub mod switch;
pub mod tuple;
pub mod value;
pub mod variable;
pub trait MersStatement: Debug {
fn has_scope(&self) -> bool;
fn compile_custom(
&self,
info: &mut Info,
comp: CompInfo,
) -> Result<Box<dyn super::run::MersStatement>, String>;
fn compile(
&self,
info: &mut Info,
comp: CompInfo,
) -> Result<Box<dyn super::run::MersStatement>, String> {
if self.has_scope() {
info.create_scope();
}
let o = self.compile_custom(info, comp);
if self.has_scope() {
info.end_scope();
}
o
}
}
#[derive(Clone, Copy)]
pub struct CompInfo {
is_init: bool,
}
impl Default for CompInfo {
fn default() -> Self {
Self { is_init: false }
}
}
pub type Info = info::Info<Local>;
#[derive(Default, Clone, Debug)]
pub struct Local {
vars: HashMap<String, (usize, usize)>,
}
impl info::Local for Local {
type VariableIdentifier = String;
type VariableData = (usize, usize);
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
self.vars.insert(id, value);
}
fn get_var(&self, id: &Self::VariableIdentifier) -> Option<&Self::VariableData> {
self.vars.get(id)
}
fn get_var_mut(&mut self, id: &Self::VariableIdentifier) -> Option<&mut Self::VariableData> {
self.vars.get_mut(id)
}
}

View File

@@ -0,0 +1,27 @@
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

@@ -0,0 +1,26 @@
use crate::{info, program};
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Tuple {
pub elems: Vec<Box<dyn MersStatement>>,
}
impl MersStatement for Tuple {
fn has_scope(&self) -> bool {
false
}
fn compile_custom(
&self,
info: &mut info::Info<super::Local>,
comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
Ok(Box::new(program::run::tuple::Tuple {
elems: self
.elems
.iter()
.map(|v| v.compile(info, comp))
.collect::<Result<Vec<_>, _>>()?,
}))
}
}

View File

@@ -0,0 +1,21 @@
use crate::{data::Data, program};
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Value(pub Data);
impl MersStatement for Value {
fn has_scope(&self) -> bool {
false
}
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::value::Value {
val: self.0.clone(),
}))
}
}

View File

@@ -0,0 +1,38 @@
use crate::{info::Local, program};
use super::{CompInfo, MersStatement};
#[derive(Debug)]
pub struct Variable {
pub is_ref: bool,
pub var: String,
}
impl MersStatement for Variable {
fn has_scope(&self) -> bool {
false
}
fn compile_custom(
&self,
info: &mut crate::info::Info<super::Local>,
comp: CompInfo,
) -> Result<Box<dyn program::run::MersStatement>, String> {
if comp.is_init {
info.init_var(
self.var.clone(),
(
info.scopes.len() - 1,
info.scopes.last().unwrap().vars.len(),
),
)
}
Ok(Box::new(program::run::variable::Variable {
is_ref: comp.is_init || self.is_ref,
var: if let Some(v) = info.get_var(&self.var) {
*v
} else {
return Err(format!("No variable named '{}' found!", self.var));
},
}))
}
}

View File

@@ -0,0 +1,21 @@
use crate::data;
use super::MersStatement;
#[derive(Debug)]
pub struct AssignTo {
pub target: Box<dyn MersStatement>,
pub source: Box<dyn MersStatement>,
}
impl MersStatement for AssignTo {
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
let source = self.source.run(info);
let target = self.target.run(info);
data::defs::assign(source, &target);
target
}
fn has_scope(&self) -> bool {
false
}
}

View File

@@ -0,0 +1,20 @@
use std::sync::Arc;
use super::MersStatement;
#[derive(Debug)]
pub struct Block {
pub statements: Vec<Box<dyn MersStatement>>,
}
impl MersStatement for Block {
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
self.statements
.iter()
.map(|s| s.run(info))
.last()
.unwrap_or_else(|| crate::data::Data::new(crate::data::tuple::Tuple(vec![])))
}
fn has_scope(&self) -> bool {
true
}
}

View File

@@ -0,0 +1,26 @@
use std::{any::Any, sync::Arc};
use crate::data::{function::Function, Data};
use super::MersStatement;
#[derive(Debug)]
pub struct Chain {
pub first: Box<dyn MersStatement>,
pub chained: Box<dyn MersStatement>,
}
impl MersStatement for Chain {
fn run_custom(&self, info: &mut super::Info) -> Data {
let f = self.first.run(info);
let c = self.chained.run(info);
let c = c.get();
if let Some(func) = c.as_any().downcast_ref::<crate::data::function::Function>() {
func.run(f)
} else {
todo!("err: not a function");
}
}
fn has_scope(&self) -> bool {
false
}
}

View File

@@ -0,0 +1,17 @@
use crate::data::{self, Data, MersData};
use super::MersStatement;
#[derive(Debug)]
pub struct Function {
pub func_no_info: data::function::Function,
}
impl MersStatement for Function {
fn has_scope(&self) -> bool {
false
}
fn run_custom(&self, info: &mut super::Info) -> Data {
Data::new(self.func_no_info.with_info(info.clone()))
}
}

18
mers_lib/src/program/run/if.rs Executable file
View File

@@ -0,0 +1,18 @@
use super::MersStatement;
#[derive(Debug)]
pub struct If {
pub condition: Box<dyn MersStatement>,
pub on_true: Box<dyn MersStatement>,
pub on_false: Option<Box<dyn MersStatement>>,
}
impl MersStatement for If {
fn run_custom(&self, info: &mut super::Info) -> crate::data::Data {
self.condition.run(info);
todo!("what now?")
}
fn has_scope(&self) -> bool {
true
}
}

View File

@@ -0,0 +1,21 @@
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
}
}

63
mers_lib/src/program/run/mod.rs Executable file
View File

@@ -0,0 +1,63 @@
use std::sync::Arc;
use crate::{
data::{self, Data, Type},
info,
};
pub mod assign_to;
pub mod block;
pub mod chain;
pub mod function;
pub mod r#if;
pub mod r#loop;
pub mod switch;
pub mod tuple;
pub mod value;
pub mod variable;
pub trait MersStatement: std::fmt::Debug {
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 run(&self, info: &mut Info) -> Data {
if self.has_scope() {
info.create_scope();
}
let o = self.run_custom(info);
if self.has_scope() {
info.end_scope();
}
o
}
}
pub type Info = info::Info<Local>;
#[derive(Default, Clone, Debug)]
pub struct Local {
vars: Vec<Data>,
}
impl info::Local for Local {
type VariableIdentifier = usize;
type VariableData = Data;
fn init_var(&mut self, id: Self::VariableIdentifier, value: Self::VariableData) {
while self.vars.len() <= id {
self.vars.push(Data::new(data::bool::Bool(false)));
}
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,
}
}
}

View File

@@ -0,0 +1,23 @@
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

@@ -0,0 +1,18 @@
use crate::data::{self, Data};
use super::MersStatement;
#[derive(Debug)]
pub struct Tuple {
pub elems: Vec<Box<dyn MersStatement>>,
}
impl MersStatement for Tuple {
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(),
))
}
fn has_scope(&self) -> bool {
false
}
}

View File

@@ -0,0 +1,17 @@
use crate::data::{Data, MersData};
use super::MersStatement;
#[derive(Debug)]
pub struct Value {
pub val: Data,
}
impl MersStatement for Value {
fn has_scope(&self) -> bool {
false
}
fn run_custom(&self, info: &mut super::Info) -> Data {
self.val.clone()
}
}

View File

@@ -0,0 +1,30 @@
use crate::data::{self, Data};
use super::MersStatement;
#[derive(Debug)]
pub struct Variable {
pub is_ref: bool,
pub var: (usize, usize),
}
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)));
}
if self.is_ref {
Data::new(data::reference::Reference(
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())
}
}
}