mirror of
https://github.com/danog/parser.git
synced 2024-11-26 20:04:57 +01:00
interpreter: basic support for require
This commit is contained in:
parent
4501905705
commit
cdaec0b7ca
@ -1,3 +1,5 @@
|
|||||||
|
use std::{path::PathBuf, fs::canonicalize};
|
||||||
|
|
||||||
use cmder::ParserMatches;
|
use cmder::ParserMatches;
|
||||||
use trunk_lexer::Lexer;
|
use trunk_lexer::Lexer;
|
||||||
use trunk_parser::Parser;
|
use trunk_parser::Parser;
|
||||||
@ -6,8 +8,9 @@ use crate::engine::eval;
|
|||||||
|
|
||||||
pub fn run(matches: ParserMatches) {
|
pub fn run(matches: ParserMatches) {
|
||||||
// FIXME: Better error handling needed.
|
// FIXME: Better error handling needed.
|
||||||
let file = matches.get_arg("file").unwrap();
|
let file = PathBuf::from(matches.get_arg("file").unwrap());
|
||||||
let contents = std::fs::read_to_string(file).unwrap();
|
let contents = std::fs::read_to_string(&file).unwrap();
|
||||||
|
let abs_filename = canonicalize(&file).unwrap();
|
||||||
|
|
||||||
let mut lexer = Lexer::new(None);
|
let mut lexer = Lexer::new(None);
|
||||||
let tokens = lexer.tokenize(&contents).unwrap();
|
let tokens = lexer.tokenize(&contents).unwrap();
|
||||||
@ -15,5 +18,5 @@ pub fn run(matches: ParserMatches) {
|
|||||||
let mut parser = Parser::new(None);
|
let mut parser = Parser::new(None);
|
||||||
let program = parser.parse(tokens).unwrap();
|
let program = parser.parse(tokens).unwrap();
|
||||||
|
|
||||||
eval(program);
|
eval(abs_filename, program).ok();
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use trunk_parser::{Statement, Param, Expression, InfixOp, CastKind};
|
use trunk_lexer::Lexer;
|
||||||
|
use trunk_parser::{Statement, Param, Expression, InfixOp, CastKind, MagicConst, Parser};
|
||||||
|
|
||||||
use self::environment::Environment;
|
use self::environment::Environment;
|
||||||
use self::value::Value;
|
use self::value::Value;
|
||||||
@ -14,14 +16,16 @@ pub struct Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
|
pub(crate) filename: PathBuf,
|
||||||
pub(crate) global_environment: Environment,
|
pub(crate) global_environment: Environment,
|
||||||
pub(crate) function_table: HashMap<String, Function>,
|
pub(crate) function_table: HashMap<String, Function>,
|
||||||
pub(crate) scopes: Vec<Environment>,
|
pub(crate) scopes: Vec<Environment>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
pub fn new() -> Self {
|
pub fn new(filename: PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
filename,
|
||||||
global_environment: Environment::new(),
|
global_environment: Environment::new(),
|
||||||
function_table: HashMap::default(),
|
function_table: HashMap::default(),
|
||||||
scopes: Vec::new(),
|
scopes: Vec::new(),
|
||||||
@ -29,8 +33,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(program: Vec<Statement>) -> Result<(), Escape> {
|
pub fn eval(filename: PathBuf, program: Vec<Statement>) -> Result<(), Escape> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new(filename);
|
||||||
for statement in program {
|
for statement in program {
|
||||||
eval_statement(&mut engine, statement)?;
|
eval_statement(&mut engine, statement)?;
|
||||||
}
|
}
|
||||||
@ -41,12 +45,22 @@ pub enum Escape {
|
|||||||
Return(Value),
|
Return(Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! extract {
|
||||||
|
($target:expr, $pattern:pat, $return:expr) => {
|
||||||
|
match $target {
|
||||||
|
$pattern => $return,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eval_statement(engine: &mut Engine, statement: Statement) -> Result<(), Escape> {
|
pub fn eval_statement(engine: &mut Engine, statement: Statement) -> Result<(), Escape> {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Function { .. } => eval_function(engine, statement)?,
|
Statement::Function { .. } => eval_function(engine, statement)?,
|
||||||
Statement::Echo { .. } => eval_echo(engine, statement)?,
|
Statement::Echo { .. } => eval_echo(engine, statement)?,
|
||||||
Statement::If { .. } => eval_if(engine, statement)?,
|
Statement::If { .. } => eval_if(engine, statement)?,
|
||||||
Statement::Return { .. } => return Err(Escape::Return(eval_return(engine, statement))),
|
Statement::Return { .. } => return Err(Escape::Return(eval_return(engine, statement))),
|
||||||
|
Statement::Include { .. } => eval_include(engine, statement)?,
|
||||||
_ => unimplemented!("{:?}", statement)
|
_ => unimplemented!("{:?}", statement)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,10 +116,7 @@ fn eval_if(engine: &mut Engine, statement: Statement) -> Result<(), Escape> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn eval_return(engine: &mut Engine, statement: Statement) -> Value {
|
fn eval_return(engine: &mut Engine, statement: Statement) -> Value {
|
||||||
let (value) = match statement {
|
let value = extract!(statement, Statement::Return { value }, value);
|
||||||
Statement::Return { value } => value,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
return eval_expression(engine, value);
|
return eval_expression(engine, value);
|
||||||
@ -114,12 +125,37 @@ fn eval_return(engine: &mut Engine, statement: Statement) -> Value {
|
|||||||
return Value::Null;
|
return Value::Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eval_include(engine: &mut Engine, statement: Statement) -> Result<(), Escape> {
|
||||||
|
let (kind, path) = extract!(statement, Statement::Include { kind, path }, (kind, path));
|
||||||
|
|
||||||
|
let path = extract!(eval_expression(engine, path), Value::String(value), value);
|
||||||
|
let original_filename = engine.filename.clone();
|
||||||
|
let contents = std::fs::read_to_string(&path).unwrap();
|
||||||
|
|
||||||
|
engine.filename = PathBuf::from(&path);
|
||||||
|
|
||||||
|
let mut lexer = Lexer::new(None);
|
||||||
|
let tokens = lexer.tokenize(&contents).unwrap();
|
||||||
|
|
||||||
|
let mut parser = Parser::new(None);
|
||||||
|
let ast = parser.parse(tokens).unwrap();
|
||||||
|
|
||||||
|
for statement in ast {
|
||||||
|
eval_statement(engine, statement)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.filename = original_filename;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_expression(engine: &mut Engine, expression: Expression) -> Value {
|
fn eval_expression(engine: &mut Engine, expression: Expression) -> Value {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::Infix { .. } => eval_infix_expression(engine, expression),
|
Expression::Infix { .. } => eval_infix_expression(engine, expression),
|
||||||
Expression::Call { .. } => eval_call_expression(engine, expression),
|
Expression::Call { .. } => eval_call_expression(engine, expression),
|
||||||
Expression::Variable { .. } => eval_variable_expression(engine, expression),
|
Expression::Variable { .. } => eval_variable_expression(engine, expression),
|
||||||
Expression::Cast { .. } => eval_cast_expression(engine, expression),
|
Expression::Cast { .. } => eval_cast_expression(engine, expression),
|
||||||
|
Expression::MagicConst { constant } => eval_magic_const(engine, constant),
|
||||||
Expression::Int { i } => Value::Int(i),
|
Expression::Int { i } => Value::Int(i),
|
||||||
Expression::ConstantString { value } => Value::String(value.into()),
|
Expression::ConstantString { value } => Value::String(value.into()),
|
||||||
_ => panic!("unhandled expression: {:?}", expression)
|
_ => panic!("unhandled expression: {:?}", expression)
|
||||||
@ -240,3 +276,13 @@ fn eval_cast_expression(engine: &mut Engine, expression: Expression) -> Value {
|
|||||||
_ => value,
|
_ => value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eval_magic_const(engine: &mut Engine, constant: MagicConst) -> Value {
|
||||||
|
match constant {
|
||||||
|
MagicConst::Dir => {
|
||||||
|
// FIXME: Sort this nasty code out.
|
||||||
|
Value::String(engine.filename.parent().unwrap().to_str().unwrap().to_string())
|
||||||
|
},
|
||||||
|
_ => todo!()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user