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"
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]]
name = "anstream"
version = "0.6.5"
@ -560,6 +569,7 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
name = "dust-lang"
version = "0.4.0"
dependencies = [
"ansi_term",
"cc",
"clap",
"csv",

View File

@ -35,6 +35,7 @@ eframe = { version = "0.24.1", default-features = false, features = [
"glow", # Use the glow rendering backend. Alternative: "wgpu".
"persistence", # Enable restoring app state when restarting the app.
] }
ansi_term = "0.12.1"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
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};
#[derive(Deserialize, Serialize)]
pub struct App {
path: String,
source: String,
context: Map,
#[serde(skip)]
interpreter: Interpreter,
output: Result<Value>,
}
impl App {
pub fn new(cc: &eframe::CreationContext<'_>, source: String) -> Self {
// This is also where you can customize the look and feel of egui using
// `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.
cc.egui_ctx.set_zoom_factor(1.5);
let app = App {
source,
output: Ok(Value::default()),
};
if let Some(storage) = cc.storage {
return eframe::get_value(storage, eframe::APP_KEY).unwrap_or(app);
pub fn new(cc: &eframe::CreationContext<'_>, path: PathBuf) -> Self {
fn create_app(path: PathBuf) -> App {
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 {
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);
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| {
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() {
self.output = interpret(&self.source);
if ui.button("read").clicked() {
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 {
Ok(value) => value.to_string(),
@ -61,10 +96,6 @@ impl eframe::App for App {
};
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")]
use std::{fs::read_to_string, path::PathBuf};
use std::path::PathBuf;
use clap::Parser;
@ -9,14 +9,17 @@ mod app;
#[derive(Parser)]
struct Args {
// Path to the file to read.
path: PathBuf,
path: Option<PathBuf>,
}
fn main() -> eframe::Result<()> {
env_logger::init();
let path = Args::parse().path;
let source = read_to_string(&path).unwrap();
let path = if let Some(path) = Args::parse().path {
path
} else {
PathBuf::new()
};
let native_options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([400.0, 300.0])
@ -27,6 +30,6 @@ fn main() -> eframe::Result<()> {
eframe::run_native(
"Dust GUI",
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> {
let mut interpreter = Interpreter::new(context)?;
let mut interpreter = Interpreter::new(context);
let value = interpreter.run(source)?;
Ok(value)
@ -56,25 +56,27 @@ pub struct Interpreter {
}
impl Interpreter {
pub fn new(context: Map) -> Result<Self> {
pub fn new(context: Map) -> Self {
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,
context,
syntax_tree: None,
abstract_tree: None,
})
}
}
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> {
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 {
Some(Root::from_syntax_node(
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();
parser.set_language(language()).unwrap();
let mut interpreter = Interpreter::new(context).unwrap();
let mut interpreter = Interpreter::new(context);
if args.show_syntax_tree {
interpreter.parse_only(&source);

View File

@ -154,7 +154,7 @@ mod value {
let function = value.as_function().unwrap();
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 value = result.unwrap();
@ -164,7 +164,7 @@ mod value {
&vec![Identifier::new("x".to_string())],
function.parameters()
);
assert_eq!(Ok(&Type::Boolean), function.return_type());
assert_eq!(&Type::Boolean, function.return_type());
}
#[test]