start expanding eval

This commit is contained in:
JT 2021-07-23 17:14:49 +12:00
parent 8c6feb7e80
commit 3eefa6dec8
6 changed files with 147 additions and 98 deletions

View File

@ -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
}

View File

@ -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 {

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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")
}
}