From 697bf16f261e2930915203354e106e042f6d61b9 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 16 Jul 2021 13:10:22 +1200 Subject: [PATCH] Start moving towards decls and add a simple eval --- src/declaration.rs | 7 ++++ src/eval.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 10 ++++- src/main.rs | 20 ++++++---- src/parser.rs | 34 ++++++++-------- src/parser_state.rs | 22 +++++++---- src/signature.rs | 11 +++++- 7 files changed, 164 insertions(+), 35 deletions(-) create mode 100644 src/declaration.rs create mode 100644 src/eval.rs diff --git a/src/declaration.rs b/src/declaration.rs new file mode 100644 index 0000000000..d555bffc3a --- /dev/null +++ b/src/declaration.rs @@ -0,0 +1,7 @@ +use crate::{BlockId, Signature}; + +#[derive(Clone, Debug)] +pub struct Declaration { + pub signature: Signature, + pub body: Option, +} diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 0000000000..76fb864d12 --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,95 @@ +use crate::{parser::Operator, Block, Expr, Expression, Span, Statement}; + +#[derive(Debug)] +pub enum ShellError { + Mismatch(String, Span), + Unsupported(Span), +} + +pub struct Engine; + +#[derive(Debug)] +pub enum Value { + Int { val: i64, span: Span }, + Unknown, +} + +impl Value { + pub fn add(&self, rhs: &Value) -> Result { + match (self, rhs) { + (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int { + val: lhs + rhs, + span: Span::unknown(), + }), + _ => Ok(Value::Unknown), + } + } +} + +impl Default for Engine { + fn default() -> Self { + Self::new() + } +} + +impl Engine { + pub fn new() -> Self { + Self + } + + pub fn eval_operator(&self, op: &Expression) -> Result { + match op { + Expression { + expr: Expr::Operator(operator), + .. + } => Ok(operator.clone()), + Expression { span, .. } => Err(ShellError::Mismatch("operator".to_string(), *span)), + } + } + + pub fn eval_expression(&self, expr: &Expression) -> Result { + match expr.expr { + Expr::Int(i) => Ok(Value::Int { + val: i, + span: expr.span, + }), + Expr::Var(v) => 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::Garbage => Err(ShellError::Unsupported(expr.span)), + } + } + + pub fn eval_block(&self, block: &Block) -> Result { + 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), + _ => {} + } + } + _ => {} + }, + _ => {} + } + } + + last + } +} diff --git a/src/lib.rs b/src/lib.rs index de7b4e7c59..26380f90ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +mod declaration; +mod eval; mod lex; mod lite_parse; mod parse_error; @@ -6,10 +8,14 @@ mod parser_state; mod signature; mod span; +pub use declaration::Declaration; +pub use eval::Engine; pub use lex::{lex, LexMode, Token, TokenContents}; pub use lite_parse::{lite_parse, LiteBlock, LiteCommand, LiteStatement}; pub use parse_error::ParseError; -pub use parser::{Call, Expr, Expression, Import, Pipeline, Statement, SyntaxShape, VarDecl}; -pub use parser_state::{DeclId, ParserState, ParserWorkingSet, VarId}; +pub use parser::{ + Block, Call, Expr, Expression, Import, Pipeline, Statement, SyntaxShape, VarDecl, +}; +pub use parser_state::{BlockId, DeclId, ParserState, ParserWorkingSet, VarId}; pub use signature::Signature; pub use span::Span; diff --git a/src/main.rs b/src/main.rs index 1503cbfec6..1adbb40370 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,20 @@ -use engine_q::{ParserWorkingSet, Signature, SyntaxShape}; +use engine_q::{Engine, ParserWorkingSet, Signature, SyntaxShape}; fn main() -> std::io::Result<()> { if let Some(path) = std::env::args().nth(1) { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let sig = Signature::build("bar") .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')) .switch("--rock", "rock!!", Some('r')); - working_set.add_decl((b"bar").to_vec(), sig); + working_set.add_decl((b"bar").to_vec(), sig.into()); let sig = Signature::build("where").required("cond", SyntaxShape::RowCondition, "condition"); - working_set.add_decl((b"where").to_vec(), sig); + working_set.add_decl((b"where").to_vec(), sig.into()); let sig = Signature::build("if") .required("cond", SyntaxShape::RowCondition, "condition") @@ -25,7 +25,7 @@ fn main() -> std::io::Result<()> { "else keyword", ) .required("else_block", SyntaxShape::Block, "else block"); - working_set.add_decl((b"if").to_vec(), sig); + working_set.add_decl((b"if").to_vec(), sig.into()); let sig = Signature::build("let") .required("var_name", SyntaxShape::Variable, "variable name") @@ -35,7 +35,7 @@ fn main() -> std::io::Result<()> { SyntaxShape::Expression, "the value to set the variable to", ); - working_set.add_decl((b"let").to_vec(), sig); + working_set.add_decl((b"let").to_vec(), sig.into()); let sig = Signature::build("alias") .required("var_name", SyntaxShape::Variable, "variable name") @@ -45,14 +45,14 @@ fn main() -> std::io::Result<()> { SyntaxShape::Expression, "the value to set the variable to", ); - working_set.add_decl((b"alias").to_vec(), sig); + working_set.add_decl((b"alias").to_vec(), sig.into()); let sig = Signature::build("sum").required( "arg", SyntaxShape::List(Box::new(SyntaxShape::Number)), "list of numbers", ); - working_set.add_decl((b"sum").to_vec(), sig); + working_set.add_decl((b"sum").to_vec(), sig.into()); //let file = std::fs::read(&path)?; //let (output, err) = working_set.parse_file(&path, file); @@ -61,6 +61,10 @@ fn main() -> std::io::Result<()> { println!("error: {:?}", err); // println!("{}", size_of::()); + let engine = Engine::new(); + let result = engine.eval_block(&output); + println!("{:?}", result); + // let mut buffer = String::new(); // let stdin = std::io::stdin(); // let mut handle = stdin.lock(); diff --git a/src/parser.rs b/src/parser.rs index eab43199d6..3d7e1889d4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -137,8 +137,8 @@ pub enum Expr { #[derive(Debug, Clone)] pub struct Expression { - expr: Expr, - span: Span, + pub expr: Expr, + pub span: Span, } impl Expression { pub fn garbage(span: Span) -> Expression { @@ -504,7 +504,7 @@ impl ParserWorkingSet { let mut call = Call::new(); call.decl_id = decl_id; - let sig = self + let decl = self .get_decl(decl_id) .expect("internal error: bad DeclId") .clone(); @@ -520,7 +520,8 @@ impl ParserWorkingSet { let arg_span = spans[spans_idx]; // Check if we're on a long flag, if so, parse - let (long_name, arg, err) = self.parse_long_flag(spans, &mut spans_idx, &sig); + let (long_name, arg, err) = + self.parse_long_flag(spans, &mut spans_idx, &decl.signature); if let Some(long_name) = long_name { // We found a long flag, like --bar error = error.or(err); @@ -531,7 +532,7 @@ impl ParserWorkingSet { // Check if we're on a short flag or group of short flags, if so, parse let (short_flags, err) = - self.parse_short_flags(spans, &mut spans_idx, positional_idx, &sig); + self.parse_short_flags(spans, &mut spans_idx, positional_idx, &decl.signature); if let Some(short_flags) = short_flags { error = error.or(err); @@ -555,9 +556,9 @@ impl ParserWorkingSet { } // Parse a positional arg if there is one - if let Some(positional) = sig.get_positional(positional_idx) { + if let Some(positional) = decl.signature.get_positional(positional_idx) { //Make sure we leave enough spans for the remaining positionals - let remainder = sig.num_positionals() - positional_idx; + let remainder = decl.signature.num_positionals() - positional_idx; let (arg, err) = self.parse_multispan_value( &spans[..(spans.len() - remainder + 1)], @@ -575,7 +576,7 @@ impl ParserWorkingSet { spans_idx += 1; } - let err = check_call(spans[0], &sig, &call); + let err = check_call(spans[0], &decl.signature, &call); error = error.or(err); // FIXME: type unknown @@ -1185,6 +1186,7 @@ impl ParserWorkingSet { expr_stack.push(lhs); while idx < spans.len() { + println!("idx: {}", idx); let (op, err) = self.parse_operator(spans[idx]); error = error.or(err); @@ -1417,7 +1419,7 @@ mod tests { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (block, err) = working_set.parse_source(b"foo"); @@ -1440,7 +1442,7 @@ mod tests { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo --jazz"); assert!(matches!(err, Some(ParseError::MissingFlagParam(..)))); @@ -1451,7 +1453,7 @@ mod tests { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo -j"); assert!(matches!(err, Some(ParseError::MissingFlagParam(..)))); @@ -1464,7 +1466,7 @@ mod tests { let sig = Signature::build("foo") .named("--jazz", SyntaxShape::Int, "jazz!!", Some('j')) .named("--math", SyntaxShape::Int, "math!!", Some('m')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo -mj"); assert!(matches!( err, @@ -1477,7 +1479,7 @@ mod tests { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo -mj"); assert!(matches!(err, Some(ParseError::UnknownFlag(..)))); } @@ -1487,7 +1489,7 @@ mod tests { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j')); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo -j 100"); assert!(matches!(err, Some(ParseError::ExtraPositional(..)))); } @@ -1497,7 +1499,7 @@ mod tests { let mut working_set = ParserWorkingSet::new(None); let sig = Signature::build("foo").required("jazz", SyntaxShape::Int, "jazz!!"); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo"); assert!(matches!(err, Some(ParseError::MissingPositional(..)))); } @@ -1508,7 +1510,7 @@ mod tests { let sig = Signature::build("foo").required_named("--jazz", SyntaxShape::Int, "jazz!!", None); - working_set.add_decl((b"foo").to_vec(), sig); + working_set.add_decl((b"foo").to_vec(), sig.into()); let (_, err) = working_set.parse_source(b"foo"); assert!(matches!(err, Some(ParseError::MissingRequiredFlag(..)))); } diff --git a/src/parser_state.rs b/src/parser_state.rs index 76451ab233..861dda523f 100644 --- a/src/parser_state.rs +++ b/src/parser_state.rs @@ -1,11 +1,12 @@ -use crate::{Signature, Span}; +use crate::{parser::Block, Declaration, Signature, Span}; use std::{collections::HashMap, sync::Arc}; pub struct ParserState { files: Vec<(String, usize, usize)>, file_contents: Vec, vars: Vec, - decls: Vec, + decls: Vec, + blocks: Vec, } #[derive(Clone, Copy, Debug)] @@ -16,6 +17,7 @@ pub enum Type { pub type VarId = usize; pub type DeclId = usize; +pub type BlockId = usize; #[derive(Debug)] struct ScopeFrame { @@ -45,6 +47,7 @@ impl ParserState { file_contents: vec![], vars: vec![], decls: vec![], + blocks: vec![], } } @@ -58,6 +61,7 @@ impl ParserState { this.file_contents.extend(working_set.file_contents); this.decls.extend(working_set.decls); this.vars.extend(working_set.vars); + this.blocks.extend(working_set.blocks); //FIXME: add scope frame merging } else { @@ -81,7 +85,7 @@ impl ParserState { self.vars.get(var_id) } - pub fn get_decl(&self, decl_id: DeclId) -> Option<&Signature> { + pub fn get_decl(&self, decl_id: DeclId) -> Option<&Declaration> { self.decls.get(decl_id) } @@ -106,8 +110,9 @@ impl ParserState { pub struct ParserWorkingSet { files: Vec<(String, usize, usize)>, pub(crate) file_contents: Vec, - vars: Vec, // indexed by VarId - decls: Vec, // indexed by DeclId + vars: Vec, // indexed by VarId + decls: Vec, // indexed by DeclId + blocks: Vec, // indexed by BlockId permanent_state: Option>, scope: Vec, } @@ -119,6 +124,7 @@ impl ParserWorkingSet { file_contents: vec![], vars: vec![], decls: vec![], + blocks: vec![], permanent_state, scope: vec![ScopeFrame::new()], } @@ -134,13 +140,13 @@ impl ParserWorkingSet { self.files.len() + parent_len } - pub fn add_decl(&mut self, name: Vec, sig: Signature) -> DeclId { + pub fn add_decl(&mut self, name: Vec, decl: Declaration) -> DeclId { let scope_frame = self .scope .last_mut() .expect("internal error: missing required scope frame"); - self.decls.push(sig); + self.decls.push(decl); let decl_id = self.decls.len() - 1; scope_frame.decls.insert(name, decl_id); @@ -246,7 +252,7 @@ impl ParserWorkingSet { } } - pub fn get_decl(&self, decl_id: DeclId) -> Option<&Signature> { + pub fn get_decl(&self, decl_id: DeclId) -> Option<&Declaration> { if let Some(permanent_state) = &self.permanent_state { let num_permanent_decls = permanent_state.num_decls(); if decl_id < num_permanent_decls { diff --git a/src/signature.rs b/src/signature.rs index f2a0874652..f83df6871e 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,4 +1,4 @@ -use crate::parser::SyntaxShape; +use crate::{parser::SyntaxShape, Declaration}; #[derive(Debug, Clone)] pub struct Flag { @@ -216,3 +216,12 @@ impl Signature { None } } + +impl Into for Signature { + fn into(self) -> Declaration { + Declaration { + signature: self, + body: None, + } + } +}