From 719920fa37ee9bd9210f5a46eeaf32a2292c706c Mon Sep 17 00:00:00 2001 From: Tanishq Kancharla Date: Mon, 27 Sep 2021 08:10:18 -0400 Subject: [PATCH] tried to move source command into parser (still doesn't compile) --- Cargo.lock | 1 + crates/nu-command/src/source.rs | 2 +- crates/nu-engine/src/eval.rs | 15 +++- crates/nu-parser/src/parser.rs | 108 +++++++++++++++++++++++++- crates/nu-protocol/src/value/mod.rs | 1 + crates/nu-protocol/src/value/range.rs | 1 + example.nu | 1 + 7 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 example.nu diff --git a/Cargo.lock b/Cargo.lock index 8948993d4c..acfbf68bc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,6 +277,7 @@ name = "nu-command" version = "0.1.0" dependencies = [ "nu-engine", + "nu-parser", "nu-protocol", ] diff --git a/crates/nu-command/src/source.rs b/crates/nu-command/src/source.rs index b50c7bfca9..1997bbea82 100644 --- a/crates/nu-command/src/source.rs +++ b/crates/nu-command/src/source.rs @@ -101,7 +101,7 @@ pub fn source(ctx: &EvaluationContext, call: &Call, input: Value) -> Result Result { @@ -239,3 +240,15 @@ pub fn eval_block( Ok(input) } + +// pub fn eval(context: &EvaluationContext, script: &str) -> Result { +// let engine_state = EngineState::new(); +// let mut working_set = StateWorkingSet::new(&engine_state); + +// let (block, err) = parse(&mut working_set, None, b"3", true); +// if let Some(e) = err { +// Err(e) +// } else { +// eval_block(context, &block, Value::nothing()) +// } +// } diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 86271281be..cab66c3e8d 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use crate::{ lex, lite_parse, type_check::{math_result_type, type_compatible}, @@ -10,7 +12,7 @@ use nu_protocol::{ RangeInclusion, RangeOperator, Statement, }, engine::StateWorkingSet, - span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId, + span, Flag, PositionalArg, ShellError, Signature, Span, SyntaxShape, Type, VarId, }; #[derive(Debug, Clone)] @@ -2299,6 +2301,7 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) { } } +/// Parser for the def command pub fn parse_def( working_set: &mut StateWorkingSet, spans: &[Span], @@ -2381,6 +2384,7 @@ pub fn parse_def( } } +/// Parser for the alias command pub fn parse_alias( working_set: &mut StateWorkingSet, spans: &[Span], @@ -2436,6 +2440,7 @@ pub fn parse_alias( ) } +/// Parse let command pub fn parse_let( working_set: &mut StateWorkingSet, spans: &[Span], @@ -2480,6 +2485,105 @@ pub fn parse_let( ) } +/// Parser for the source command +pub fn parse_source( + working_set: &mut StateWorkingSet, + spans: &[Span], +) -> (Statement, Option) { + let mut error = None; + let name = working_set.get_span_contents(spans[0]); + + if name == b"source" { + let (name_expr, err) = parse_string(working_set, spans[1]); + error = error.or(err); + + if let Some(filename) = name_expr.as_string() { + let source_file = Path::new(&filename); + // This is to stay consistent w/ the code taken from nushell + let path = source_file; + + let contents = std::fs::read(path); + + match contents { + Ok(contents) => { + let (block, err) = parse( + &mut working_set, + path.file_name().and_then(|x| x.to_str()), + &contents, + true, + ); + if let Some(e) = err { + ( + Statement::Pipeline(Pipeline::from_vec(vec![Expression { + expr: Expr::Garbage, + span: span(spans), + ty: Type::Unknown, + }])), + err, + ) + } else { + let block_id = working_set.add_block(block); + ( + // Why creating a pipeline here for only one expression? + // Is there a way to only make this a declaration? + Statement::Pipeline(Pipeline::from_vec(vec![Expression { + expr: Expr::Subexpression(block_id), + span: span(spans), + ty: Type::Unknown, // FIXME + }])), + None, + ) + } + } + Err(e) => ( + Statement::Pipeline(Pipeline::from_vec(vec![Expression { + expr: Expr::Garbage, + span: span(spans), + ty: Type::Unknown, + }])), + Some(ParseError::UnknownState(e.into(), span(spans))), + ), //(ShellError::InternalError("Can't load file to source".to_string())), + } + } else { + ( + Statement::Pipeline(Pipeline::from_vec(vec![Expression { + expr: Expr::Garbage, + span: span(spans), + ty: Type::Unknown, + }])), + Some(ParseError::Mismatch( + "string".into(), + // Can this be better? + "incompatible string".into(), + spans[1], + )), + ) + } + } else { + // Not source command? + ( + Statement::Pipeline(Pipeline::from_vec(vec![Expression { + expr: Expr::Garbage, + span: span(spans), + ty: Type::Unknown, + }])), + error, + ) + } + // ( + // Statement::Pipeline(Pipeline::from_vec(vec![Expression { + // expr: Expr::Garbage, + // span: span(spans), + // ty: Type::Unknown, + // }])), + // Some(ParseError::UnknownState( + // "internal error: let statement unparseable".into(), + // span(spans), + // )), + // ) +} + +/// Parse a statement. Check if def, let, alias, or source command can process it properly pub fn parse_statement( working_set: &mut StateWorkingSet, spans: &[Span], @@ -2491,6 +2595,8 @@ pub fn parse_statement( (stmt, None) } else if let (stmt, None) = parse_alias(working_set, spans) { (stmt, None) + } else if let (decl, None) = parse_source(working_set, spans) { + (decl, None) } else { let (expr, err) = parse_expression(working_set, spans); (Statement::Pipeline(Pipeline::from_vec(vec![expr])), err) diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index d02f1ce2d4..815a0fabfd 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -179,6 +179,7 @@ impl Value { } } + /// Follow a given column path into the value: for example accessing nth elements in a stream or list pub fn follow_cell_path(self, column_path: &[PathMember]) -> Result { let mut current = self; for member in column_path { diff --git a/crates/nu-protocol/src/value/range.rs b/crates/nu-protocol/src/value/range.rs index 54d836de16..6c7de36166 100644 --- a/crates/nu-protocol/src/value/range.rs +++ b/crates/nu-protocol/src/value/range.rs @@ -1,5 +1,6 @@ use crate::{ast::RangeInclusion, *}; +/// A Range is an iterator over integers. #[derive(Debug, Clone, PartialEq)] pub struct Range { pub from: Value, diff --git a/example.nu b/example.nu new file mode 100644 index 0000000000..a157d1a3ce --- /dev/null +++ b/example.nu @@ -0,0 +1 @@ +length [1,2,3,4] \ No newline at end of file