mirror of
https://github.com/nushell/nushell
synced 2024-12-28 05:53:09 +00:00
Start moving towards decls and add a simple eval
This commit is contained in:
parent
9916f35b22
commit
697bf16f26
7 changed files with 164 additions and 35 deletions
7
src/declaration.rs
Normal file
7
src/declaration.rs
Normal 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
95
src/eval.rs
Normal 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
|
||||
}
|
||||
}
|
10
src/lib.rs
10
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;
|
||||
|
|
20
src/main.rs
20
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::<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();
|
||||
|
|
|
@ -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(..))));
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue