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