mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 07:30:13 +01:00
start expanding eval
This commit is contained in:
parent
8c6feb7e80
commit
3eefa6dec8
148
src/eval.rs
148
src/eval.rs
@ -1,19 +1,19 @@
|
||||
use crate::{parser::Operator, Block, Expr, Expression, Span, Statement};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{parser::Operator, Block, Call, Expr, Expression, ParserState, Span, Statement, VarId};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ShellError {
|
||||
Mismatch(String, Span),
|
||||
Unsupported(Span),
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
pub struct Engine;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Value {
|
||||
Int { val: i64, span: Span },
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn add(&self, rhs: &Value) -> Result<Value, ShellError> {
|
||||
match (self, rhs) {
|
||||
@ -26,71 +26,99 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Engine {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
pub struct State<'a> {
|
||||
pub parser_state: &'a ParserState,
|
||||
}
|
||||
|
||||
pub struct Stack {
|
||||
pub vars: HashMap<VarId, Value>,
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn get_var(&self, var_id: VarId) -> Result<Value, ShellError> {
|
||||
match self.vars.get(&var_id) {
|
||||
Some(v) => Ok(v.clone()),
|
||||
_ => Err(ShellError::InternalError("variable not found".into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
pub fn eval_operator(
|
||||
state: &State,
|
||||
stack: &mut Stack,
|
||||
op: &Expression,
|
||||
) -> Result<Operator, ShellError> {
|
||||
match op {
|
||||
Expression {
|
||||
expr: Expr::Operator(operator),
|
||||
..
|
||||
} => Ok(operator.clone()),
|
||||
Expression { span, .. } => Err(ShellError::Mismatch("operator".to_string(), *span)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_operator(&self, op: &Expression) -> Result<Operator, ShellError> {
|
||||
match op {
|
||||
Expression {
|
||||
expr: Expr::Operator(operator),
|
||||
..
|
||||
} => Ok(operator.clone()),
|
||||
Expression { span, .. } => Err(ShellError::Mismatch("operator".to_string(), *span)),
|
||||
}
|
||||
fn eval_call(state: &State, stack: &mut Stack, call: &Call) -> Result<Value, ShellError> {
|
||||
let decl = state.parser_state.get_decl(call.decl_id);
|
||||
|
||||
if let Some(block_id) = decl.body {
|
||||
let block = state.parser_state.get_block(block_id);
|
||||
eval_block(state, stack, block)
|
||||
} else {
|
||||
Ok(Value::Unknown)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_expression(&self, expr: &Expression) -> Result<Value, ShellError> {
|
||||
match expr.expr {
|
||||
Expr::Int(i) => Ok(Value::Int {
|
||||
val: i,
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::Var(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Call(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Operator(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::BinaryOp(_, _, _) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Subexpression(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Block(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::List(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Table(_, _) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Literal(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::String(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Signature(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Garbage => Err(ShellError::Unsupported(expr.span)),
|
||||
}
|
||||
}
|
||||
pub fn eval_expression(
|
||||
state: &State,
|
||||
stack: &mut Stack,
|
||||
expr: &Expression,
|
||||
) -> Result<Value, ShellError> {
|
||||
match &expr.expr {
|
||||
Expr::Int(i) => Ok(Value::Int {
|
||||
val: *i,
|
||||
span: expr.span,
|
||||
}),
|
||||
Expr::Var(var_id) => stack.get_var(*var_id),
|
||||
Expr::Call(call) => eval_call(state, stack, call),
|
||||
Expr::ExternalCall(_, _) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Operator(_) => Ok(Value::Unknown),
|
||||
Expr::BinaryOp(lhs, op, rhs) => {
|
||||
let lhs = eval_expression(state, stack, &lhs)?;
|
||||
let op = eval_operator(state, stack, &op)?;
|
||||
let rhs = eval_expression(state, stack, &rhs)?;
|
||||
|
||||
pub fn eval_block(&self, block: &Block) -> Result<Value, ShellError> {
|
||||
let mut last = Ok(Value::Unknown);
|
||||
|
||||
for stmt in &block.stmts {
|
||||
match stmt {
|
||||
Statement::Expression(expression) => match &expression.expr {
|
||||
Expr::BinaryOp(lhs, op, rhs) => {
|
||||
let lhs = self.eval_expression(&lhs)?;
|
||||
let op = self.eval_operator(&op)?;
|
||||
let rhs = self.eval_expression(&rhs)?;
|
||||
|
||||
match op {
|
||||
Operator::Plus => last = lhs.add(&rhs),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
match op {
|
||||
Operator::Plus => lhs.add(&rhs),
|
||||
_ => Ok(Value::Unknown),
|
||||
}
|
||||
}
|
||||
|
||||
last
|
||||
Expr::Subexpression(block_id) => {
|
||||
let block = state.parser_state.get_block(*block_id);
|
||||
|
||||
eval_block(state, stack, block)
|
||||
}
|
||||
Expr::Block(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::List(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Table(_, _) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Literal(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::String(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Signature(_) => Err(ShellError::Unsupported(expr.span)),
|
||||
Expr::Garbage => Err(ShellError::Unsupported(expr.span)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_block(state: &State, stack: &mut Stack, block: &Block) -> Result<Value, ShellError> {
|
||||
let mut last = Ok(Value::Unknown);
|
||||
|
||||
for stmt in &block.stmts {
|
||||
match stmt {
|
||||
Statement::Expression(expression) => {
|
||||
last = Ok(eval_expression(state, stack, expression)?);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
last
|
||||
}
|
||||
|
@ -38,10 +38,7 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
output.extend(self.flatten_expression(&rhs));
|
||||
output
|
||||
}
|
||||
Expr::Block(block_id) => self.flatten_block(
|
||||
self.get_block(*block_id)
|
||||
.expect("internal error: missing block"),
|
||||
),
|
||||
Expr::Block(block_id) => self.flatten_block(self.get_block(*block_id)),
|
||||
Expr::Call(call) => {
|
||||
let mut output = vec![];
|
||||
output.push((call.head, FlatShape::InternalCall));
|
||||
@ -78,10 +75,7 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
Expr::String(_) => {
|
||||
vec![(expr.span, FlatShape::String)]
|
||||
}
|
||||
Expr::Subexpression(block_id) => self.flatten_block(
|
||||
self.get_block(*block_id)
|
||||
.expect("internal error: missing block"),
|
||||
),
|
||||
Expr::Subexpression(block_id) => self.flatten_block(self.get_block(*block_id)),
|
||||
Expr::Table(headers, cells) => {
|
||||
let mut output = vec![];
|
||||
for e in headers {
|
||||
|
@ -13,7 +13,7 @@ mod syntax_highlight;
|
||||
mod tests;
|
||||
|
||||
pub use declaration::Declaration;
|
||||
pub use eval::Engine;
|
||||
pub use eval::{eval_block, eval_expression, Stack, State};
|
||||
pub use lex::{lex, Token, TokenContents};
|
||||
pub use lite_parse::{lite_parse, LiteBlock, LiteCommand, LiteStatement};
|
||||
pub use parse_error::ParseError;
|
||||
|
41
src/main.rs
41
src/main.rs
@ -1,6 +1,8 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||
|
||||
use engine_q::{NuHighlighter, ParserState, ParserWorkingSet, Signature, SyntaxShape};
|
||||
use engine_q::{
|
||||
eval_block, NuHighlighter, ParserState, ParserWorkingSet, Signature, Stack, State, SyntaxShape,
|
||||
};
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let parser_state = Rc::new(RefCell::new(ParserState::new()));
|
||||
@ -82,14 +84,15 @@ fn main() -> std::io::Result<()> {
|
||||
}
|
||||
|
||||
if let Some(path) = std::env::args().nth(1) {
|
||||
// let file = std::fs::read(&path)?;
|
||||
// let (output, err) = working_set.parse_file(&path, file);
|
||||
|
||||
let parser_state = parser_state.borrow();
|
||||
let mut working_set = ParserWorkingSet::new(&*parser_state);
|
||||
let (output, err) = working_set.parse_source(path.as_bytes(), false);
|
||||
println!("{:#?}", output);
|
||||
println!("error: {:?}", err);
|
||||
|
||||
let file = std::fs::read(&path)?;
|
||||
|
||||
let (block, err) = working_set.parse_file(&path, &file, false);
|
||||
println!("{}", block.len());
|
||||
// println!("{:#?}", output);
|
||||
// println!("error: {:?}", err);
|
||||
|
||||
//println!("working set: {:#?}", working_set);
|
||||
|
||||
@ -128,9 +131,9 @@ fn main() -> std::io::Result<()> {
|
||||
if s.trim() == "exit" {
|
||||
break;
|
||||
}
|
||||
println!("input: '{}'", s);
|
||||
// println!("input: '{}'", s);
|
||||
|
||||
let delta = {
|
||||
let (block, delta) = {
|
||||
let parser_state = parser_state.borrow();
|
||||
let mut working_set = ParserWorkingSet::new(&*parser_state);
|
||||
let (output, err) = working_set.parse_file(
|
||||
@ -139,12 +142,24 @@ fn main() -> std::io::Result<()> {
|
||||
false,
|
||||
);
|
||||
println!("{:?}", output);
|
||||
println!("Error: {:?}", err);
|
||||
working_set.render()
|
||||
if let Some(err) = err {
|
||||
println!("Error: {:?}", err);
|
||||
}
|
||||
// println!("Error: {:?}", err);
|
||||
(output, working_set.render())
|
||||
};
|
||||
|
||||
ParserState::merge_delta(&mut *parser_state.borrow_mut(), delta);
|
||||
// println!("{:#?}", parser_state);
|
||||
|
||||
let mut stack = Stack {
|
||||
vars: HashMap::new(),
|
||||
};
|
||||
let state = State {
|
||||
parser_state: &*parser_state.borrow(),
|
||||
};
|
||||
|
||||
let output = eval_block(&state, &mut stack, &block);
|
||||
println!("{:#?}", output);
|
||||
}
|
||||
Signal::CtrlC => {
|
||||
println!("Ctrl-c");
|
||||
|
@ -561,10 +561,7 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
call.decl_id = decl_id;
|
||||
call.head = command_span;
|
||||
|
||||
let decl = self
|
||||
.get_decl(decl_id)
|
||||
.expect("internal error: bad DeclId")
|
||||
.clone();
|
||||
let decl = self.get_decl(decl_id).clone();
|
||||
|
||||
// The index into the positional parameter in the definition
|
||||
let mut positional_idx = 0;
|
||||
|
@ -89,16 +89,22 @@ impl ParserState {
|
||||
self.blocks.len()
|
||||
}
|
||||
|
||||
pub fn get_var(&self, var_id: VarId) -> Option<&Type> {
|
||||
self.vars.get(var_id)
|
||||
pub fn get_var(&self, var_id: VarId) -> &Type {
|
||||
self.vars
|
||||
.get(var_id)
|
||||
.expect("internal error: missing variable")
|
||||
}
|
||||
|
||||
pub fn get_decl(&self, decl_id: DeclId) -> Option<&Declaration> {
|
||||
self.decls.get(decl_id)
|
||||
pub fn get_decl(&self, decl_id: DeclId) -> &Declaration {
|
||||
self.decls
|
||||
.get(decl_id)
|
||||
.expect("internal error: missing declaration")
|
||||
}
|
||||
|
||||
pub fn get_block(&self, block_id: BlockId) -> Option<&Block> {
|
||||
self.blocks.get(block_id)
|
||||
pub fn get_block(&self, block_id: BlockId) -> &Block {
|
||||
self.blocks
|
||||
.get(block_id)
|
||||
.expect("internal error: missing block")
|
||||
}
|
||||
|
||||
pub fn next_span_start(&self) -> usize {
|
||||
@ -318,30 +324,39 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
next_id
|
||||
}
|
||||
|
||||
pub fn get_variable(&self, var_id: VarId) -> Option<&Type> {
|
||||
pub fn get_variable(&self, var_id: VarId) -> &Type {
|
||||
let num_permanent_vars = self.permanent_state.num_vars();
|
||||
if var_id < num_permanent_vars {
|
||||
self.permanent_state.get_var(var_id)
|
||||
} else {
|
||||
self.delta.vars.get(var_id - num_permanent_vars)
|
||||
self.delta
|
||||
.vars
|
||||
.get(var_id - num_permanent_vars)
|
||||
.expect("internal error: missing variable")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_decl(&self, decl_id: DeclId) -> Option<&Declaration> {
|
||||
pub fn get_decl(&self, decl_id: DeclId) -> &Declaration {
|
||||
let num_permanent_decls = self.permanent_state.num_decls();
|
||||
if decl_id < num_permanent_decls {
|
||||
self.permanent_state.get_decl(decl_id)
|
||||
} else {
|
||||
self.delta.decls.get(decl_id - num_permanent_decls)
|
||||
self.delta
|
||||
.decls
|
||||
.get(decl_id - num_permanent_decls)
|
||||
.expect("internal error: missing declaration")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_block(&self, block_id: BlockId) -> Option<&Block> {
|
||||
pub fn get_block(&self, block_id: BlockId) -> &Block {
|
||||
let num_permanent_blocks = self.permanent_state.num_blocks();
|
||||
if block_id < num_permanent_blocks {
|
||||
self.permanent_state.get_block(block_id)
|
||||
} else {
|
||||
self.delta.blocks.get(block_id - num_permanent_blocks)
|
||||
self.delta
|
||||
.blocks
|
||||
.get(block_id - num_permanent_blocks)
|
||||
.expect("internal error: missing block")
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user