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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "mers"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1.7.2"
|
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: (),
|
||||||
|
}
|
152
src/libs/mod.rs
152
src/libs/mod.rs
@ -1,5 +1,10 @@
|
|||||||
|
pub mod inlib;
|
||||||
|
pub mod path;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
io::{self, BufRead, BufReader, Read, Write},
|
io::{self, BufRead, BufReader, Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
process::{Child, ChildStdin, ChildStdout, Command, Stdio},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
@ -55,7 +60,10 @@ pub struct Lib {
|
|||||||
pub registered_fns: Vec<(String, Vec<VType>, VType)>,
|
pub registered_fns: Vec<(String, Vec<VType>, VType)>,
|
||||||
}
|
}
|
||||||
impl Lib {
|
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
|
let mut handle = match exec
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
@ -92,22 +100,33 @@ impl Lib {
|
|||||||
let (name, args) = line[1..]
|
let (name, args) = line[1..]
|
||||||
.split_once('(')
|
.split_once('(')
|
||||||
.expect("function signature didn't include the ( character.");
|
.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![];
|
let mut fn_in = vec![];
|
||||||
loop {
|
fn_signature.skip_whitespaces();
|
||||||
let t = parse::parse_type_adv(&mut fn_signature, true).unwrap();
|
if let Some(')') = fn_signature.peek() {
|
||||||
fn_in.push(t.0);
|
fn_signature.next();
|
||||||
if t.1 {
|
} else {
|
||||||
break;
|
loop {
|
||||||
|
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();
|
let mut 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..]);
|
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));
|
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 {
|
Ok(Self {
|
||||||
process: handle,
|
process: handle,
|
||||||
stdin: Arc::new(Mutex::new(stdin)),
|
stdin: Arc::new(Mutex::new(stdin)),
|
||||||
@ -126,9 +145,9 @@ impl Lib {
|
|||||||
write!(stdin, "f").unwrap();
|
write!(stdin, "f").unwrap();
|
||||||
stdin.write(&[fnid as _]).unwrap();
|
stdin.write(&[fnid as _]).unwrap();
|
||||||
for (_i, arg) in args.iter().enumerate() {
|
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
|
o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +158,7 @@ pub enum LaunchError {
|
|||||||
CouldNotSpawnProcess(io::Error),
|
CouldNotSpawnProcess(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
trait DirectReader {
|
pub trait DirectReader {
|
||||||
fn line(&mut self) -> Result<String, io::Error>;
|
fn line(&mut self) -> Result<String, io::Error>;
|
||||||
fn one_byte(&mut self) -> Result<u8, 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 {
|
match &data.data {
|
||||||
VDataEnum::Bool(false) => write!(stdin, "b").unwrap(),
|
VDataEnum::Bool(false) => write!(stdin, "b").unwrap(),
|
||||||
VDataEnum::Bool(true) => write!(stdin, "B").unwrap(),
|
VDataEnum::Bool(true) => write!(stdin, "B").unwrap(),
|
||||||
VDataEnum::Int(_) => todo!(),
|
VDataEnum::Int(v) => {
|
||||||
VDataEnum::Float(_) => todo!("floats are not yet implemented for LibFunction calls."),
|
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) => {
|
VDataEnum::String(s) => {
|
||||||
write!(stdin, "\"").unwrap();
|
write!(stdin, "\"").unwrap();
|
||||||
stdin.write(&(s.len() as u64).to_be_bytes()).unwrap();
|
stdin.write(&(s.len() as u64).to_be_bytes()).unwrap();
|
||||||
stdin.write(s.as_bytes()).unwrap();
|
stdin.write(s.as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
VDataEnum::Tuple(_) => todo!(),
|
VDataEnum::Tuple(v) => {
|
||||||
VDataEnum::List(..) => todo!(),
|
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(..) => {
|
VDataEnum::Function(..) | VDataEnum::Reference(..) | VDataEnum::Thread(..) => {
|
||||||
panic!("cannot use functions, references or threads in LibFunctions.")
|
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();
|
stdin.flush().unwrap();
|
||||||
}
|
}
|
||||||
fn data_from_bytes(stdout: &mut BufReader<ChildStdout>) -> VDataEnum {
|
pub fn data_from_bytes<T>(stdout: &mut T) -> VDataEnum
|
||||||
match stdout.one_byte().unwrap().into() {
|
where
|
||||||
|
T: BufRead,
|
||||||
|
{
|
||||||
|
let id_byte = stdout.one_byte().unwrap().into();
|
||||||
|
match id_byte {
|
||||||
'b' => VDataEnum::Bool(false),
|
'b' => VDataEnum::Bool(false),
|
||||||
'B' => VDataEnum::Bool(true),
|
'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;
|
let mut len_bytes = 0u64;
|
||||||
for _ in 0..8 {
|
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())
|
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;
|
use std::time::Instant;
|
||||||
|
|
||||||
pub(crate) mod libs;
|
pub mod libs;
|
||||||
pub(crate) mod parse;
|
pub mod parse;
|
||||||
pub(crate) mod script;
|
pub mod script;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let path = std::env::args().nth(1).unwrap();
|
||||||
let script = parse::parse::parse(&mut parse::file::File::new(
|
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();
|
.unwrap();
|
||||||
println!(" - - - - -");
|
println!(" - - - - -");
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
ops::{Index, Range, RangeFrom, RangeTo},
|
ops::{Index, Range, RangeFrom, RangeTo},
|
||||||
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
|
path: PathBuf,
|
||||||
data: String,
|
data: String,
|
||||||
chars: Vec<(usize, char)>,
|
chars: Vec<(usize, char)>,
|
||||||
pos: FilePosition,
|
pos: FilePosition,
|
||||||
@ -25,7 +27,7 @@ impl Display for FilePosition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
pub fn new(data: String) -> Self {
|
pub fn new(data: String, path: PathBuf) -> Self {
|
||||||
let mut chs = data.chars();
|
let mut chs = data.chars();
|
||||||
let mut data = String::with_capacity(data.len());
|
let mut data = String::with_capacity(data.len());
|
||||||
loop {
|
loop {
|
||||||
@ -63,6 +65,7 @@ impl File {
|
|||||||
}
|
}
|
||||||
let chars = data.char_indices().collect();
|
let chars = data.char_indices().collect();
|
||||||
Self {
|
Self {
|
||||||
|
path,
|
||||||
data,
|
data,
|
||||||
chars,
|
chars,
|
||||||
pos: FilePosition {
|
pos: FilePosition {
|
||||||
@ -80,6 +83,9 @@ impl File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn path(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
pub fn get_pos(&self) -> &FilePosition {
|
pub fn get_pos(&self) -> &FilePosition {
|
||||||
&self.pos
|
&self.pos
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{path::PathBuf, process::Command, sync::Arc};
|
use std::{process::Command, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
libs,
|
libs,
|
||||||
@ -35,17 +35,21 @@ pub enum ParseError {}
|
|||||||
|
|
||||||
pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
||||||
let mut libs = vec![];
|
let mut libs = vec![];
|
||||||
|
let mut enum_variants = GInfo::default_enum_variants();
|
||||||
loop {
|
loop {
|
||||||
file.skip_whitespaces();
|
file.skip_whitespaces();
|
||||||
let pos = file.get_pos().clone();
|
let pos = file.get_pos().clone();
|
||||||
let line = file.next_line();
|
let line = file.next_line();
|
||||||
if line.starts_with("lib ") {
|
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);
|
let mut cmd = Command::new(&path_to_executable);
|
||||||
if let Some(parent) = path_to_executable.parent() {
|
if let Some(parent) = path_to_executable.parent() {
|
||||||
cmd.current_dir(parent.clone());
|
cmd.current_dir(parent.clone());
|
||||||
}
|
}
|
||||||
match libs::Lib::launch(cmd) {
|
match libs::Lib::launch(cmd, &mut enum_variants) {
|
||||||
Ok(lib) => {
|
Ok(lib) => {
|
||||||
libs.push(lib);
|
libs.push(lib);
|
||||||
eprintln!("Loaded library!");
|
eprintln!("Loaded library!");
|
||||||
@ -72,7 +76,7 @@ pub fn parse(file: &mut File) -> Result<RScript, ScriptError> {
|
|||||||
eprintln!("Parsed: {func}");
|
eprintln!("Parsed: {func}");
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
eprintln!("Parsed: {func:#?}");
|
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)]
|
#[cfg(debug_assertions)]
|
||||||
eprintln!("Runnable: {run:#?}");
|
eprintln!("Runnable: {run:#?}");
|
||||||
Ok(run)
|
Ok(run)
|
||||||
@ -463,10 +467,14 @@ pub(crate) fn parse_type_adv(
|
|||||||
Some('/') => {
|
Some('/') => {
|
||||||
file.next();
|
file.next();
|
||||||
}
|
}
|
||||||
Some(ch) => {
|
Some(')') => {
|
||||||
|
closed_fn_args = true;
|
||||||
|
file.next();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => break,
|
Some(_) => break,
|
||||||
|
|
||||||
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((VType { types }, closed_fn_args))
|
Ok((VType { types }, closed_fn_args))
|
||||||
@ -506,6 +514,13 @@ fn parse_single_type_adv(
|
|||||||
}
|
}
|
||||||
types.push(parse_type(file)?);
|
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 {
|
if types.len() == 1 {
|
||||||
VSingleType::List(types.pop().unwrap())
|
VSingleType::List(types.pop().unwrap())
|
||||||
} else {
|
} else {
|
||||||
@ -529,14 +544,13 @@ fn parse_single_type_adv(
|
|||||||
VSingleType::EnumVariantS(name, {
|
VSingleType::EnumVariantS(name, {
|
||||||
let po = parse_type_adv(file, true)?;
|
let po = parse_type_adv(file, true)?;
|
||||||
if !po.1 {
|
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(')'));
|
assert_eq!(file.next(), Some(')'));
|
||||||
}
|
}
|
||||||
po.0
|
po.0
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(')') if in_fn_args => {
|
Some(')') if in_fn_args => {
|
||||||
closed_bracket_in_fn_args = true;
|
closed_bracket_in_fn_args = true;
|
||||||
break;
|
break;
|
||||||
@ -550,7 +564,10 @@ fn parse_single_type_adv(
|
|||||||
"int" => VSingleType::Int,
|
"int" => VSingleType::Int,
|
||||||
"float" => VSingleType::Float,
|
"float" => VSingleType::Float,
|
||||||
"string" => VSingleType::String,
|
"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)"),
|
None => todo!("Err: EOF in type (1)"),
|
||||||
|
@ -87,10 +87,6 @@ fn am<T>(i: T) -> Am<T> {
|
|||||||
Arc::new(Mutex::new(i))
|
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 {
|
pub mod to_runnable {
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -118,7 +114,6 @@ pub mod to_runnable {
|
|||||||
found: VType,
|
found: VType,
|
||||||
problematic: Vec<VSingleType>,
|
problematic: Vec<VSingleType>,
|
||||||
},
|
},
|
||||||
InvalidTypeForWhileLoop(VType),
|
|
||||||
CaseForceButTypeNotCovered(VType),
|
CaseForceButTypeNotCovered(VType),
|
||||||
MatchConditionInvalidReturn(VType),
|
MatchConditionInvalidReturn(VType),
|
||||||
NotIndexableFixed(VType, usize),
|
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.")
|
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::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::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}."),
|
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>,
|
enum_variants: HashMap<String, usize>,
|
||||||
}
|
}
|
||||||
impl GInfo {
|
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();
|
let mut lib_fns = HashMap::new();
|
||||||
for (libid, lib) in libs.iter().enumerate() {
|
for (libid, lib) in libs.iter().enumerate() {
|
||||||
for (fnid, (name, ..)) in lib.registered_fns.iter().enumerate() {
|
for (fnid, (name, ..)) in lib.registered_fns.iter().enumerate() {
|
||||||
lib_fns.insert(name.to_string(), (libid, fnid));
|
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
|
// 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" {
|
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
|
||||||
return Err(ToRunnableError::MainWrongInput);
|
return Err(ToRunnableError::MainWrongInput);
|
||||||
}
|
}
|
||||||
if s.inputs[0].1
|
assert_eq!(s.inputs[0].1,VType {
|
||||||
!= (VType {
|
types: vec![VSingleType::List(VType {
|
||||||
types: vec![VSingleType::List(VType {
|
types: vec![VSingleType::String],
|
||||||
types: vec![VSingleType::String],
|
})],
|
||||||
})],
|
});
|
||||||
})
|
|
||||||
{}
|
|
||||||
let func = function(
|
let func = function(
|
||||||
&s,
|
&s,
|
||||||
&mut ginfo,
|
&mut ginfo,
|
||||||
|
@ -265,19 +265,7 @@ impl BuiltinFunction {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::Eq => {
|
Self::Eq => input.len() == 2,
|
||||||
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::Add => {
|
Self::Add => {
|
||||||
input.len() == 2 && {
|
input.len() == 2 && {
|
||||||
let num = VType {
|
let num = VType {
|
||||||
@ -1059,20 +1047,7 @@ impl BuiltinFunction {
|
|||||||
}
|
}
|
||||||
Self::Eq => {
|
Self::Eq => {
|
||||||
if args.len() == 2 {
|
if args.len() == 2 {
|
||||||
match (args[0].run(vars, libs).data, args[1].run(vars, libs).data) {
|
VDataEnum::Bool(args[0].run(vars, libs) == args[1].run(vars, libs)).to()
|
||||||
(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"),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!("eq: not 2 args")
|
unreachable!("eq: not 2 args")
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use super::{
|
|||||||
val_type::{VSingleType, VType},
|
val_type::{VSingleType, VType},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct VData {
|
pub struct VData {
|
||||||
// parents: Vec<()>,
|
// parents: Vec<()>,
|
||||||
pub data: VDataEnum,
|
pub data: VDataEnum,
|
||||||
@ -29,6 +29,24 @@ pub enum VDataEnum {
|
|||||||
Reference(Arc<Mutex<VData>>),
|
Reference(Arc<Mutex<VData>>),
|
||||||
EnumVariant(usize, Box<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 {
|
impl VData {
|
||||||
pub fn out(&self) -> VType {
|
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)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct VType {
|
pub struct VType {
|
||||||
@ -87,6 +87,11 @@ impl VType {
|
|||||||
}
|
}
|
||||||
out
|
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 {
|
pub fn contains(&self, t: &VSingleType) -> bool {
|
||||||
self.types.contains(t)
|
self.types.contains(t)
|
||||||
}
|
}
|
||||||
@ -154,6 +159,39 @@ impl VSingleType {
|
|||||||
v => v.to(),
|
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 {
|
pub fn fits_in(&self, rhs: &Self) -> bool {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b),
|
(Self::Reference(r), Self::Reference(b)) => r.fits_in(b),
|
||||||
|
Loading…
Reference in New Issue
Block a user