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 ::{
error ::{ RuntimeError , SyntaxError , ValidationError } ,
language , AbstractTree , Error , Format , Map , Root , Value ,
} ;
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-01-30 23:13:30 +00:00
parser . set_logger ( Some ( Box ::new ( | log_type , message | {
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 ,
) -> Result < ( ) , ValidationError > {
2023-12-31 16:46:56 +00:00
if node . is_error ( ) {
Err ( Error ::Syntax {
source : source [ node . byte_range ( ) ] . to_string ( ) ,
location : node . start_position ( ) ,
} )
} else {
for child in node . children ( & mut cursor . clone ( ) ) {
2024-01-10 20:03:52 +00:00
check_for_error ( child , source , cursor ) ? ;
2023-12-31 16:46:56 +00:00
}
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 ( ) ;
2023-12-31 16:46:56 +00:00
2024-01-30 23:13:30 +00:00
check_for_error ( root , source , & mut cursor ) ? ;
2023-12-31 16:46:56 +00:00
2024-01-30 23:13:30 +00:00
let abstract_tree = Root ::from_syntax ( syntax_tree . root_node ( ) , source , & self . context ) ? ;
2023-12-31 16:46:56 +00:00
2024-01-30 23:13:30 +00:00
abstract_tree . check_type ( source , & self . context ) ? ;
2023-12-31 16:46:56 +00:00
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-01-30 23:13:30 +00:00
self . verify ( source ) ? . run ( source , & self . context )
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 ( ) )
}
}