Fix parsing bug; Extend GUI

This commit is contained in:
Jeff 2023-12-30 12:02:58 -05:00
parent 6cb84a664a
commit 9a35dc5ec9
7 changed files with 95 additions and 42 deletions

10
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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());
let read_source = read_to_string(&path);
let source = if let Ok(source) = read_source {
source
} else {
String::new()
};
let output = interpreter.run(&source);
cc.egui_ctx.set_zoom_factor(1.5); App {
path: path.to_string_lossy().to_string(),
source,
context,
interpreter,
output,
}
}
let app = App { if path.is_file() {
source, create_app(path)
output: Ok(Value::default()),
};
if let Some(storage) = cc.storage {
return eframe::get_value(storage, eframe::APP_KEY).unwrap_or(app);
} else { } else {
app 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,28 +65,37 @@ 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(),
Err(error) => error.to_string(), Err(error) => error.to_string(),
}; };
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");
}); });
}); });
} }

View File

@ -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))),
) )
} }

View File

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

View File

@ -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);

View File

@ -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]