1
0
dust/src/interpret.rs

182 lines
6.1 KiB
Rust
Raw Normal View History

2024-01-30 23:13:30 +00:00
//! Tools to interpret dust source code.
2023-12-29 19:01:54 +00:00
//!
2024-01-30 23:13:30 +00:00
//! This module has three tools to run Dust code.
//!
//! - [interpret] is the simples way to run Dust code inside of an application or library
//! - [interpret_with_context] allows you to set variables on the execution context
//! - [Interpreter] is an advanced tool that can parse, verify, run and format Dust code
//!
//! # Examples
//!
//! Run some Dust and get the result.
//!
//! ```rust
//! # use dust_lang::*;
//! assert_eq!(
//! interpret("1 + 2 + 3"),
//! Ok(Value::Integer(6))
//! );
//! ```
//!
//! Create a custom context with variables you can use in your code.
//!
//! ```rust
//! # use dust_lang::*;
//! let context = Map::new();
//!
//! context.set("one".into(), 1.into());
//! context.set("two".into(), 2.into());
//! context.set("three".into(), 3.into());
//!
//! let dust_code = "four = 4; one + two + three + four";
//!
//! assert_eq!(
//! interpret_with_context(dust_code, context),
//! Ok(Value::Integer(10))
//! );
//! ```
use tree_sitter::{Node as SyntaxNode, Parser, Tree as SyntaxTree, TreeCursor};
2023-12-29 19:01:54 +00:00
2024-01-31 18:51:48 +00:00
use crate::{
2024-02-01 00:07:18 +00:00
error::SyntaxError, language, AbstractTree, Error, Format, Map, Root, SourcePosition, Value,
2024-01-31 18:51:48 +00:00
};
2023-12-29 19:01:54 +00:00
2024-01-25 12:10:45 +00:00
/// Interpret the given source code. Returns the value of last statement or the
/// first error encountered.
2023-12-29 19:01:54 +00:00
///
2024-01-30 23:13:30 +00:00
/// See the [module-level docs][self] for more info.
2024-01-31 18:51:48 +00:00
pub fn interpret(source: &str) -> Result<Value, Error> {
2023-12-29 19:52:51 +00:00
interpret_with_context(source, Map::new())
2023-12-29 19:01:54 +00:00
}
/// Interpret the given source code with the given context.
///
2024-01-25 12:10:45 +00:00
/// A context is a [Map] instance, which is dust's
/// [BTreeMap][std::collections::btree_map::BTreeMap] that is used internally
2024-01-25 13:27:24 +00:00
/// for the `<map>` type. Any value can be set, including functions and nested
/// maps.
2024-01-25 12:10:45 +00:00
///
2024-01-30 23:13:30 +00:00
/// See the [module-level docs][self] for more info.
2024-01-31 18:51:48 +00:00
pub fn interpret_with_context(source: &str, context: Map) -> Result<Value, Error> {
2023-12-30 17:02:58 +00:00
let mut interpreter = Interpreter::new(context);
2023-12-29 21:27:13 +00:00
let value = interpreter.run(source)?;
2023-12-29 19:01:54 +00:00
Ok(value)
}
/// A source code interpreter for the Dust language.
2024-01-30 23:13:30 +00:00
///
/// The interpreter's most important functions are used to parse dust source code, verify it is safe
/// and run it and they are written in a way that forces them to be used safely. Each step in this
/// process contains the prior steps, meaning that the same code is always used to create the syntax /// tree, abstract tree and final evaluation. This avoids a critical logic error.
2023-12-29 21:27:13 +00:00
pub struct Interpreter {
2023-12-29 19:35:52 +00:00
parser: Parser,
2023-12-29 19:52:51 +00:00
context: Map,
2023-12-29 19:01:54 +00:00
}
2023-12-29 21:27:13 +00:00
impl Interpreter {
2024-01-30 23:13:30 +00:00
/// Creates a new interpreter with the given variable context.
2023-12-30 17:02:58 +00:00
pub fn new(context: Map) -> Self {
2023-12-29 19:01:54 +00:00
let mut parser = Parser::new();
2023-12-30 17:02:58 +00:00
parser
.set_language(language())
.expect("Language version is incompatible with tree sitter version.");
2023-12-29 19:01:54 +00:00
2024-02-01 00:07:18 +00:00
parser.set_logger(Some(Box::new(|_log_type, message| {
2024-01-30 23:13:30 +00:00
log::info!("{}", message)
})));
Interpreter { parser, context }
}
/// Generates a syntax tree from the source. Returns an error if the the parser is cancelled for
/// taking too long. The syntax tree may contain error nodes, which represent syntax errors.
///
/// Tree sitter is designed to be run on every keystroke, so this is generally a lightweight
/// function to call.
2024-01-31 18:51:48 +00:00
pub fn parse(&mut self, source: &str) -> Result<SyntaxTree, Error> {
2024-01-30 23:13:30 +00:00
if let Some(tree) = self.parser.parse(source, None) {
Ok(tree)
} else {
Err(Error::ParserCancelled)
2023-12-30 17:02:58 +00:00
}
2023-12-29 19:01:54 +00:00
}
2024-01-30 23:13:30 +00:00
/// Checks the source for errors and generates an abstract tree.
///
/// The order in which this function works is:
///
/// - parse the source into a syntax tree
/// - check the syntax tree for errors
/// - generate an abstract tree from the source and syntax tree
/// - check the abstract tree for type errors
2024-01-31 18:51:48 +00:00
pub fn verify(&mut self, source: &str) -> Result<Root, Error> {
fn check_for_error(
node: SyntaxNode,
source: &str,
cursor: &mut TreeCursor,
2024-02-01 00:07:18 +00:00
) -> Result<(), Error> {
if node.is_error() {
2024-02-01 00:07:18 +00:00
Err(Error::Syntax(SyntaxError::InvalidSource {
source: source[node.byte_range()].to_string(),
2024-02-01 00:07:18 +00:00
position: SourcePosition::from(node.range()),
}))
} else {
for child in node.children(&mut cursor.clone()) {
2024-01-10 20:03:52 +00:00
check_for_error(child, source, cursor)?;
}
Ok(())
}
}
2024-01-30 23:13:30 +00:00
let syntax_tree = self.parse(source)?;
let root = syntax_tree.root_node();
let mut cursor = syntax_tree.root_node().walk();
2024-01-30 23:13:30 +00:00
check_for_error(root, source, &mut cursor)?;
2024-01-30 23:13:30 +00:00
let abstract_tree = Root::from_syntax(syntax_tree.root_node(), source, &self.context)?;
2024-02-01 01:52:34 +00:00
abstract_tree.validate(source, &self.context)?;
2024-01-30 23:13:30 +00:00
Ok(abstract_tree)
2023-12-29 19:01:54 +00:00
}
2024-01-30 23:13:30 +00:00
/// Runs the source, returning the final statement's value or first error.
///
/// This function [parses][Self::parse], [verifies][Self::verify] and [runs][Root::run] using
/// the same source code.
2024-01-31 18:51:48 +00:00
pub fn run(&mut self, source: &str) -> Result<Value, Error> {
2024-02-01 00:07:18 +00:00
self.verify(source)?
.run(source, &self.context)
.map_err(|error| Error::Runtime(error))
2023-12-29 19:01:54 +00:00
}
2024-01-30 23:13:30 +00:00
/// Return an s-expression displaying a syntax tree of the source, or the ParserCancelled error
/// if the parser takes too long.
2024-01-31 18:51:48 +00:00
pub fn syntax_tree(&mut self, source: &str) -> Result<String, Error> {
2024-01-30 23:13:30 +00:00
Ok(self.parse(source)?.root_node().to_sexp())
2023-12-29 19:01:54 +00:00
}
2024-01-06 10:00:36 +00:00
2024-01-30 23:13:30 +00:00
/// Return formatted Dust code generated from the current abstract tree, or None if no source
/// code has been run successfully.
///
/// You should call [verify][Interpreter::verify] before calling this function. You can only
/// create formatted source from a valid abstract tree.
2024-01-31 18:51:48 +00:00
pub fn format(&mut self, source: &str) -> Result<String, Error> {
2024-01-30 23:13:30 +00:00
let mut formatted_output = String::new();
2024-01-06 13:11:09 +00:00
2024-01-30 23:13:30 +00:00
self.verify(source)?.format(&mut formatted_output, 0);
2024-01-06 13:11:09 +00:00
2024-01-30 23:13:30 +00:00
Ok(formatted_output)
2024-01-06 10:00:36 +00:00
}
2023-12-29 19:01:54 +00:00
}
2023-12-30 17:02:58 +00:00
impl Default for Interpreter {
fn default() -> Self {
Interpreter::new(Map::new())
}
}