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

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