1
0
dust/src/interpret.rs

195 lines
6.4 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.
//!
2024-02-15 09:16:34 +00:00
//! - [interpret] is the simplest way to run Dust code inside of an application or library
2024-01-30 23:13:30 +00:00
//! - [interpret_with_context] allows you to set variables on the execution context
2024-02-15 09:18:30 +00:00
//! - [Interpreter] is an advanced tool that can parse, validate, run and format Dust code
2024-01-30 23:13:30 +00:00
//!
//! # 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::*;
2024-02-15 09:16:34 +00:00
//! let context = Context::new();
2024-01-30 23:13:30 +00:00
//!
2024-02-15 09:16:34 +00:00
//! context.set_value("one".into(), 1.into()).unwrap();
//! context.set_value("two".into(), 2.into()).unwrap();
//! context.set_value("three".into(), 3.into()).unwrap();
2024-01-30 23:13:30 +00:00
//!
//! 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-11 00:31:47 +00:00
error::SyntaxError, language, AbstractTree, Context, Error, Format, 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> {
2024-02-11 00:31:47 +00:00
interpret_with_context(source, Context::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-02-11 00:31:47 +00:00
pub fn interpret_with_context(source: &str, context: Context) -> 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
///
2024-02-15 09:16:34 +00:00
/// The interpreter's most important functions are used to parse dust source
/// code, verify it is safe and run it. 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.
///
/// ```
/// # use dust_lang::*;
/// let context = Context::new();
/// let mut interpreter = Interpreter::new(context);
/// let result = interpreter.run("2 + 2");
///
/// assert_eq!(result, Ok(Value::Integer(4)));
/// ```
2023-12-29 21:27:13 +00:00
pub struct Interpreter {
2023-12-29 19:35:52 +00:00
parser: Parser,
2024-02-11 00:31:47 +00:00
context: Context,
2023-12-29 19:01:54 +00:00
}
2023-12-29 21:27:13 +00:00
impl Interpreter {
2024-02-15 09:16:34 +00:00
/// Create a new interpreter with the given context.
2024-02-11 00:31:47 +00:00
pub fn new(context: Context) -> 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 }
}
2024-02-15 09:16:34 +00:00
/// Generate 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.
2024-01-30 23:13:30 +00:00
///
2024-02-15 09:16:34 +00:00
/// 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-02-15 09:16:34 +00:00
/// Check the source for errors and generate an abstract tree.
2024-01-30 23:13:30 +00:00
///
/// 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-02-15 09:16:34 +00:00
pub fn validate(&mut self, source: &str) -> Result<Root, Error> {
2024-01-31 18:51:48 +00:00
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-02-15 09:16:34 +00:00
/// Run the source, returning the final statement's value or first error.
2024-01-30 23:13:30 +00:00
///
2024-02-15 09:16:34 +00:00
/// This function [parses][Self::parse], [validates][Self::validate] 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-15 09:16:34 +00:00
self.validate(source)?
2024-02-01 00:07:18 +00:00
.run(source, &self.context)
.map_err(|error| Error::Runtime(error))
2023-12-29 19:01:54 +00:00
}
2024-02-15 09:16:34 +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-02-15 09:16:34 +00:00
/// Return formatted Dust code generated from the current abstract tree, or
/// None if no source code has been run successfully.
2024-01-30 23:13:30 +00:00
///
2024-02-15 09:18:30 +00:00
/// You should call [validate][Interpreter::validate] before calling this
2024-02-15 09:16:34 +00:00
/// 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-02-15 09:16:34 +00:00
self.validate(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 {
2024-02-11 00:31:47 +00:00
Interpreter::new(Context::new())
2023-12-30 17:02:58 +00:00
}
}