refactor: split parser and interpreter into separate crates
This commit is contained in:
parent
e49dbab859
commit
f1083009a4
18 changed files with 265 additions and 128 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
@ -323,8 +323,25 @@ name = "mute"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"rstest",
|
||||
"mute-interpreter",
|
||||
"mute-parser",
|
||||
"rustyline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mute-interpreter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mute-parser",
|
||||
"rstest",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mute-parser"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rstest",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
|
15
Cargo.toml
15
Cargo.toml
|
@ -4,14 +4,15 @@ version = "0.1.0"
|
|||
authors = ["Raine Godmaire <its@raine.ing>"]
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "mute"
|
||||
path = "src/bin/cli.rs"
|
||||
[workspace]
|
||||
members = [
|
||||
".",
|
||||
"mute-parser",
|
||||
"mute-interpreter",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.4", features = ["derive"] }
|
||||
rustyline = "14.0.0"
|
||||
thiserror = "1.0.48"
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.18.2"
|
||||
mute-parser = { path = "./mute-parser" }
|
||||
mute-interpreter = { path = "./mute-interpreter" }
|
||||
|
|
11
mute-interpreter/Cargo.toml
Normal file
11
mute-interpreter/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "mute-interpreter"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.48"
|
||||
mute-parser = { path = "../mute-parser" }
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.18.2"
|
|
@ -1,10 +1,9 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::{Error, Node};
|
||||
use crate::evaluator::{eval, eval_node};
|
||||
use crate::macros::arg_count;
|
||||
use crate::node::Node;
|
||||
|
||||
pub(super) fn core() -> HashMap<String, Node> {
|
||||
[
|
|
@ -1,9 +1,8 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::macros::arg_count;
|
||||
use crate::node::Node;
|
||||
use crate::{Error, Node};
|
||||
|
||||
pub(super) fn io() -> HashMap<String, Node> {
|
||||
[
|
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::node::Node;
|
||||
use crate::Node;
|
||||
|
||||
mod core;
|
||||
mod io;
|
28
mute-interpreter/src/error.rs
Normal file
28
mute-interpreter/src/error.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use thiserror::Error;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("could not find symbol '{0}' in environment")]
|
||||
NotInEnv(String),
|
||||
#[error("expression does not have a valid operator")]
|
||||
InvalidOperator,
|
||||
#[error("expected symbol")]
|
||||
ExpectedSymbol,
|
||||
#[error("expected list, vector, or map")]
|
||||
ExpectedCollection,
|
||||
#[error("expected list")]
|
||||
ExpectedList,
|
||||
#[error("expected number")]
|
||||
ExpectedNumber,
|
||||
#[error("expected string")]
|
||||
ExpectedString,
|
||||
#[error("expected {0} arguments, got {1}")]
|
||||
MismatchedArgCount(usize, usize),
|
||||
#[error("system error {0}")]
|
||||
SystemError(String),
|
||||
|
||||
#[error("please file a bug report")]
|
||||
Unreachable,
|
||||
}
|
|
@ -4,7 +4,7 @@ use crate::Result;
|
|||
|
||||
use crate::env::Environment;
|
||||
use crate::error::Error;
|
||||
use crate::node::Node;
|
||||
use crate::Node;
|
||||
|
||||
pub fn eval(env: &Environment, ast: Vec<Node>) -> Result<Vec<Node>> {
|
||||
let mut exprs = Vec::new();
|
||||
|
@ -80,7 +80,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::parser;
|
||||
use mute_parser::parse_str;
|
||||
|
||||
use super::*;
|
||||
use rstest::rstest;
|
||||
|
@ -204,7 +204,7 @@ mod test {
|
|||
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
|
||||
dbg!(input);
|
||||
let env = Environment::default();
|
||||
let ast = parser::parse_str(input).unwrap();
|
||||
let ast = parse_str(input).unwrap();
|
||||
let res = eval(&env, ast)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
|
@ -221,7 +221,7 @@ mod test {
|
|||
#[case("{:a}")]
|
||||
fn test_evaluator_fail(#[case] input: &str) {
|
||||
let env = Environment::default();
|
||||
let ast = parser::parse_str(input).unwrap();
|
||||
let ast = parse_str(input).unwrap();
|
||||
let res = eval(&env, ast);
|
||||
|
||||
assert!(res.is_err())
|
15
mute-interpreter/src/lib.rs
Normal file
15
mute-interpreter/src/lib.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// Crate Exports
|
||||
mod env;
|
||||
mod error;
|
||||
mod evaluator;
|
||||
mod macros;
|
||||
mod node;
|
||||
|
||||
pub use env::Environment;
|
||||
pub use error::{Error, Result};
|
||||
pub use node::Node;
|
||||
|
||||
pub fn eval(env: &Environment, ast: Vec<mute_parser::Node>) -> Result<Vec<Node>> {
|
||||
let ast = ast.into_iter().map(Into::into).collect();
|
||||
evaluator::eval(env, ast)
|
||||
}
|
110
mute-interpreter/src/node.rs
Normal file
110
mute-interpreter/src/node.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::Environment;
|
||||
use crate::Result;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Node {
|
||||
List(Vec<Node>),
|
||||
|
||||
Symbol(String),
|
||||
Keyword(String),
|
||||
Int(i64),
|
||||
Int128(i128),
|
||||
Float(f64),
|
||||
String(String),
|
||||
Boolean(bool),
|
||||
Nil,
|
||||
|
||||
Vector(Vec<Node>),
|
||||
Map(HashMap<String, Node>),
|
||||
Function {
|
||||
params: Vec<String>,
|
||||
env: Environment,
|
||||
body: Box<Node>,
|
||||
},
|
||||
NativeFunc(fn(env: &Environment, args: Vec<Node>) -> Result<Node>),
|
||||
Special(fn(env: &Environment, args: Vec<Node>) -> Result<Node>),
|
||||
|
||||
Void,
|
||||
}
|
||||
|
||||
impl From<mute_parser::Node> for Node {
|
||||
fn from(value: mute_parser::Node) -> Self {
|
||||
match value {
|
||||
mute_parser::Node::List(list) => Node::List(list.into_iter().map(Into::into).collect()),
|
||||
mute_parser::Node::Symbol(symbol) => Node::Symbol(symbol),
|
||||
mute_parser::Node::Keyword(keyword) => Node::Keyword(keyword),
|
||||
mute_parser::Node::Int(int) => Node::Int(int),
|
||||
mute_parser::Node::Int128(int) => Node::Int128(int),
|
||||
mute_parser::Node::Float(float) => Node::Float(float),
|
||||
mute_parser::Node::String(string) => Node::String(string),
|
||||
mute_parser::Node::Boolean(boolean) => Node::Boolean(boolean),
|
||||
mute_parser::Node::Nil => Node::Nil,
|
||||
mute_parser::Node::Vector(vector) => {
|
||||
Node::Vector(vector.into_iter().map(Into::into).collect())
|
||||
}
|
||||
mute_parser::Node::Map(map) => {
|
||||
Node::Map(map.into_iter().map(|(k, v)| (k, v.into())).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Node {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Node::List(list) => {
|
||||
let s = list
|
||||
.iter()
|
||||
.map(|elem| elem.to_string())
|
||||
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
|
||||
.unwrap_or_default();
|
||||
|
||||
write!(f, "({s})")
|
||||
}
|
||||
|
||||
Node::Int(val) => write!(f, "{}", val),
|
||||
Node::Int128(val) => write!(f, "{}", val),
|
||||
Node::Float(val) => write!(f, "{}", val),
|
||||
Node::Boolean(true) => write!(f, "true"),
|
||||
Node::Boolean(false) => write!(f, "false"),
|
||||
Node::Symbol(val) => write!(f, "{}", val),
|
||||
Node::Keyword(val) => write!(f, ":{}", val),
|
||||
Node::String(val) => write!(f, "{}", val),
|
||||
Node::Nil => write!(f, "()"),
|
||||
|
||||
Node::Vector(vec) => {
|
||||
let s = vec
|
||||
.iter()
|
||||
.map(|elem| elem.to_string())
|
||||
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
|
||||
.unwrap_or_default();
|
||||
|
||||
write!(f, "[{s}]")
|
||||
}
|
||||
Node::Map(map) => {
|
||||
let res = map
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{k}: {v}"))
|
||||
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
|
||||
.unwrap_or_default();
|
||||
|
||||
write!(f, "{{{res}}}")
|
||||
}
|
||||
|
||||
Node::Function {
|
||||
params: _,
|
||||
env: _,
|
||||
body: _,
|
||||
} => {
|
||||
write!(f, "#<function>")
|
||||
}
|
||||
|
||||
Node::NativeFunc(func) => write!(f, "{func:?}"),
|
||||
Node::Special(func) => write!(f, "{func:?}"),
|
||||
|
||||
Node::Void => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
10
mute-parser/Cargo.toml
Normal file
10
mute-parser/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "mute-parser"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.48"
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.18.2"
|
|
@ -4,34 +4,6 @@ pub type Result<T> = std::result::Result<T, Error>;
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("ParserError: {0}")]
|
||||
ParserError(ParserError),
|
||||
|
||||
#[error("could not find symbol '{0}' in environment")]
|
||||
NotInEnv(String),
|
||||
#[error("expression does not have a valid operator")]
|
||||
InvalidOperator,
|
||||
#[error("expected symbol")]
|
||||
ExpectedSymbol,
|
||||
#[error("expected list, vector, or map")]
|
||||
ExpectedCollection,
|
||||
#[error("expected list")]
|
||||
ExpectedList,
|
||||
#[error("expected number")]
|
||||
ExpectedNumber,
|
||||
#[error("expected string")]
|
||||
ExpectedString,
|
||||
#[error("expected {0} arguments, got {1}")]
|
||||
MismatchedArgCount(usize, usize),
|
||||
#[error("system error {0}")]
|
||||
SystemError(String),
|
||||
|
||||
#[error("please file a bug report")]
|
||||
Unreachable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParserError {
|
||||
#[error("closing parenthesis does not have matching open parenthesis")]
|
||||
UnopenedParenthesis,
|
||||
#[error("unclosed list")]
|
|
@ -1,6 +1,6 @@
|
|||
use std::{iter::Peekable, str::Chars};
|
||||
|
||||
use crate::error::ParserError;
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd)]
|
||||
pub enum Token {
|
||||
|
@ -42,7 +42,7 @@ pub enum Token {
|
|||
Nil,
|
||||
}
|
||||
|
||||
pub fn read(input: &str) -> Result<Vec<Token>, ParserError> {
|
||||
pub fn read(input: &str) -> Result<Vec<Token>, Error> {
|
||||
let mut input = input.chars().peekable();
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
|
@ -53,7 +53,7 @@ pub fn read(input: &str) -> Result<Vec<Token>, ParserError> {
|
|||
Ok(tokens)
|
||||
}
|
||||
|
||||
fn next_token(input: &mut Peekable<Chars>) -> Result<Option<Token>, ParserError> {
|
||||
fn next_token(input: &mut Peekable<Chars>) -> Result<Option<Token>, Error> {
|
||||
let tok = match input.next() {
|
||||
Some(tok) => tok,
|
||||
None => return Ok(None),
|
||||
|
@ -129,13 +129,13 @@ fn next_token(input: &mut Peekable<Chars>) -> Result<Option<Token>, ParserError>
|
|||
Some(tok) => tok,
|
||||
None => return Ok(None),
|
||||
},
|
||||
c => Err(ParserError::UnexpectedChar(c))?,
|
||||
c => Err(Error::UnexpectedChar(c))?,
|
||||
};
|
||||
|
||||
Ok(Some(tok))
|
||||
}
|
||||
|
||||
fn read_string(input: &mut Peekable<Chars>) -> Result<Token, ParserError> {
|
||||
fn read_string(input: &mut Peekable<Chars>) -> Result<Token, Error> {
|
||||
let mut raw_str = Vec::new();
|
||||
|
||||
loop {
|
||||
|
@ -147,7 +147,7 @@ fn read_string(input: &mut Peekable<Chars>) -> Result<Token, ParserError> {
|
|||
}
|
||||
|
||||
Some(_) => (),
|
||||
None => Err(ParserError::UnterminatedString)?,
|
||||
None => Err(Error::UnterminatedString)?,
|
||||
}
|
||||
|
||||
raw_str.push(input.next().unwrap())
|
|
@ -1,26 +1,30 @@
|
|||
// Crate exports
|
||||
mod error;
|
||||
mod lexer;
|
||||
mod node;
|
||||
|
||||
pub use error::{Error, Result};
|
||||
pub use node::Node;
|
||||
|
||||
// Actual imports
|
||||
use std::{iter::Peekable, vec::IntoIter};
|
||||
|
||||
mod lexer;
|
||||
use lexer::Token;
|
||||
|
||||
use crate::error::ParserError;
|
||||
use crate::{Error, Node};
|
||||
type TokenIter = Peekable<IntoIter<Token>>;
|
||||
|
||||
pub fn parse_str(input: &str) -> crate::Result<Vec<Node>> {
|
||||
let mut tokens = lexer::read(input)
|
||||
.map_err(Error::ParserError)?
|
||||
.into_iter()
|
||||
.peekable();
|
||||
pub fn parse_str(input: &str) -> Result<Vec<Node>> {
|
||||
let mut tokens: TokenIter = lexer::read(input)?.into_iter().peekable();
|
||||
let mut ast = Vec::new();
|
||||
|
||||
while let Some(node) = next_statement(&mut tokens).map_err(Error::ParserError)? {
|
||||
while let Some(node) = next_statement(&mut tokens)? {
|
||||
ast.push(node)
|
||||
}
|
||||
|
||||
Ok(ast)
|
||||
}
|
||||
|
||||
fn next_statement(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Option<Node>, ParserError> {
|
||||
fn next_statement(tokens: &mut TokenIter) -> Result<Option<Node>> {
|
||||
let tok = match tokens.next() {
|
||||
Some(tok) => tok,
|
||||
None => return Ok(None),
|
||||
|
@ -28,13 +32,13 @@ fn next_statement(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Option<Node>
|
|||
|
||||
let node = match tok {
|
||||
Token::LeftParen => read_list(tokens, Token::RightParen)?,
|
||||
Token::RightParen => Err(ParserError::UnopenedParenthesis)?,
|
||||
Token::RightParen => Err(Error::UnopenedParenthesis)?,
|
||||
|
||||
Token::LeftBracket => read_list(tokens, Token::RightBracket)?,
|
||||
Token::RightBracket => Err(ParserError::UnopenedBracket)?,
|
||||
Token::RightBracket => Err(Error::UnopenedBracket)?,
|
||||
|
||||
Token::LeftBrace => read_list(tokens, Token::RightBrace)?,
|
||||
Token::RightBrace => Err(ParserError::UnopenedBrace)?,
|
||||
Token::RightBrace => Err(Error::UnopenedBrace)?,
|
||||
|
||||
Token::WeirdSign => read_quote(tokens, "splice-unquote")?,
|
||||
Token::Apostrophe => read_quote(tokens, "quote")?,
|
||||
|
@ -69,12 +73,12 @@ fn next_statement(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Option<Node>
|
|||
Ok(Some(node))
|
||||
}
|
||||
|
||||
fn read_list(tokens: &mut Peekable<IntoIter<Token>>, closer: Token) -> Result<Node, ParserError> {
|
||||
fn read_list(tokens: &mut TokenIter, closer: Token) -> Result<Node> {
|
||||
let mut list = match closer {
|
||||
Token::RightParen => Vec::new(),
|
||||
Token::RightBracket => vec![Node::Symbol("vector".into())],
|
||||
Token::RightBrace => vec![Node::Symbol("hashmap".into())],
|
||||
_ => Err(ParserError::Unreachable)?,
|
||||
_ => Err(Error::Unreachable)?,
|
||||
};
|
||||
|
||||
loop {
|
||||
|
@ -91,10 +95,10 @@ fn read_list(tokens: &mut Peekable<IntoIter<Token>>, closer: Token) -> Result<No
|
|||
match next_statement(tokens)? {
|
||||
Some(node) => list.push(node),
|
||||
None => match closer {
|
||||
Token::RightParen => Err(ParserError::UnclosedParenthesis)?,
|
||||
Token::RightBracket => Err(ParserError::UnclosedBracket)?,
|
||||
Token::RightBrace => Err(ParserError::UnclosedBrace)?,
|
||||
_ => Err(ParserError::Unreachable)?,
|
||||
Token::RightParen => Err(Error::UnclosedParenthesis)?,
|
||||
Token::RightBracket => Err(Error::UnclosedBracket)?,
|
||||
Token::RightBrace => Err(Error::UnclosedBrace)?,
|
||||
_ => Err(Error::Unreachable)?,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -102,13 +106,10 @@ fn read_list(tokens: &mut Peekable<IntoIter<Token>>, closer: Token) -> Result<No
|
|||
Ok(Node::List(list))
|
||||
}
|
||||
|
||||
fn read_quote(
|
||||
tokens: &mut Peekable<IntoIter<Token>>,
|
||||
quote_type: &str,
|
||||
) -> Result<Node, ParserError> {
|
||||
fn read_quote(tokens: &mut TokenIter, quote_type: &str) -> Result<Node> {
|
||||
let follower_node = match next_statement(tokens)? {
|
||||
Some(node) => node,
|
||||
None => Err(ParserError::NoFollowerNode)?,
|
||||
None => Err(Error::NoFollowerNode)?,
|
||||
};
|
||||
|
||||
Ok(Node::List(vec![
|
|
@ -1,9 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
use crate::env::Environment;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Node {
|
||||
List(Vec<Node>),
|
||||
|
@ -19,15 +15,6 @@ pub enum Node {
|
|||
|
||||
Vector(Vec<Node>),
|
||||
Map(HashMap<String, Node>),
|
||||
Function {
|
||||
params: Vec<String>,
|
||||
env: Environment,
|
||||
body: Box<Node>,
|
||||
},
|
||||
NativeFunc(fn(env: &Environment, args: Vec<Node>) -> Result<Node>),
|
||||
Special(fn(env: &Environment, args: Vec<Node>) -> Result<Node>),
|
||||
|
||||
Void,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Node {
|
||||
|
@ -71,19 +58,6 @@ impl std::fmt::Display for Node {
|
|||
|
||||
write!(f, "{{{res}}}")
|
||||
}
|
||||
|
||||
Node::Function {
|
||||
params: _,
|
||||
env: _,
|
||||
body: _,
|
||||
} => {
|
||||
write!(f, "#<function>")
|
||||
}
|
||||
|
||||
Node::NativeFunc(func) => write!(f, "{func:?}"),
|
||||
Node::Special(func) => write!(f, "{func:?}"),
|
||||
|
||||
Node::Void => write!(f, ""),
|
||||
}
|
||||
}
|
||||
}
|
18
src/lib.rs
18
src/lib.rs
|
@ -1,18 +0,0 @@
|
|||
mod env;
|
||||
mod error;
|
||||
mod evaluator;
|
||||
mod macros;
|
||||
mod node;
|
||||
mod parser;
|
||||
|
||||
pub use env::Environment;
|
||||
pub use error::{Error, Result};
|
||||
pub use node::Node;
|
||||
|
||||
pub fn parse(input: &str) -> Result<Vec<Node>> {
|
||||
parser::parse_str(input)
|
||||
}
|
||||
|
||||
pub fn eval(env: &Environment, input: Vec<Node>) -> Result<Vec<Node>> {
|
||||
evaluator::eval(env, input)
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use rustyline::{error::ReadlineError, DefaultEditor};
|
||||
|
||||
use mute::{eval, parse, Environment, Node, Result};
|
||||
use mute_interpreter::{eval, Environment};
|
||||
use mute_parser::parse_str;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(version, author, about)]
|
||||
|
@ -29,7 +30,14 @@ fn main() {
|
|||
Command::Run { file } => {
|
||||
let input = std::fs::read_to_string(file).unwrap();
|
||||
let env = Environment::default();
|
||||
let res = run(&env, &input);
|
||||
let ast = match parse_str(&input) {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
println!("error: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let res = eval(&env, ast);
|
||||
match res {
|
||||
Ok(expressions) => expressions.into_iter().for_each(|expr| println!("{expr}")),
|
||||
Err(err) => println!("{}", err),
|
||||
|
@ -37,7 +45,14 @@ fn main() {
|
|||
}
|
||||
Command::RunCmd { command } => {
|
||||
let env = Environment::default();
|
||||
let res = run(&env, &command);
|
||||
let ast = match parse_str(&command) {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
println!("error: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let res = eval(&env, ast);
|
||||
match res {
|
||||
Ok(expressions) => expressions.into_iter().for_each(|expr| println!("{expr}")),
|
||||
Err(err) => println!("{}", err),
|
||||
|
@ -47,11 +62,6 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
fn run(env: &Environment, command: &str) -> Result<Vec<Node>> {
|
||||
let ast = parse(command)?;
|
||||
eval(env, ast)
|
||||
}
|
||||
|
||||
fn repl() {
|
||||
let env = Environment::default();
|
||||
let mut rl = DefaultEditor::new().unwrap();
|
||||
|
@ -65,7 +75,15 @@ fn repl() {
|
|||
Ok(line) => {
|
||||
rl.add_history_entry(line.as_str()).unwrap();
|
||||
|
||||
match run(&env, &line) {
|
||||
let ast = match parse_str(&line) {
|
||||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
println!("error: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let res = eval(&env, ast);
|
||||
match res {
|
||||
Ok(expressions) => expressions.into_iter().for_each(|expr| println!("{expr}")),
|
||||
Err(err) => println!("error: {}", err),
|
||||
}
|
Loading…
Reference in a new issue