Modify library for new parser
This commit is contained in:
parent
5fed0984a7
commit
589d66a90f
5033
Cargo.lock
generated
5033
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
46
Cargo.toml
46
Cargo.toml
@ -1,46 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "dust-lang"
|
|
||||||
version = "0.1.2"
|
|
||||||
description = "Data-oriented programming language and interactive shell."
|
|
||||||
authors = ["jeff <dev@jeffa.io.com>"]
|
|
||||||
repository = "https://git.jeffa.io/jeff/dust.git"
|
|
||||||
homepage = "https://git.jeffa.io/jeff/dust"
|
|
||||||
readme = "README.md"
|
|
||||||
license = "MIT"
|
|
||||||
edition = "2018"
|
|
||||||
default-run = "dust"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "dust"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "gui"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "dust_lib"
|
|
||||||
path = "src/lib.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
rand = "0.8.5"
|
|
||||||
chrono = "0.4.26"
|
|
||||||
trash = "3.0.3"
|
|
||||||
rayon = "1.7.0"
|
|
||||||
serde = { version = "1.0.171", features = ["derive"] }
|
|
||||||
sysinfo = "0.29.6"
|
|
||||||
toml = "0.7.6"
|
|
||||||
toml_edit = "0.19.14"
|
|
||||||
comfy-table = "7.0.1"
|
|
||||||
clap = { version = "4.3.19", features = ["derive"] }
|
|
||||||
git2 = "0.17.2"
|
|
||||||
csv = "1.2.2"
|
|
||||||
json = "0.12.4"
|
|
||||||
reqwest = { version = "0.11.18", features = ["blocking", "json"] }
|
|
||||||
serde_json = "1.0.104"
|
|
||||||
egui_extras = "0.22.0"
|
|
||||||
rustyline = { version = "12.0.0", features = ["with-file-history", "derive"] }
|
|
||||||
ansi_term = "0.12.1"
|
|
||||||
iced = "0.10.0"
|
|
||||||
egui = "0.22.0"
|
|
||||||
eframe = "0.22.0"
|
|
||||||
env_logger = "0.10.0"
|
|
||||||
once_cell = "1.18.0"
|
|
40
build.rs
Normal file
40
build.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
fn main() {
|
||||||
|
let src_dir = std::path::Path::new("src");
|
||||||
|
|
||||||
|
let mut c_config = cc::Build::new();
|
||||||
|
c_config.include(&src_dir);
|
||||||
|
c_config
|
||||||
|
.flag_if_supported("-Wno-unused-parameter")
|
||||||
|
.flag_if_supported("-Wno-unused-but-set-variable")
|
||||||
|
.flag_if_supported("-Wno-trigraphs");
|
||||||
|
let parser_path = src_dir.join("parser.c");
|
||||||
|
c_config.file(&parser_path);
|
||||||
|
|
||||||
|
// If your language uses an external scanner written in C,
|
||||||
|
// then include this block of code:
|
||||||
|
|
||||||
|
/*
|
||||||
|
let scanner_path = src_dir.join("scanner.c");
|
||||||
|
c_config.file(&scanner_path);
|
||||||
|
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
|
||||||
|
*/
|
||||||
|
|
||||||
|
c_config.compile("parser");
|
||||||
|
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
|
||||||
|
|
||||||
|
// If your language uses an external scanner written in C++,
|
||||||
|
// then include this block of code:
|
||||||
|
|
||||||
|
/*
|
||||||
|
let mut cpp_config = cc::Build::new();
|
||||||
|
cpp_config.cpp(true);
|
||||||
|
cpp_config.include(&src_dir);
|
||||||
|
cpp_config
|
||||||
|
.flag_if_supported("-Wno-unused-parameter")
|
||||||
|
.flag_if_supported("-Wno-unused-but-set-variable");
|
||||||
|
let scanner_path = src_dir.join("scanner.cc");
|
||||||
|
cpp_config.file(&scanner_path);
|
||||||
|
cpp_config.compile("scanner");
|
||||||
|
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
|
||||||
|
*/
|
||||||
|
}
|
@ -1,88 +0,0 @@
|
|||||||
use dust_lib::eval;
|
|
||||||
use iced::widget::{column, container, text_input, Column};
|
|
||||||
use iced::{executor, Application, Command, Element, Settings, Theme};
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
static INPUT_ID: Lazy<text_input::Id> = Lazy::new(text_input::Id::unique);
|
|
||||||
|
|
||||||
pub fn main() -> iced::Result {
|
|
||||||
DustGui::run(Settings::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DustGui {
|
|
||||||
text_buffer: String,
|
|
||||||
results: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Application for DustGui {
|
|
||||||
type Executor = executor::Default;
|
|
||||||
|
|
||||||
type Message = Message;
|
|
||||||
|
|
||||||
type Theme = Theme;
|
|
||||||
|
|
||||||
type Flags = ();
|
|
||||||
|
|
||||||
fn new(_flags: Self::Flags) -> (Self, iced::Command<Self::Message>) {
|
|
||||||
(
|
|
||||||
DustGui {
|
|
||||||
text_buffer: String::new(),
|
|
||||||
results: Vec::new(),
|
|
||||||
},
|
|
||||||
Command::none(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self) -> String {
|
|
||||||
"Dust".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> iced::Command<Self::Message> {
|
|
||||||
match message {
|
|
||||||
Message::TextInput(input) => {
|
|
||||||
self.text_buffer = input;
|
|
||||||
|
|
||||||
Command::none()
|
|
||||||
}
|
|
||||||
Message::Evaluate => {
|
|
||||||
let eval_result = eval(&self.text_buffer);
|
|
||||||
|
|
||||||
match eval_result {
|
|
||||||
Ok(result) => self.results.push(result.to_string()),
|
|
||||||
Err(error) => self.results.push(error.to_string()),
|
|
||||||
}
|
|
||||||
|
|
||||||
Command::batch(vec![])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Element<'_, Self::Message, iced::Renderer<Self::Theme>> {
|
|
||||||
let input = text_input("What needs to be done?", &self.text_buffer)
|
|
||||||
.id(INPUT_ID.clone())
|
|
||||||
.on_input(Message::TextInput)
|
|
||||||
.on_submit(Message::Evaluate)
|
|
||||||
.padding(15)
|
|
||||||
.size(30);
|
|
||||||
|
|
||||||
let result_display: Column<Message> = {
|
|
||||||
let mut text_widgets = Vec::new();
|
|
||||||
|
|
||||||
for _result in &self.results {
|
|
||||||
// text_widgets.push(text(result).style().into());
|
|
||||||
}
|
|
||||||
|
|
||||||
text_widgets.reverse();
|
|
||||||
|
|
||||||
Column::with_children(text_widgets)
|
|
||||||
};
|
|
||||||
|
|
||||||
container(column![input, result_display]).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum Message {
|
|
||||||
TextInput(String),
|
|
||||||
Evaluate,
|
|
||||||
}
|
|
@ -14,6 +14,13 @@ pub type Result<T> = std::result::Result<T, Error>;
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
UnexpectedSourceNode {
|
||||||
|
expected: &'static str,
|
||||||
|
actual: &'static str,
|
||||||
|
},
|
||||||
|
|
||||||
|
ExpectedFieldName,
|
||||||
|
|
||||||
/// Dust's internal type checking failed to identify a type mismatch. This should never happen, /// the error prompts the user to report the bug.
|
/// Dust's internal type checking failed to identify a type mismatch. This should never happen, /// the error prompts the user to report the bug.
|
||||||
TypeCheckFailure {
|
TypeCheckFailure {
|
||||||
tool_info: ToolInfo<'static>,
|
tool_info: ToolInfo<'static>,
|
||||||
@ -628,6 +635,8 @@ impl fmt::Display for Error {
|
|||||||
macro_info.identifier,
|
macro_info.identifier,
|
||||||
macro_info.inputs
|
macro_info.inputs
|
||||||
),
|
),
|
||||||
|
UnexpectedSourceNode { expected, actual } => write!(f, "Unexpected source node. Expected {expected}, but found {actual}."),
|
||||||
|
ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
src/interface.rs
114
src/interface.rs
@ -1,6 +1,10 @@
|
|||||||
//! The top level of Dust's API with functions in interpret Dust code.
|
//! The top level of Dust's API with functions in interpret Dust code.
|
||||||
|
|
||||||
use crate::{token, tree, Result, Value, VariableMap};
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use tree_sitter::{Parser, TreeCursor};
|
||||||
|
|
||||||
|
use crate::{language, token, tree, Error, Result, Value, VariableMap};
|
||||||
|
|
||||||
/// Evaluate the given expression string.
|
/// Evaluate the given expression string.
|
||||||
///
|
///
|
||||||
@ -12,9 +16,10 @@ use crate::{token, tree, Result, Value, VariableMap};
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
|
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
|
||||||
pub fn eval(string: &str) -> Result<Value> {
|
pub fn eval(source: &str) -> Result<Value> {
|
||||||
let mut context = VariableMap::new();
|
let mut context = VariableMap::new();
|
||||||
eval_with_context(string, &mut context)
|
|
||||||
|
eval_with_context(source, &mut context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string with the given context.
|
/// Evaluate the given expression string with the given context.
|
||||||
@ -30,32 +35,93 @@ pub fn eval(string: &str) -> Result<Value> {
|
|||||||
/// assert_eq!(eval_with_context("one + two + three", &mut context), Ok(Value::from(6)));
|
/// assert_eq!(eval_with_context("one + two + three", &mut context), Ok(Value::from(6)));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_with_context(input: &str, context: &mut VariableMap) -> Result<Value> {
|
pub fn eval_with_context(input: &str, context: &mut VariableMap) -> Result<Value> {
|
||||||
let without_comments = input
|
let mut parser = Parser::new();
|
||||||
.lines()
|
|
||||||
.map(|line| {
|
|
||||||
let split = line.split_once('#');
|
|
||||||
|
|
||||||
if let Some((code, _comment)) = split {
|
parser.set_language(language()).unwrap();
|
||||||
code
|
|
||||||
} else {
|
|
||||||
line
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let split = without_comments.split_once("->");
|
let tree = parser.parse(input, None).unwrap();
|
||||||
|
let sexp = tree.root_node().to_sexp();
|
||||||
|
|
||||||
if let Some((left, right)) = split {
|
println!("{sexp}");
|
||||||
let left_result = tree::tokens_to_operator_tree(token::tokenize(left)?)?
|
|
||||||
.eval_with_context_mut(context)?;
|
|
||||||
|
|
||||||
context.set_value("input", left_result)?;
|
let mut cursor = tree.walk();
|
||||||
|
|
||||||
let right_result = eval_with_context(right, context)?;
|
cursor.goto_first_child();
|
||||||
|
|
||||||
Ok(right_result)
|
let statement = Statement::from_cursor(cursor);
|
||||||
} else {
|
|
||||||
tree::tokens_to_operator_tree(token::tokenize(&without_comments)?)?
|
println!("{statement:?}");
|
||||||
.eval_with_context_mut(context)
|
|
||||||
|
Ok(Value::Empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct EvalTree {
|
||||||
|
root: Source,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Source {
|
||||||
|
Comment(String),
|
||||||
|
Statement(Statement),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Statement {
|
||||||
|
Closed(Expression),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Statement {
|
||||||
|
fn from_cursor(mut cursor: TreeCursor) -> Result<Self> {
|
||||||
|
let node = cursor.node();
|
||||||
|
|
||||||
|
cursor.goto_first_child();
|
||||||
|
|
||||||
|
if node.kind() == "statement" {
|
||||||
|
Ok(Statement::Closed(Expression::from_cursor(cursor)?))
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedSourceNode {
|
||||||
|
expected: "statement",
|
||||||
|
actual: node.kind(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Expression {
|
||||||
|
Identifier(&'static str),
|
||||||
|
Value(Range<usize>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
fn from_cursor(mut cursor: TreeCursor) -> Result<Self> {
|
||||||
|
let parent = cursor.node();
|
||||||
|
|
||||||
|
cursor.goto_first_child();
|
||||||
|
|
||||||
|
let child = cursor.node();
|
||||||
|
|
||||||
|
if parent.kind() == "expression" {
|
||||||
|
if child.kind() == "identifier" {
|
||||||
|
if let Some(name) = cursor.field_name() {
|
||||||
|
Ok(Expression::Identifier(name))
|
||||||
|
} else {
|
||||||
|
Err(Error::ExpectedFieldName)
|
||||||
|
}
|
||||||
|
} else if child.kind() == "value" {
|
||||||
|
Ok(Self::Value(child.byte_range()))
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedSourceNode {
|
||||||
|
expected: "identifier or value",
|
||||||
|
actual: child.kind(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(Error::UnexpectedSourceNode {
|
||||||
|
expected: "expression",
|
||||||
|
actual: parent.kind(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
src/lib.rs
37
src/lib.rs
@ -3,7 +3,6 @@
|
|||||||
//!
|
//!
|
||||||
//! Using this library is simple and straightforward, see the [inferface] module for instructions on
|
//! Using this library is simple and straightforward, see the [inferface] module for instructions on
|
||||||
//! interpreting Dust code. Most of the language's features are implemented in the [tools] module.
|
//! interpreting Dust code. Most of the language's features are implemented in the [tools] module.
|
||||||
#![forbid(unsafe_code)]
|
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
error::*,
|
error::*,
|
||||||
@ -26,3 +25,39 @@ mod operator;
|
|||||||
mod token;
|
mod token;
|
||||||
mod tree;
|
mod tree;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
|
use tree_sitter::Language;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn tree_sitter_dust() -> Language;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the tree-sitter [Language][] for this grammar.
|
||||||
|
///
|
||||||
|
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
|
||||||
|
pub fn language() -> Language {
|
||||||
|
unsafe { tree_sitter_dust() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The content of the [`node-types.json`][] file for this grammar.
|
||||||
|
///
|
||||||
|
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
|
||||||
|
pub const NODE_TYPES: &'static str = include_str!("../../../src/node-types.json");
|
||||||
|
|
||||||
|
// Uncomment these to include any queries that this grammar contains
|
||||||
|
|
||||||
|
// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
|
||||||
|
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
|
||||||
|
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
|
||||||
|
// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn test_can_load_grammar() {
|
||||||
|
let mut parser = tree_sitter::Parser::new();
|
||||||
|
parser
|
||||||
|
.set_language(super::language())
|
||||||
|
.expect("Error loading dust language");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user