mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
improved the mers library system
added a GUI library wrapping iced-rs, mainly to test the limits of the current library system. see gui.txt for an example on how to use the gui library. (note: set the MERS_LIB_DIR environment variable to the path of your local mers_libs/ folder (lib paths are relative to MERS_LIB_DIR if they're not specified as absolute))
This commit is contained in:
parent
38d641ffcd
commit
5b051e72f1
@ -5,5 +5,9 @@ edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
name = "mers"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
regex = "1.7.2"
|
||||
|
51
gui.txt
Normal file
51
gui.txt
Normal file
@ -0,0 +1,51 @@
|
||||
lib gui.sh
|
||||
|
||||
base = gui_init()
|
||||
column = base.gui_add(Column: [])
|
||||
|
||||
text = column.gui_add(Text: "Welcome to MERS GUI!")
|
||||
|
||||
button = column.gui_add(Button: "This is a button.")
|
||||
second_button = column.gui_add(Button: "This is a second button.")
|
||||
|
||||
text_state = -2
|
||||
second_text = column.gui_add(Text: "press the button above to remove this text!")
|
||||
|
||||
while {
|
||||
for event gui_updates() {
|
||||
switch! event {
|
||||
ButtonPressed([int]) {
|
||||
e = event.noenum()
|
||||
match e {
|
||||
&e.eq(&button) println("First button pressed")
|
||||
&e.eq(&second_button) {
|
||||
// don't match on text_state because we need to change the original from inside the match statement
|
||||
state = text_state
|
||||
match state {
|
||||
// the first, third, fifth, ... time the button is pressed: remove the text
|
||||
text_state.mod(2).eq(0) {
|
||||
if text_state.eq(-2) {
|
||||
// the first time the button is pressed
|
||||
text_state = 0
|
||||
set_title("keep pressing the button!")
|
||||
}
|
||||
second_text.gui_remove()
|
||||
}
|
||||
// the 2nd, 4th, 6th, ... time the button is pressed: add the text back
|
||||
text_state.eq(1) second_text = column.gui_add(Text: "i'm back!")
|
||||
text_state.eq(3) second_text = column.gui_add(Text: "you can't fully get rid of me!")
|
||||
true {
|
||||
second_text = column.gui_add(Text: "i always come back")
|
||||
// restart (set text_state to 0)
|
||||
text_state = -1
|
||||
}
|
||||
}
|
||||
text_state = text_state.add(1)
|
||||
}
|
||||
true println("A different button was pressed (unreachable)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[]
|
||||
}
|
3
mers_libs/gui.sh
Executable file
3
mers_libs/gui.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd ./gui_v1
|
||||
cargo run --release
|
2921
mers_libs/gui_v1/Cargo.lock
generated
Normal file
2921
mers_libs/gui_v1/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
mers_libs/gui_v1/Cargo.toml
Normal file
10
mers_libs/gui_v1/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "gui_v1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
iced = { version = "0.8.0", features = ["smol"] }
|
||||
mers = { path = "../../" }
|
451
mers_libs/gui_v1/src/main.rs
Normal file
451
mers_libs/gui_v1/src/main.rs
Normal file
@ -0,0 +1,451 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{self, Read},
|
||||
rc::Rc,
|
||||
sync::{mpsc, Arc},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use iced::{
|
||||
executor, time,
|
||||
widget::{self, button, column, row, text},
|
||||
Application, Command, Element, Renderer, Settings, Subscription, Theme,
|
||||
};
|
||||
use mers::{
|
||||
libs::inlib::{MyLib, MyLibTask},
|
||||
script::{
|
||||
val_data::{VData, VDataEnum},
|
||||
val_type::{VSingleType, VType},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Path: Vec<usize>
|
||||
|
||||
*/
|
||||
|
||||
fn single_gui_element() -> VType {
|
||||
VType {
|
||||
types: vec![
|
||||
VSingleType::EnumVariantS("Row".to_string(), VSingleType::Tuple(vec![]).to()),
|
||||
VSingleType::EnumVariantS("Column".to_string(), VSingleType::Tuple(vec![]).to()),
|
||||
VSingleType::EnumVariantS("Text".to_string(), VSingleType::String.to()),
|
||||
VSingleType::EnumVariantS(
|
||||
"Button".to_string(),
|
||||
VType {
|
||||
types: vec![VSingleType::Tuple(vec![]), VSingleType::String],
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
}
|
||||
fn single_gui_update() -> VType {
|
||||
VType {
|
||||
types: vec![VSingleType::EnumVariantS(
|
||||
"ButtonPressed".to_string(),
|
||||
VSingleType::List(VSingleType::Int.to()).to(),
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (sender, recv) = mpsc::channel();
|
||||
let (sender2, recv2) = mpsc::channel();
|
||||
std::thread::spawn(move || {
|
||||
let recv = recv2;
|
||||
let (mut my_lib, mut run) = MyLib::new(
|
||||
"GUI-Iced".to_string(),
|
||||
(0, 0),
|
||||
"A basic GUI library for mers.".to_string(),
|
||||
vec![
|
||||
(
|
||||
"gui_init".to_string(),
|
||||
vec![],
|
||||
VSingleType::List(VSingleType::Int.to()).to(),
|
||||
),
|
||||
(
|
||||
"gui_updates".to_string(),
|
||||
vec![],
|
||||
VSingleType::List(single_gui_update()).to(),
|
||||
),
|
||||
(
|
||||
"set_title".to_string(),
|
||||
vec![VSingleType::String.to()],
|
||||
VSingleType::Tuple(vec![]).to(),
|
||||
),
|
||||
(
|
||||
"gui_add".to_string(),
|
||||
vec![
|
||||
VSingleType::List(VSingleType::Int.to()).to(),
|
||||
single_gui_element(),
|
||||
],
|
||||
VSingleType::List(VSingleType::Int.to()).to(),
|
||||
),
|
||||
(
|
||||
"gui_remove".to_string(),
|
||||
vec![VSingleType::List(VSingleType::Int.to()).to()],
|
||||
VSingleType::Tuple(vec![]).to(),
|
||||
),
|
||||
],
|
||||
);
|
||||
let mut stdin = std::io::stdin().lock();
|
||||
let mut stdout = std::io::stdout().lock();
|
||||
let mut layout = Layout::Row(vec![]);
|
||||
loop {
|
||||
run = match my_lib.run(run, &mut stdin, &mut stdout) {
|
||||
MyLibTask::None(v) => v,
|
||||
MyLibTask::RunFunction(mut f) => {
|
||||
let return_value = match f.function {
|
||||
0 => VDataEnum::List(VSingleType::Int.to(), vec![]).to(),
|
||||
1 => {
|
||||
let mut v = vec![];
|
||||
while let Ok(recv) = recv.try_recv() {
|
||||
match recv {
|
||||
MessageAdv::ButtonPressed(path) => v.push(
|
||||
VDataEnum::EnumVariant(
|
||||
my_lib.get_enum("ButtonPressed"),
|
||||
Box::new(
|
||||
VDataEnum::List(VSingleType::Int.to(), path).to(),
|
||||
),
|
||||
)
|
||||
.to(),
|
||||
),
|
||||
}
|
||||
}
|
||||
VDataEnum::List(single_gui_update(), v).to()
|
||||
}
|
||||
2 => {
|
||||
// set_title
|
||||
if let VDataEnum::String(new_title) = f.args.remove(0).data {
|
||||
sender.send(Task::SetTitle(new_title)).unwrap();
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
// gui_add
|
||||
if let (layout_data, VDataEnum::List(_, path)) =
|
||||
(f.args.remove(1).data, f.args.remove(0).data)
|
||||
{
|
||||
let path: Vec<usize> = path
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
if let VDataEnum::Int(v) = v.data {
|
||||
v as _
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let lo = layout_from_vdata(&my_lib, layout_data);
|
||||
let layout_inner = layout.get_mut(&path, 0);
|
||||
let new_path: Vec<_> = path
|
||||
.iter()
|
||||
.map(|v| VDataEnum::Int(*v as _).to())
|
||||
.chain(
|
||||
[VDataEnum::Int(layout_inner.len() as _).to()].into_iter(),
|
||||
)
|
||||
.collect();
|
||||
layout_inner.add(lo.clone());
|
||||
sender.send(Task::LAdd(path, lo)).unwrap();
|
||||
VDataEnum::List(VSingleType::Int.to(), new_path).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
// gui_remove
|
||||
if let VDataEnum::List(_, path) = f.args.remove(0).data {
|
||||
let mut path: Vec<usize> = path
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
if let VDataEnum::Int(v) = v.data {
|
||||
v as _
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if let Some(remove_index) = path.pop() {
|
||||
let layout_inner = layout.get_mut(&path, 0);
|
||||
layout_inner.remove(remove_index);
|
||||
path.push(remove_index);
|
||||
sender.send(Task::LRemove(path)).unwrap();
|
||||
}
|
||||
VDataEnum::Tuple(vec![]).to()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
f.done(&mut stdout, return_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
App::run(Settings::with_flags((recv, sender2))).unwrap();
|
||||
}
|
||||
|
||||
fn layout_from_vdata(my_lib: &MyLib, d: VDataEnum) -> Layout {
|
||||
let row = my_lib.get_enum("Row");
|
||||
let col = my_lib.get_enum("Column");
|
||||
let text = my_lib.get_enum("Text");
|
||||
let button = my_lib.get_enum("Button");
|
||||
if let VDataEnum::EnumVariant(variant, inner_data) = d {
|
||||
if variant == row {
|
||||
Layout::Row(vec![])
|
||||
} else if variant == col {
|
||||
Layout::Column(vec![])
|
||||
} else if variant == text {
|
||||
Layout::Text(if let VDataEnum::String(s) = inner_data.data {
|
||||
s
|
||||
} else {
|
||||
String::new()
|
||||
})
|
||||
} else if variant == button {
|
||||
Layout::Button(Box::new(Layout::Text(
|
||||
if let VDataEnum::String(s) = inner_data.data {
|
||||
s
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
)))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
enum Task {
|
||||
SetTitle(String),
|
||||
LAdd(Vec<usize>, Layout),
|
||||
LSet(Vec<usize>, Layout),
|
||||
LRemove(Vec<usize>),
|
||||
}
|
||||
|
||||
struct App {
|
||||
title: String,
|
||||
recv: mpsc::Receiver<Task>,
|
||||
sender: mpsc::Sender<MessageAdv>,
|
||||
buttons: Vec<Vec<usize>>,
|
||||
layout: Layout,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Message {
|
||||
Tick,
|
||||
ButtonPressed(usize),
|
||||
}
|
||||
enum MessageAdv {
|
||||
ButtonPressed(Vec<VData>),
|
||||
}
|
||||
|
||||
impl Application for App {
|
||||
type Executor = executor::Default;
|
||||
type Message = Message;
|
||||
type Theme = Theme;
|
||||
type Flags = (mpsc::Receiver<Task>, mpsc::Sender<MessageAdv>);
|
||||
fn new(flags: Self::Flags) -> (Self, Command<Self::Message>) {
|
||||
(
|
||||
Self {
|
||||
title: format!("mers gui (using iced)..."),
|
||||
recv: flags.0,
|
||||
sender: flags.1,
|
||||
buttons: vec![],
|
||||
layout: Layout::Row(vec![]),
|
||||
},
|
||||
Command::none(),
|
||||
)
|
||||
}
|
||||
fn title(&self) -> String {
|
||||
format!("{}", self.title)
|
||||
}
|
||||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
|
||||
let mut commands = vec![];
|
||||
match message {
|
||||
Message::Tick => {
|
||||
let mut changed_layout = false;
|
||||
while let Ok(task) = self.recv.try_recv() {
|
||||
match task {
|
||||
Task::SetTitle(t) => {
|
||||
self.title = t;
|
||||
}
|
||||
Task::LAdd(path, add) => {
|
||||
changed_layout = true;
|
||||
self.layout.get_mut(&path, 0).add(add);
|
||||
}
|
||||
Task::LSet(path, add) => {
|
||||
changed_layout = true;
|
||||
*self.layout.get_mut(&path, 0) = add;
|
||||
}
|
||||
Task::LRemove(mut path) => {
|
||||
if let Some(last) = path.pop() {
|
||||
changed_layout = true;
|
||||
self.layout.get_mut(&path, 0).remove(last);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed_layout {
|
||||
self.calc_layout_stats();
|
||||
}
|
||||
}
|
||||
Message::ButtonPressed(bid) => self
|
||||
.sender
|
||||
.send(MessageAdv::ButtonPressed(
|
||||
self.buttons[bid]
|
||||
.iter()
|
||||
.map(|v| VDataEnum::Int(*v as _).to())
|
||||
.collect(),
|
||||
))
|
||||
.unwrap(),
|
||||
}
|
||||
Command::batch(commands)
|
||||
}
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
time::every(Duration::from_millis(10)).map(|_| Message::Tick)
|
||||
}
|
||||
fn view(&self) -> Element<'_, Self::Message, Renderer<Self::Theme>> {
|
||||
self.viewl(&mut vec![], &self.layout, &mut 0)
|
||||
}
|
||||
}
|
||||
impl App {
|
||||
fn viewl(
|
||||
&self,
|
||||
p: &mut Vec<usize>,
|
||||
l: &Layout,
|
||||
current_button: &mut usize,
|
||||
) -> Element<'_, <Self as Application>::Message, Renderer<<Self as Application>::Theme>> {
|
||||
match l {
|
||||
Layout::Row(v) => row(v
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
p.push(i);
|
||||
let o = self.viewl(p, v, current_button);
|
||||
p.pop();
|
||||
o
|
||||
})
|
||||
.collect())
|
||||
.into(),
|
||||
Layout::Column(v) => column(
|
||||
v.iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
p.push(i);
|
||||
let o = self.viewl(p, v, current_button);
|
||||
p.pop();
|
||||
o
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.into(),
|
||||
Layout::Text(txt) => text(txt).into(),
|
||||
Layout::Button(content) => button({
|
||||
p.push(0);
|
||||
let o = self.viewl(p, content, current_button);
|
||||
p.pop();
|
||||
o
|
||||
})
|
||||
.on_press(Message::ButtonPressed({
|
||||
let o = *current_button;
|
||||
*current_button = *current_button + 1;
|
||||
o
|
||||
}))
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
fn calc_layout_stats(&mut self) {
|
||||
Self::calc_layout_stats_rec(&self.layout, &mut vec![], &mut self.buttons)
|
||||
}
|
||||
fn calc_layout_stats_rec(
|
||||
layout: &Layout,
|
||||
path: &mut Vec<usize>,
|
||||
buttons: &mut Vec<Vec<usize>>,
|
||||
) {
|
||||
match layout {
|
||||
Layout::Row(v) | Layout::Column(v) => {
|
||||
for (i, v) in v.iter().enumerate() {
|
||||
path.push(i);
|
||||
Self::calc_layout_stats_rec(v, path, buttons);
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
Layout::Button(c) => {
|
||||
buttons.push(path.clone());
|
||||
path.push(0);
|
||||
Self::calc_layout_stats_rec(c, path, buttons);
|
||||
path.pop();
|
||||
}
|
||||
Layout::Text(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Layout {
|
||||
Row(Vec<Self>),
|
||||
Column(Vec<Self>),
|
||||
Text(String),
|
||||
Button(Box<Self>),
|
||||
}
|
||||
impl Layout {
|
||||
pub fn get_mut(&mut self, path: &Vec<usize>, index: usize) -> &mut Self {
|
||||
if index >= path.len() {
|
||||
return self;
|
||||
}
|
||||
match self {
|
||||
Self::Row(v) => v[path[index]].get_mut(path, index + 1),
|
||||
Self::Column(v) => v[path[index]].get_mut(path, index + 1),
|
||||
Self::Button(c) => c.as_mut().get_mut(path, index + 1),
|
||||
Self::Text(_) => {
|
||||
panic!("cannot index this layout type! ({:?})", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn add(&mut self, add: Layout) {
|
||||
match self {
|
||||
Self::Row(v) | Self::Column(v) => v.push(add),
|
||||
_ => panic!("cannot add to this layout type! ({:?})", self),
|
||||
}
|
||||
}
|
||||
pub fn remove(&mut self, remove: usize) {
|
||||
match self {
|
||||
Self::Row(v) | Self::Column(v) => {
|
||||
if remove < v.len() {
|
||||
v.remove(remove);
|
||||
}
|
||||
}
|
||||
_ => panic!("cannot add to this layout type! ({:?})", self),
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Self::Row(v) | Self::Column(v) => v.len(),
|
||||
_ => panic!("cannot get len of this layout type! ({:?})", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait DirectRead {
|
||||
fn nbyte(&mut self) -> Result<u8, io::Error>;
|
||||
fn nchar(&mut self) -> Result<char, io::Error>;
|
||||
}
|
||||
impl<T> DirectRead for T
|
||||
where
|
||||
T: Read,
|
||||
{
|
||||
fn nbyte(&mut self) -> Result<u8, io::Error> {
|
||||
let mut b = [0];
|
||||
self.read(&mut b)?;
|
||||
Ok(b[0])
|
||||
}
|
||||
fn nchar(&mut self) -> Result<char, io::Error> {
|
||||
Ok(self.nbyte()?.into())
|
||||
}
|
||||
}
|
139
src/libs/inlib.rs
Normal file
139
src/libs/inlib.rs
Normal file
@ -0,0 +1,139 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::{BufRead, Write},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
libs::DirectReader,
|
||||
script::{
|
||||
val_data::{VData, VDataEnum},
|
||||
val_type::VType,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{data_from_bytes, data_to_bytes};
|
||||
|
||||
pub struct MyLib {
|
||||
name: String,
|
||||
version: (u8, u8),
|
||||
description: String,
|
||||
functions: Vec<(String, Vec<VType>, VType)>,
|
||||
enum_variants: HashMap<String, usize>,
|
||||
}
|
||||
impl MyLib {
|
||||
pub fn new(
|
||||
name: String,
|
||||
version: (u8, u8),
|
||||
description: String,
|
||||
functions: Vec<(String, Vec<VType>, VType)>,
|
||||
) -> (Self, MyLibTaskCompletion) {
|
||||
(
|
||||
Self {
|
||||
name,
|
||||
version,
|
||||
description,
|
||||
functions,
|
||||
enum_variants: HashMap::new(),
|
||||
},
|
||||
MyLibTaskCompletion { _priv: () },
|
||||
)
|
||||
}
|
||||
pub fn get_enum(&self, e: &str) -> usize {
|
||||
*self.enum_variants.get(e).unwrap()
|
||||
}
|
||||
pub fn run<I, O>(
|
||||
&mut self,
|
||||
run: MyLibTaskCompletion,
|
||||
stdin: &mut I,
|
||||
stdout: &mut O,
|
||||
) -> MyLibTask
|
||||
where
|
||||
I: BufRead,
|
||||
O: Write,
|
||||
{
|
||||
drop(run);
|
||||
match match stdin.one_byte().unwrap().into() {
|
||||
'i' => {
|
||||
assert_eq!(stdin.one_byte().unwrap() as char, '\n');
|
||||
stdout.write(&[self.version.0, self.version.1]).unwrap();
|
||||
writeln!(stdout, "{}", self.name).unwrap();
|
||||
stdout
|
||||
.write(&[self.description.split('\n').count() as _])
|
||||
.unwrap();
|
||||
writeln!(stdout, "{}", self.description).unwrap();
|
||||
for func in self.functions.iter() {
|
||||
writeln!(
|
||||
stdout,
|
||||
"f{}({}) {}",
|
||||
func.0,
|
||||
func.1
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| if i == 0 {
|
||||
format!("{v}")
|
||||
} else {
|
||||
format!(" {v}")
|
||||
})
|
||||
.collect::<String>(),
|
||||
func.2
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
writeln!(stdout, "x").unwrap();
|
||||
None
|
||||
}
|
||||
'I' => {
|
||||
let mut line = String::new();
|
||||
stdin.read_line(&mut line).unwrap();
|
||||
if let Some((task, args)) = line.split_once(' ') {
|
||||
match task {
|
||||
"set_enum_id" => {
|
||||
let (enum_name, enum_id) = args.split_once(' ').unwrap();
|
||||
let name = enum_name.trim().to_string();
|
||||
let id = enum_id.trim().parse().unwrap();
|
||||
self.enum_variants.insert(name.clone(), id);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
'f' => {
|
||||
let fnid = stdin.one_byte().unwrap() as usize;
|
||||
Some(MyLibTask::RunFunction(MyLibTaskRunFunction {
|
||||
function: fnid,
|
||||
args: self.functions[fnid]
|
||||
.1
|
||||
.iter()
|
||||
.map(|_| data_from_bytes(stdin).to())
|
||||
.collect(),
|
||||
}))
|
||||
}
|
||||
_ => None,
|
||||
} {
|
||||
Some(v) => v,
|
||||
None => MyLibTask::None(MyLibTaskCompletion { _priv: () }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MyLibTask {
|
||||
None(MyLibTaskCompletion),
|
||||
RunFunction(MyLibTaskRunFunction),
|
||||
}
|
||||
pub struct MyLibTaskRunFunction {
|
||||
pub function: usize,
|
||||
pub args: Vec<VData>,
|
||||
}
|
||||
impl MyLibTaskRunFunction {
|
||||
pub fn done<O>(self, o: &mut O, returns: VData) -> MyLibTaskCompletion
|
||||
where
|
||||
O: Write,
|
||||
{
|
||||
data_to_bytes(&returns, o);
|
||||
MyLibTaskCompletion { _priv: () }
|
||||
}
|
||||
}
|
||||
pub struct MyLibTaskCompletion {
|
||||
_priv: (),
|
||||
}
|
144
src/libs/mod.rs
144
src/libs/mod.rs
@ -1,5 +1,10 @@
|
||||
pub mod inlib;
|
||||
pub mod path;
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
io::{self, BufRead, BufReader, Read, Write},
|
||||
path::PathBuf,
|
||||
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
@ -55,7 +60,10 @@ pub struct Lib {
|
||||
pub registered_fns: Vec<(String, Vec<VType>, VType)>,
|
||||
}
|
||||
impl Lib {
|
||||
pub fn launch(mut exec: Command) -> Result<Self, LaunchError> {
|
||||
pub fn launch(
|
||||
mut exec: Command,
|
||||
enum_variants: &mut HashMap<String, usize>,
|
||||
) -> Result<Self, LaunchError> {
|
||||
let mut handle = match exec
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
@ -92,22 +100,33 @@ impl Lib {
|
||||
let (name, args) = line[1..]
|
||||
.split_once('(')
|
||||
.expect("function signature didn't include the ( character.");
|
||||
let mut fn_signature = File::new(args.to_string());
|
||||
let mut fn_signature = File::new(args.to_string(), PathBuf::new());
|
||||
let mut fn_in = vec![];
|
||||
fn_signature.skip_whitespaces();
|
||||
if let Some(')') = fn_signature.peek() {
|
||||
fn_signature.next();
|
||||
} else {
|
||||
loop {
|
||||
let t = parse::parse_type_adv(&mut fn_signature, true).unwrap();
|
||||
let mut t = parse::parse_type_adv(&mut fn_signature, true).unwrap();
|
||||
t.0.enum_variants(enum_variants);
|
||||
fn_in.push(t.0);
|
||||
if t.1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let fn_out = parse::parse_type(&mut fn_signature).unwrap();
|
||||
eprintln!("Registering function \"{name}\" with args \"{}\" and return type \"{fn_out}\"", &fn_in.iter().fold(String::new(), |mut s, v| { s.push_str(format!(" {}", v).as_str()); s })[1..]);
|
||||
}
|
||||
let mut fn_out = parse::parse_type(&mut fn_signature).unwrap();
|
||||
fn_out.enum_variants(enum_variants);
|
||||
eprintln!("Registering function \"{name}\" with args \"{}\" and return type \"{fn_out}\"", &fn_in.iter().fold(String::new(), |mut s, v| { s.push_str(format!(" {}", v).as_str()); s }).trim_start_matches(' '));
|
||||
registered_fns.push((name.to_string(), fn_in, fn_out));
|
||||
}
|
||||
_ => break,
|
||||
Some('x') => break,
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
for (enum_name, enum_id) in enum_variants.iter() {
|
||||
writeln!(stdin, "Iset_enum_id {enum_name} {enum_id}").unwrap();
|
||||
}
|
||||
Ok(Self {
|
||||
process: handle,
|
||||
stdin: Arc::new(Mutex::new(stdin)),
|
||||
@ -126,9 +145,9 @@ impl Lib {
|
||||
write!(stdin, "f").unwrap();
|
||||
stdin.write(&[fnid as _]).unwrap();
|
||||
for (_i, arg) in args.iter().enumerate() {
|
||||
data_to_bytes(arg, &mut stdin);
|
||||
data_to_bytes(arg, &mut *stdin);
|
||||
}
|
||||
let o = data_from_bytes(&mut stdout).to();
|
||||
let o = data_from_bytes(&mut *stdout).to();
|
||||
o
|
||||
}
|
||||
}
|
||||
@ -139,7 +158,7 @@ pub enum LaunchError {
|
||||
CouldNotSpawnProcess(io::Error),
|
||||
}
|
||||
|
||||
trait DirectReader {
|
||||
pub trait DirectReader {
|
||||
fn line(&mut self) -> Result<String, io::Error>;
|
||||
fn one_byte(&mut self) -> Result<u8, io::Error>;
|
||||
}
|
||||
@ -159,31 +178,112 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn data_to_bytes(data: &VData, stdin: &mut ChildStdin) {
|
||||
pub fn data_to_bytes<T>(data: &VData, stdin: &mut T)
|
||||
where
|
||||
T: Write,
|
||||
{
|
||||
match &data.data {
|
||||
VDataEnum::Bool(false) => write!(stdin, "b").unwrap(),
|
||||
VDataEnum::Bool(true) => write!(stdin, "B").unwrap(),
|
||||
VDataEnum::Int(_) => todo!(),
|
||||
VDataEnum::Float(_) => todo!("floats are not yet implemented for LibFunction calls."),
|
||||
VDataEnum::Int(v) => {
|
||||
let mut v = *v;
|
||||
let mut b = [0u8; 8];
|
||||
for i in (0..8).rev() {
|
||||
b[i] = (v & 0xFF) as _;
|
||||
v >>= 8;
|
||||
}
|
||||
write!(stdin, "1").unwrap();
|
||||
stdin.write(&b).unwrap();
|
||||
}
|
||||
VDataEnum::Float(f) => {
|
||||
writeln!(stdin, "6{f}").unwrap();
|
||||
}
|
||||
VDataEnum::String(s) => {
|
||||
write!(stdin, "\"").unwrap();
|
||||
stdin.write(&(s.len() as u64).to_be_bytes()).unwrap();
|
||||
stdin.write(s.as_bytes()).unwrap();
|
||||
}
|
||||
VDataEnum::Tuple(_) => todo!(),
|
||||
VDataEnum::List(..) => todo!(),
|
||||
VDataEnum::Tuple(v) => {
|
||||
write!(stdin, "t").unwrap();
|
||||
for v in v {
|
||||
write!(stdin, "+").unwrap();
|
||||
data_to_bytes(v, stdin);
|
||||
}
|
||||
writeln!(stdin).unwrap();
|
||||
}
|
||||
VDataEnum::List(_, v) => {
|
||||
write!(stdin, "l").unwrap();
|
||||
for v in v {
|
||||
write!(stdin, "+").unwrap();
|
||||
data_to_bytes(v, stdin);
|
||||
}
|
||||
writeln!(stdin).unwrap();
|
||||
}
|
||||
VDataEnum::Function(..) | VDataEnum::Reference(..) | VDataEnum::Thread(..) => {
|
||||
panic!("cannot use functions, references or threads in LibFunctions.")
|
||||
}
|
||||
VDataEnum::EnumVariant(..) => todo!(),
|
||||
VDataEnum::EnumVariant(e, v) => {
|
||||
stdin
|
||||
.write(
|
||||
['E' as u8]
|
||||
.into_iter()
|
||||
.chain((*e as u64).to_be_bytes().into_iter())
|
||||
.collect::<Vec<u8>>()
|
||||
.as_slice(),
|
||||
)
|
||||
.unwrap();
|
||||
data_to_bytes(v.as_ref(), stdin);
|
||||
}
|
||||
}
|
||||
stdin.flush().unwrap();
|
||||
}
|
||||
fn data_from_bytes(stdout: &mut BufReader<ChildStdout>) -> VDataEnum {
|
||||
match stdout.one_byte().unwrap().into() {
|
||||
pub fn data_from_bytes<T>(stdout: &mut T) -> VDataEnum
|
||||
where
|
||||
T: BufRead,
|
||||
{
|
||||
let id_byte = stdout.one_byte().unwrap().into();
|
||||
match id_byte {
|
||||
'b' => VDataEnum::Bool(false),
|
||||
'B' => VDataEnum::Bool(true),
|
||||
'1' | '2' | '5' | '6' => todo!(),
|
||||
'1' => {
|
||||
let mut num = 0;
|
||||
for _ in 0..8 {
|
||||
num <<= 8;
|
||||
num |= stdout.one_byte().unwrap() as isize;
|
||||
}
|
||||
VDataEnum::Int(num)
|
||||
}
|
||||
'2' => {
|
||||
let mut buf = String::new();
|
||||
stdout.read_line(&mut buf).unwrap();
|
||||
VDataEnum::Int(buf.parse().unwrap())
|
||||
}
|
||||
'5' => {
|
||||
let mut num = 0;
|
||||
for _ in 0..8 {
|
||||
num <<= 8;
|
||||
num |= stdout.one_byte().unwrap() as u64;
|
||||
}
|
||||
VDataEnum::Float(f64::from_bits(num))
|
||||
}
|
||||
'6' => {
|
||||
let mut buf = String::new();
|
||||
stdout.read_line(&mut buf).unwrap();
|
||||
VDataEnum::Float(buf.parse().unwrap())
|
||||
}
|
||||
't' | 'l' => {
|
||||
let mut v = vec![];
|
||||
loop {
|
||||
if stdout.one_byte().unwrap() == '\n' as _ {
|
||||
break if id_byte == 't' {
|
||||
VDataEnum::Tuple(v)
|
||||
} else {
|
||||
VDataEnum::List(VType { types: vec![] }, v)
|
||||
};
|
||||
}
|
||||
v.push(data_from_bytes(stdout).to())
|
||||
}
|
||||
}
|
||||
'"' => {
|
||||
let mut len_bytes = 0u64;
|
||||
for _ in 0..8 {
|
||||
@ -196,6 +296,12 @@ fn data_from_bytes(stdout: &mut BufReader<ChildStdout>) -> VDataEnum {
|
||||
}
|
||||
VDataEnum::String(String::from_utf8_lossy(&buf).into_owned())
|
||||
}
|
||||
_ => todo!(),
|
||||
'E' => {
|
||||
let mut u = [0u8; 8];
|
||||
stdout.read_exact(&mut u).unwrap();
|
||||
let u = u64::from_be_bytes(u) as _;
|
||||
VDataEnum::EnumVariant(u, Box::new(data_from_bytes(stdout).to()))
|
||||
}
|
||||
other => todo!("data_from_bytes: found '{other}'."),
|
||||
}
|
||||
}
|
||||
|
19
src/libs/path.rs
Normal file
19
src/libs/path.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn path_from_string(path: &str, script_directory: &PathBuf) -> Option<PathBuf> {
|
||||
let path = PathBuf::from(path);
|
||||
if path.is_absolute() {
|
||||
return Some(path);
|
||||
}
|
||||
let p = script_directory.join(&path);
|
||||
if p.exists() {
|
||||
return Some(p);
|
||||
}
|
||||
if let Ok(mers_lib_dir) = std::env::var("MERS_LIB_DIR") {
|
||||
let p = PathBuf::from(mers_lib_dir).join(&path);
|
||||
if p.exists() {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
10
src/main.rs
10
src/main.rs
@ -1,12 +1,14 @@
|
||||
use std::time::Instant;
|
||||
|
||||
pub(crate) mod libs;
|
||||
pub(crate) mod parse;
|
||||
pub(crate) mod script;
|
||||
pub mod libs;
|
||||
pub mod parse;
|
||||
pub mod script;
|
||||
|
||||
fn main() {
|
||||
let path = std::env::args().nth(1).unwrap();
|
||||
let script = parse::parse::parse(&mut parse::file::File::new(
|
||||
std::fs::read_to_string(std::env::args().nth(1).unwrap()).unwrap(),
|
||||
std::fs::read_to_string(&path).unwrap(),
|
||||
path.into(),
|
||||
))
|
||||
.unwrap();
|
||||
println!(" - - - - -");
|
||||
|
@ -1,9 +1,11 @@
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{Index, Range, RangeFrom, RangeTo},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
pub struct File {
|
||||
path: PathBuf,
|
||||
data: String,
|
||||
chars: Vec<(usize, char)>,
|
||||
pos: FilePosition,
|
||||
@ -25,7 +27,7 @@ impl Display for FilePosition {
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn new(data: String) -> Self {
|
||||
pub fn new(data: String, path: PathBuf) -> Self {
|
||||
let mut chs = data.chars();
|
||||
let mut data = String::with_capacity(data.len());
|
||||
loop {
|
||||
@ -63,6 +65,7 @@ impl File {
|
||||
}
|
||||
let chars = data.char_indices().collect();
|
||||
Self {
|
||||
path,
|
||||
data,
|
||||
chars,
|
||||
pos: FilePosition {
|
||||
@ -80,6 +83,9 @@ impl File {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
pub fn get_pos(&self) -> &FilePosition {
|
||||
&self.pos
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{path::PathBuf, process::Command, sync::Arc};
|
||||
use std::{process::Command, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
libs,
|
||||
@ -35,17 +35,21 @@ pub enum ParseError {}
|
||||
|
||||
pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||
let mut libs = vec![];
|
||||
let mut enum_variants = GInfo::default_enum_variants();
|
||||
loop {
|
||||
file.skip_whitespaces();
|
||||
let pos = file.get_pos().clone();
|
||||
let line = file.next_line();
|
||||
if line.starts_with("lib ") {
|
||||
let path_to_executable: PathBuf = line[4..].into();
|
||||
let path_to_executable = match libs::path::path_from_string(&line[4..], file.path()) {
|
||||
Some(v) => v,
|
||||
None => panic!("Couldn't find a path for the library with the path '{}'. Maybe set the MERS_LIB_DIR env variable?", &line[4..]),
|
||||
};
|
||||
let mut cmd = Command::new(&path_to_executable);
|
||||
if let Some(parent) = path_to_executable.parent() {
|
||||
cmd.current_dir(parent.clone());
|
||||
}
|
||||
match libs::Lib::launch(cmd) {
|
||||
match libs::Lib::launch(cmd, &mut enum_variants) {
|
||||
Ok(lib) => {
|
||||
libs.push(lib);
|
||||
eprintln!("Loaded library!");
|
||||
@ -72,7 +76,7 @@ pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||
eprintln!("Parsed: {func}");
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Parsed: {func:#?}");
|
||||
let run = to_runnable::to_runnable(func, GInfo::new(Arc::new(libs)))?;
|
||||
let run = to_runnable::to_runnable(func, GInfo::new(Arc::new(libs), enum_variants))?;
|
||||
#[cfg(debug_assertions)]
|
||||
eprintln!("Runnable: {run:#?}");
|
||||
Ok(run)
|
||||
@ -463,10 +467,14 @@ pub(crate) fn parse_type_adv(
|
||||
Some('/') => {
|
||||
file.next();
|
||||
}
|
||||
Some(ch) => {
|
||||
Some(')') => {
|
||||
closed_fn_args = true;
|
||||
file.next();
|
||||
break;
|
||||
}
|
||||
_ => break,
|
||||
Some(_) => break,
|
||||
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
Ok((VType { types }, closed_fn_args))
|
||||
@ -506,6 +514,13 @@ fn parse_single_type_adv(
|
||||
}
|
||||
types.push(parse_type(file)?);
|
||||
}
|
||||
if in_fn_args {
|
||||
file.skip_whitespaces();
|
||||
if let Some(')') = file.peek() {
|
||||
closed_bracket_in_fn_args = true;
|
||||
file.next();
|
||||
}
|
||||
}
|
||||
if types.len() == 1 {
|
||||
VSingleType::List(types.pop().unwrap())
|
||||
} else {
|
||||
@ -529,14 +544,13 @@ fn parse_single_type_adv(
|
||||
VSingleType::EnumVariantS(name, {
|
||||
let po = parse_type_adv(file, true)?;
|
||||
if !po.1 {
|
||||
eprintln!("enum type should be closed by ')', but apparently wasn't?");
|
||||
// eprintln!("enum type should be closed by ')', but apparently wasn't?");
|
||||
assert_eq!(file.next(), Some(')'));
|
||||
}
|
||||
po.0
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
Some(')') if in_fn_args => {
|
||||
closed_bracket_in_fn_args = true;
|
||||
break;
|
||||
@ -550,7 +564,10 @@ fn parse_single_type_adv(
|
||||
"int" => VSingleType::Int,
|
||||
"float" => VSingleType::Float,
|
||||
"string" => VSingleType::String,
|
||||
_ => todo!("Err: Invalid type: \"{}\"", name.trim()),
|
||||
_ => {
|
||||
eprintln!("in_fn_args: {in_fn_args}");
|
||||
todo!("Err: Invalid type: \"{}\"", name.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
None => todo!("Err: EOF in type (1)"),
|
||||
|
@ -87,10 +87,6 @@ fn am<T>(i: T) -> Am<T> {
|
||||
Arc::new(Mutex::new(i))
|
||||
}
|
||||
|
||||
pub fn to_runnable(f: SFunction, ginfo: GInfo) -> Result<RScript, ToRunnableError> {
|
||||
to_runnable::to_runnable(f, ginfo)
|
||||
}
|
||||
|
||||
pub mod to_runnable {
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@ -118,7 +114,6 @@ pub mod to_runnable {
|
||||
found: VType,
|
||||
problematic: Vec<VSingleType>,
|
||||
},
|
||||
InvalidTypeForWhileLoop(VType),
|
||||
CaseForceButTypeNotCovered(VType),
|
||||
MatchConditionInvalidReturn(VType),
|
||||
NotIndexableFixed(VType, usize),
|
||||
@ -145,7 +140,6 @@ pub mod to_runnable {
|
||||
} => {
|
||||
write!(f, "Invalid type: Expected {expected:?} but found {found:?}, which includes {problematic:?}, which is not covered.")
|
||||
}
|
||||
Self::InvalidTypeForWhileLoop(v) => write!(f, "Invalid type: Expected bool or Tuples of length 0 or 1 as return types for the while loop, but found {v:?} instead."),
|
||||
Self::CaseForceButTypeNotCovered(v) => write!(f, "Switch! statement, but not all types covered. Types to cover: {v}"),
|
||||
Self::MatchConditionInvalidReturn(v) => write!(f, "match statement condition returned {v}, which is not necessarily a tuple of size 0 to 1."),
|
||||
Self::NotIndexableFixed(t, i) => write!(f, "Cannot use fixed-index {i} on type {t}."),
|
||||
@ -161,14 +155,17 @@ pub mod to_runnable {
|
||||
enum_variants: HashMap<String, usize>,
|
||||
}
|
||||
impl GInfo {
|
||||
pub fn new(libs: Arc<Vec<libs::Lib>>) -> Self {
|
||||
pub fn default_enum_variants() -> HashMap<String, usize> {
|
||||
builtins::EVS.iter().enumerate().map(|(i, v)| (v.to_string(), i)).collect()
|
||||
}
|
||||
pub fn new(libs: Arc<Vec<libs::Lib>>, enum_variants: HashMap<String, usize>) -> Self {
|
||||
let mut lib_fns = HashMap::new();
|
||||
for (libid, lib) in libs.iter().enumerate() {
|
||||
for (fnid, (name, ..)) in lib.registered_fns.iter().enumerate() {
|
||||
lib_fns.insert(name.to_string(), (libid, fnid));
|
||||
}
|
||||
}
|
||||
Self { vars: 0, libs, lib_fns, enum_variants: builtins::EVS.iter().enumerate().map(|(i, v)| (v.to_string(), i)).collect() }
|
||||
Self { vars: 0, libs, lib_fns, enum_variants }
|
||||
}
|
||||
}
|
||||
// Local, used to keep local variables separated
|
||||
@ -182,13 +179,11 @@ pub mod to_runnable {
|
||||
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
|
||||
return Err(ToRunnableError::MainWrongInput);
|
||||
}
|
||||
if s.inputs[0].1
|
||||
!= (VType {
|
||||
assert_eq!(s.inputs[0].1,VType {
|
||||
types: vec![VSingleType::List(VType {
|
||||
types: vec![VSingleType::String],
|
||||
})],
|
||||
})
|
||||
{}
|
||||
});
|
||||
let func = function(
|
||||
&s,
|
||||
&mut ginfo,
|
||||
|
@ -265,19 +265,7 @@ impl BuiltinFunction {
|
||||
false
|
||||
}
|
||||
}
|
||||
Self::Eq => {
|
||||
if input.len() == 2 {
|
||||
let num = &VType {
|
||||
types: vec![VSingleType::Int, VSingleType::Float],
|
||||
};
|
||||
let string = &VSingleType::String.to();
|
||||
(input[0].fits_in(num).is_empty() && input[1].fits_in(num).is_empty())
|
||||
|| (input[0].fits_in(string).is_empty()
|
||||
&& input[1].fits_in(string).is_empty())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
Self::Eq => input.len() == 2,
|
||||
Self::Add => {
|
||||
input.len() == 2 && {
|
||||
let num = VType {
|
||||
@ -1059,20 +1047,7 @@ impl BuiltinFunction {
|
||||
}
|
||||
Self::Eq => {
|
||||
if args.len() == 2 {
|
||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
||||
(VDataEnum::Int(a), VDataEnum::Int(b)) => VDataEnum::Bool(a == b).to(),
|
||||
(VDataEnum::Int(a), VDataEnum::Float(b)) => {
|
||||
VDataEnum::Bool(a as f64 == b).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Int(b)) => {
|
||||
VDataEnum::Bool(a == b as f64).to()
|
||||
}
|
||||
(VDataEnum::Float(a), VDataEnum::Float(b)) => VDataEnum::Bool(a == b).to(),
|
||||
(VDataEnum::String(a), VDataEnum::String(b)) => {
|
||||
VDataEnum::Bool(a == b).to()
|
||||
}
|
||||
_ => unreachable!("eq: not a number"),
|
||||
}
|
||||
VDataEnum::Bool(args[0].run(vars, libs) == args[1].run(vars, libs)).to()
|
||||
} else {
|
||||
unreachable!("eq: not 2 args")
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use super::{
|
||||
val_type::{VSingleType, VType},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct VData {
|
||||
// parents: Vec<()>,
|
||||
pub data: VDataEnum,
|
||||
@ -29,6 +29,24 @@ pub enum VDataEnum {
|
||||
Reference(Arc<Mutex<VData>>),
|
||||
EnumVariant(usize, Box<VData>),
|
||||
}
|
||||
impl PartialEq for VDataEnum {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Reference(a), Self::Reference(b)) => *a.lock().unwrap() == *b.lock().unwrap(),
|
||||
(Self::Reference(a), b) => a.lock().unwrap().data == *b,
|
||||
(a, Self::Reference(b)) => *a == b.lock().unwrap().data,
|
||||
(Self::Bool(a), Self::Bool(b)) => *a == *b,
|
||||
(Self::Int(a), Self::Int(b)) => *a == *b,
|
||||
(Self::Float(a), Self::Float(b)) => *a == *b,
|
||||
(Self::String(a), Self::String(b)) => *a == *b,
|
||||
(Self::Tuple(a), Self::Tuple(b)) | (Self::List(_, a), Self::List(_, b)) => {
|
||||
a.len() == b.len() && a.iter().zip(b.iter()).all(|(a, b)| a == b)
|
||||
}
|
||||
(Self::EnumVariant(a1, a2), Self::EnumVariant(b1, b2)) => *a1 == *b1 && *a2 == *b2,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VData {
|
||||
pub fn out(&self) -> VType {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{fmt::Debug, ops::BitOr};
|
||||
use std::{collections::HashMap, fmt::Debug, ops::BitOr};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VType {
|
||||
@ -87,6 +87,11 @@ impl VType {
|
||||
}
|
||||
out
|
||||
}
|
||||
pub fn enum_variants(&mut self, enum_variants: &mut HashMap<String, usize>) {
|
||||
for t in &mut self.types {
|
||||
t.enum_variants(enum_variants);
|
||||
}
|
||||
}
|
||||
pub fn contains(&self, t: &VSingleType) -> bool {
|
||||
self.types.contains(t)
|
||||
}
|
||||
@ -154,6 +159,39 @@ impl VSingleType {
|
||||
v => v.to(),
|
||||
}
|
||||
}
|
||||
pub fn enum_variants(&mut self, enum_variants: &mut HashMap<String, usize>) {
|
||||
match self {
|
||||
Self::Bool | Self::Int | Self::Float | Self::String => (),
|
||||
Self::Tuple(v) => {
|
||||
for t in v {
|
||||
t.enum_variants(enum_variants);
|
||||
}
|
||||
}
|
||||
Self::List(t) => t.enum_variants(enum_variants),
|
||||
Self::Function(f) => {
|
||||
for f in f {
|
||||
for t in &mut f.0 {
|
||||
t.enum_variants(enum_variants);
|
||||
}
|
||||
f.1.enum_variants(enum_variants);
|
||||
}
|
||||
}
|
||||
Self::Thread(v) => v.enum_variants(enum_variants),
|
||||
Self::Reference(v) => v.enum_variants(enum_variants),
|
||||
Self::EnumVariant(_e, v) => v.enum_variants(enum_variants),
|
||||
Self::EnumVariantS(e, v) => {
|
||||
let e = if let Some(e) = enum_variants.get(e) {
|
||||
*e
|
||||
} else {
|
||||
let v = enum_variants.len();
|
||||
enum_variants.insert(e.clone(), v);
|
||||
v
|
||||
};
|
||||
v.enum_variants(enum_variants);
|
||||
*self = Self::EnumVariant(e, v.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn fits_in(&self, rhs: &Self) -> bool {
|
||||
match (self, rhs) {
|
||||
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b),
|
||||
|
Loading…
Reference in New Issue
Block a user