Fix parsing bug; Extend GUI
This commit is contained in:
parent
6cb84a664a
commit
9a35dc5ec9
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -89,6 +89,15 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
@ -560,6 +569,7 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
|||||||
name = "dust-lang"
|
name = "dust-lang"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
"cc",
|
"cc",
|
||||||
"clap",
|
"clap",
|
||||||
"csv",
|
"csv",
|
||||||
|
@ -35,6 +35,7 @@ eframe = { version = "0.24.1", default-features = false, features = [
|
|||||||
"glow", # Use the glow rendering backend. Alternative: "wgpu".
|
"glow", # Use the glow rendering backend. Alternative: "wgpu".
|
||||||
"persistence", # Enable restoring app state when restarting the app.
|
"persistence", # Enable restoring app state when restarting the app.
|
||||||
] }
|
] }
|
||||||
|
ansi_term = "0.12.1"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
@ -1,28 +1,50 @@
|
|||||||
use dust_lang::{interpret, Result, Value};
|
use std::{fs::read_to_string, path::PathBuf};
|
||||||
|
|
||||||
|
use dust_lang::{Interpreter, Map, Result, Value};
|
||||||
|
use egui::{Align, Layout};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
path: String,
|
||||||
source: String,
|
source: String,
|
||||||
|
context: Map,
|
||||||
|
#[serde(skip)]
|
||||||
|
interpreter: Interpreter,
|
||||||
output: Result<Value>,
|
output: Result<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(cc: &eframe::CreationContext<'_>, source: String) -> Self {
|
pub fn new(cc: &eframe::CreationContext<'_>, path: PathBuf) -> Self {
|
||||||
// This is also where you can customize the look and feel of egui using
|
fn create_app(path: PathBuf) -> App {
|
||||||
// `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
|
let context = Map::new();
|
||||||
|
let mut interpreter = Interpreter::new(context.clone());
|
||||||
cc.egui_ctx.set_zoom_factor(1.5);
|
let read_source = read_to_string(&path);
|
||||||
|
let source = if let Ok(source) = read_source {
|
||||||
let app = App {
|
source
|
||||||
source,
|
|
||||||
output: Ok(Value::default()),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(storage) = cc.storage {
|
|
||||||
return eframe::get_value(storage, eframe::APP_KEY).unwrap_or(app);
|
|
||||||
} else {
|
} else {
|
||||||
app
|
String::new()
|
||||||
|
};
|
||||||
|
let output = interpreter.run(&source);
|
||||||
|
|
||||||
|
App {
|
||||||
|
path: path.to_string_lossy().to_string(),
|
||||||
|
source,
|
||||||
|
context,
|
||||||
|
interpreter,
|
||||||
|
output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.is_file() {
|
||||||
|
create_app(path)
|
||||||
|
} else {
|
||||||
|
if let Some(storage) = cc.storage {
|
||||||
|
return eframe::get_value(storage, eframe::APP_KEY)
|
||||||
|
.unwrap_or_else(|| create_app(path));
|
||||||
|
} else {
|
||||||
|
create_app(path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,17 +65,30 @@ impl eframe::App for App {
|
|||||||
ui.add_space(16.0);
|
ui.add_space(16.0);
|
||||||
|
|
||||||
egui::widgets::global_dark_light_mode_buttons(ui);
|
egui::widgets::global_dark_light_mode_buttons(ui);
|
||||||
|
|
||||||
|
ui.with_layout(Layout::right_to_left(Align::Max), |ui| {
|
||||||
|
egui::warn_if_debug_build(ui);
|
||||||
|
ui.hyperlink_to("source code", "https://git.jeffa.io/jeff/dust");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.code_editor(&mut self.source);
|
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
|
||||||
|
ui.with_layout(Layout::top_down(Align::Min).with_main_justify(true), |ui| {
|
||||||
|
ui.with_layout(Layout::left_to_right(Align::Min), |ui| {
|
||||||
|
ui.text_edit_singleline(&mut self.path);
|
||||||
|
|
||||||
if ui.button("run").clicked() {
|
if ui.button("read").clicked() {
|
||||||
self.output = interpret(&self.source);
|
self.source = read_to_string(&self.path).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.separator();
|
if ui.button("run").clicked() {
|
||||||
|
self.output = self.interpreter.run(&self.source);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ui.code_editor(&mut self.source);
|
||||||
|
});
|
||||||
|
|
||||||
let output_text = match &self.output {
|
let output_text = match &self.output {
|
||||||
Ok(value) => value.to_string(),
|
Ok(value) => value.to_string(),
|
||||||
@ -61,10 +96,6 @@ impl eframe::App for App {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ui.label(output_text);
|
ui.label(output_text);
|
||||||
|
|
||||||
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
|
|
||||||
egui::warn_if_debug_build(ui);
|
|
||||||
ui.hyperlink_to("source code", "https://git.jeffa.io/jeff/dust");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
use std::{fs::read_to_string, path::PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
@ -9,14 +9,17 @@ mod app;
|
|||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct Args {
|
struct Args {
|
||||||
// Path to the file to read.
|
// Path to the file to read.
|
||||||
path: PathBuf,
|
path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> eframe::Result<()> {
|
fn main() -> eframe::Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let path = Args::parse().path;
|
let path = if let Some(path) = Args::parse().path {
|
||||||
let source = read_to_string(&path).unwrap();
|
path
|
||||||
|
} else {
|
||||||
|
PathBuf::new()
|
||||||
|
};
|
||||||
let native_options = eframe::NativeOptions {
|
let native_options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default()
|
viewport: egui::ViewportBuilder::default()
|
||||||
.with_inner_size([400.0, 300.0])
|
.with_inner_size([400.0, 300.0])
|
||||||
@ -27,6 +30,6 @@ fn main() -> eframe::Result<()> {
|
|||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"Dust GUI",
|
"Dust GUI",
|
||||||
native_options,
|
native_options,
|
||||||
Box::new(|cc| Box::new(app::App::new(cc, source))),
|
Box::new(|cc| Box::new(app::App::new(cc, path))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ pub fn interpret(source: &str) -> Result<Value> {
|
|||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn interpret_with_context(source: &str, context: Map) -> Result<Value> {
|
pub fn interpret_with_context(source: &str, context: Map) -> Result<Value> {
|
||||||
let mut interpreter = Interpreter::new(context)?;
|
let mut interpreter = Interpreter::new(context);
|
||||||
let value = interpreter.run(source)?;
|
let value = interpreter.run(source)?;
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
@ -56,25 +56,27 @@ pub struct Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn new(context: Map) -> Result<Self> {
|
pub fn new(context: Map) -> Self {
|
||||||
let mut parser = Parser::new();
|
let mut parser = Parser::new();
|
||||||
|
|
||||||
parser.set_language(language())?;
|
parser
|
||||||
|
.set_language(language())
|
||||||
|
.expect("Language version is incompatible with tree sitter version.");
|
||||||
|
|
||||||
Ok(Interpreter {
|
Interpreter {
|
||||||
parser,
|
parser,
|
||||||
context,
|
context,
|
||||||
syntax_tree: None,
|
syntax_tree: None,
|
||||||
abstract_tree: None,
|
abstract_tree: None,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_only(&mut self, source: &str) {
|
pub fn parse_only(&mut self, source: &str) {
|
||||||
self.syntax_tree = self.parser.parse(source, self.syntax_tree.as_ref());
|
self.syntax_tree = self.parser.parse(source, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, source: &str) -> Result<Value> {
|
pub fn run(&mut self, source: &str) -> Result<Value> {
|
||||||
self.syntax_tree = self.parser.parse(source, self.syntax_tree.as_ref());
|
self.syntax_tree = self.parser.parse(source, None);
|
||||||
self.abstract_tree = if let Some(syntax_tree) = &self.syntax_tree {
|
self.abstract_tree = if let Some(syntax_tree) = &self.syntax_tree {
|
||||||
Some(Root::from_syntax_node(
|
Some(Root::from_syntax_node(
|
||||||
source,
|
source,
|
||||||
@ -100,3 +102,9 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Interpreter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Interpreter::new(Map::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -72,7 +72,7 @@ fn main() {
|
|||||||
let mut parser = TSParser::new();
|
let mut parser = TSParser::new();
|
||||||
parser.set_language(language()).unwrap();
|
parser.set_language(language()).unwrap();
|
||||||
|
|
||||||
let mut interpreter = Interpreter::new(context).unwrap();
|
let mut interpreter = Interpreter::new(context);
|
||||||
|
|
||||||
if args.show_syntax_tree {
|
if args.show_syntax_tree {
|
||||||
interpreter.parse_only(&source);
|
interpreter.parse_only(&source);
|
||||||
|
@ -154,7 +154,7 @@ mod value {
|
|||||||
let function = value.as_function().unwrap();
|
let function = value.as_function().unwrap();
|
||||||
|
|
||||||
assert_eq!(&Vec::<Identifier>::with_capacity(0), function.parameters());
|
assert_eq!(&Vec::<Identifier>::with_capacity(0), function.parameters());
|
||||||
assert_eq!(Ok(&Type::Integer), function.return_type());
|
assert_eq!(&Type::Integer, function.return_type());
|
||||||
|
|
||||||
let result = interpret("(x <bool>) -> <bool> {true}");
|
let result = interpret("(x <bool>) -> <bool> {true}");
|
||||||
let value = result.unwrap();
|
let value = result.unwrap();
|
||||||
@ -164,7 +164,7 @@ mod value {
|
|||||||
&vec![Identifier::new("x".to_string())],
|
&vec![Identifier::new("x".to_string())],
|
||||||
function.parameters()
|
function.parameters()
|
||||||
);
|
);
|
||||||
assert_eq!(Ok(&Type::Boolean), function.return_type());
|
assert_eq!(&Type::Boolean, function.return_type());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user