Start moving towards decls and add a simple eval

This commit is contained in:
JT 2021-07-16 13:10:22 +12:00
parent 9916f35b22
commit 697bf16f26
7 changed files with 164 additions and 35 deletions

7
src/declaration.rs Normal file
View file

@ -0,0 +1,7 @@
use crate::{BlockId, Signature};
#[derive(Clone, Debug)]
pub struct Declaration {
pub signature: Signature,
pub body: Option<BlockId>,
}

95
src/eval.rs Normal file
View file

@ -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<Value, ShellError> {
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<Operator, ShellError> {
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<Value, ShellError> {
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<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),
_ => {}
}
}
_ => {}
},
_ => {}
}
}
last
}
}

View file

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

View file

@ -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::<Statement>());
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();

View file

@ -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(..))));
}

View file

@ -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<u8>,
vars: Vec<Type>,
decls: Vec<Signature>,
decls: Vec<Declaration>,
blocks: Vec<Block>,
}
#[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<u8>,
vars: Vec<Type>, // indexed by VarId
decls: Vec<Signature>, // indexed by DeclId
vars: Vec<Type>, // indexed by VarId
decls: Vec<Declaration>, // indexed by DeclId
blocks: Vec<Block>, // indexed by BlockId
permanent_state: Option<Arc<ParserState>>,
scope: Vec<ScopeFrame>,
}
@ -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<u8>, sig: Signature) -> DeclId {
pub fn add_decl(&mut self, name: Vec<u8>, 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 {

View file

@ -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<Declaration> for Signature {
fn into(self) -> Declaration {
Declaration {
signature: self,
body: None,
}
}
}