From b9bde648edce79b99d4744c23fa0d500ca3bb9d4 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy <mmstickman@gmail.com> Date: Sun, 1 Jul 2018 11:25:28 -0600 Subject: [PATCH] Concatenate, ConcatenateHead, & Filter Assignment Operators --- .../lexers/src}/assignments/keys.rs | 105 +---------- members/lexers/src/assignments/mod.rs | 170 ++++++++++++++++++ members/lexers/src/assignments/operator.rs | 55 ++++++ members/lexers/src/assignments/primitive.rs | 95 ++++++++++ members/lexers/src/lib.rs | 4 +- src/lib/parser/assignments/actions.rs | 10 +- src/lib/parser/assignments/checker.rs | 6 +- src/lib/parser/assignments/mod.rs | 8 +- src/lib/parser/assignments/operator.rs | 42 ----- src/lib/parser/assignments/splitter.rs | 79 -------- src/lib/parser/mod.rs | 2 +- src/lib/parser/statement/functions.rs | 5 +- src/lib/parser/statement/parse.rs | 32 +--- src/lib/shell/assignments.rs | 2 + src/lib/shell/flow_control.rs | 1 + 15 files changed, 348 insertions(+), 268 deletions(-) rename {src/lib/parser => members/lexers/src}/assignments/keys.rs (68%) create mode 100644 members/lexers/src/assignments/mod.rs create mode 100644 members/lexers/src/assignments/operator.rs create mode 100644 members/lexers/src/assignments/primitive.rs delete mode 100644 src/lib/parser/assignments/operator.rs delete mode 100644 src/lib/parser/assignments/splitter.rs diff --git a/src/lib/parser/assignments/keys.rs b/members/lexers/src/assignments/keys.rs similarity index 68% rename from src/lib/parser/assignments/keys.rs rename to members/lexers/src/assignments/keys.rs index 365827d4..fe2ce475 100644 --- a/src/lib/parser/assignments/keys.rs +++ b/members/lexers/src/assignments/keys.rs @@ -1,9 +1,10 @@ use std::fmt::{self, Display, Formatter}; +use super::Primitive; /// Keys are used in assignments to define which variable will be set, and whether the correct /// types are being assigned. #[derive(Debug, PartialEq, Clone)] -pub(crate) struct Key<'a> { +pub struct Key<'a> { pub kind: Primitive, pub name: &'a str, } @@ -11,13 +12,13 @@ pub(crate) struct Key<'a> { /// Functions require that their keys to have a longer lifetime, and that is made possible /// by eliminating the lifetime requirements via allocating a `String`. #[derive(Debug, PartialEq, Clone)] -pub(crate) struct KeyBuf { +pub struct KeyBuf { pub kind: Primitive, pub name: String, } #[derive(Debug, PartialEq)] -pub(crate) enum TypeError { +pub enum TypeError { Invalid(String), BadValue(Primitive), } @@ -49,103 +50,9 @@ impl<'a> From<Key<'a>> for KeyBuf { } } -/// A primitive defines the type that a requested value should satisfy. -#[derive(Debug, PartialEq, Clone)] -pub enum Primitive { - Any, - AnyArray, - Str, - StrArray, - Boolean, - BooleanArray, - Integer, - IntegerArray, - Float, - FloatArray, - HashMap(Box<Primitive>), - BTreeMap(Box<Primitive>), - Indexed(String, Box<Primitive>), -} - -impl Primitive { - fn parse(data: &str) -> Option<Primitive> { - let data = match data { - "[]" => Primitive::AnyArray, - "str" => Primitive::Str, - "str[]" => Primitive::StrArray, - "bool" => Primitive::Boolean, - "bool[]" => Primitive::BooleanArray, - "int" => Primitive::Integer, - "int[]" => Primitive::IntegerArray, - "float" => Primitive::Float, - "float[]" => Primitive::FloatArray, - kind => { - fn parse_inner_hash_map(inner: &str) -> Option<Primitive> { - match inner { - "" => Some(Primitive::HashMap(Box::new(Primitive::Any))), - _ => Primitive::parse(inner).map(|p| Primitive::HashMap(Box::new(p))) - } - } - fn parse_inner_btree_map(inner: &str) -> Option<Primitive> { - match inner { - "" => Some(Primitive::BTreeMap(Box::new(Primitive::Any))), - _ => Primitive::parse(inner).map(|p| Primitive::BTreeMap(Box::new(p))) - } - } - - let res = if kind.starts_with("hmap[") { - let kind = &kind[5..]; - kind.rfind(']').map(|found| &kind[..found]).and_then(parse_inner_hash_map) - } else if kind.starts_with("bmap[") { - let kind = &kind[5..]; - kind.rfind(']').map(|found| &kind[..found]).and_then(parse_inner_btree_map) - } else { - None - }; - - if let Some(data) = res { - data - } else { - return None; - } - } - }; - Some(data) - } -} - -impl Display for Primitive { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match *self { - Primitive::Any | Primitive::Str => write!(f, "str"), - Primitive::AnyArray => write!(f, "[]"), - Primitive::Boolean => write!(f, "bool"), - Primitive::BooleanArray => write!(f, "bool[]"), - Primitive::Float => write!(f, "float"), - Primitive::FloatArray => write!(f, "float[]"), - Primitive::Integer => write!(f, "int"), - Primitive::IntegerArray => write!(f, "int[]"), - Primitive::StrArray => write!(f, "str[]"), - Primitive::HashMap(ref kind) => { - match **kind { - Primitive::Any | Primitive::Str => write!(f, "hmap[]"), - ref kind => write!(f, "hmap[{}]", kind), - } - } - Primitive::BTreeMap(ref kind) => { - match **kind { - Primitive::Any | Primitive::Str => write!(f, "bmap[]"), - ref kind => write!(f, "bmap[{}]", kind), - } - } - Primitive::Indexed(_, ref kind) => write!(f, "{}", kind), - } - } -} - /// Quite simply, an iterator that returns keys. #[derive(Debug, PartialEq)] -pub(crate) struct KeyIterator<'a> { +pub struct KeyIterator<'a> { data: &'a str, read: usize, } @@ -211,7 +118,7 @@ impl<'a> KeyIterator<'a> { } } - pub(crate) fn new(data: &'a str) -> KeyIterator<'a> { KeyIterator { data, read: 0 } } + pub fn new(data: &'a str) -> KeyIterator<'a> { KeyIterator { data, read: 0 } } } impl<'a> Iterator for KeyIterator<'a> { diff --git a/members/lexers/src/assignments/mod.rs b/members/lexers/src/assignments/mod.rs new file mode 100644 index 00000000..c128309c --- /dev/null +++ b/members/lexers/src/assignments/mod.rs @@ -0,0 +1,170 @@ +mod keys; +mod operator; +mod primitive; + +pub use self::keys::{Key, KeyBuf, KeyIterator, TypeError}; +pub use self::operator::Operator; +pub use self::primitive::Primitive; + +/// Given an valid assignment expression, this will split it into `keys`, +/// `operator`, `values`. +pub fn assignment_lexer<'a>(statement: &'a str) -> (Option<&'a str>, Option<Operator>, Option<&'a str>) { + let statement = statement.trim(); + if statement.is_empty() { + return (None, None, None); + } + + let (mut read, mut start) = (0, 0); + let as_bytes = statement.as_bytes(); + let mut bytes = statement.bytes(); + let mut operator = None; + + while let Some(byte) = bytes.next() { + if b'=' == byte { + operator = Some(Operator::Equal); + if as_bytes.get(read + 1).is_none() { + return (Some(&statement[..read].trim()), operator, None); + } + start = read; + read += 1; + break; + } else { + match find_operator(as_bytes, read) { + None => (), + Some((op, found)) => { + operator = Some(op); + start = read; + read = found; + break + } + } + } + read += 1; + } + + if statement.len() == read { + return (Some(statement.trim()), None, None); + } + + let keys = statement[..start].trim_right(); + + if read == statement.len() { + return (Some(keys), operator, None); + } + + let values = &statement[read..]; + (Some(keys), operator, Some(values.trim())) +} + +fn find_operator(bytes: &[u8], read: usize) -> Option<(Operator, usize)> { + if bytes.len() <= read + 3 { + None + } else if bytes[read+1] == b'=' { + Operator::parse_single(bytes[read]).map(|op| (op, read + 2)) + } else if bytes[read+2] == b'=' { + Operator::parse_double(&bytes[read..read+2]).map(|op| (op, read + 3)) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn assignment_splitting() { + assert_eq!( + assignment_lexer(""), + (None, None, None) + ); + assert_eq!( + assignment_lexer("abc"), + (Some("abc"), None, None) + ); + + assert_eq!( + assignment_lexer("abc+=def"), + (Some("abc"), Some(Operator::Add), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc ="), + (Some("abc"), Some(Operator::Equal), None) + ); + + assert_eq!( + assignment_lexer("abc = "), + (Some("abc"), Some(Operator::Equal), None) + ); + + assert_eq!( + assignment_lexer("abc = def"), + (Some("abc"), Some(Operator::Equal), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc=def"), + (Some("abc"), Some(Operator::Equal), Some("def")) + ); + + assert_eq!( + assignment_lexer("def ghi += 124 523"), + (Some("def ghi"), Some(Operator::Add), Some("124 523")) + ) + } + + #[test] + fn arithmetic_assignments() { + assert_eq!( + assignment_lexer("abc //= def"), + (Some("abc"), Some(Operator::IntegerDivide), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc **= def"), + (Some("abc"), Some(Operator::Exponent), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc += def"), + (Some("abc"), Some(Operator::Add), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc -= def"), + (Some("abc"), Some(Operator::Subtract), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc /= def"), + (Some("abc"), Some(Operator::Divide), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc *= def"), + (Some("abc"), Some(Operator::Multiply), Some("def")) + ); + } + + #[test] + fn concatenate_assignments() { + assert_eq!( + assignment_lexer("abc ++= def"), + (Some("abc"), Some(Operator::Concatenate), Some("def")) + ); + + assert_eq!( + assignment_lexer("abc::=def"), + (Some("abc"), Some(Operator::ConcatenateHead), Some("def")) + ); + } + + #[test] + fn filter_assignment() { + assert_eq!( + assignment_lexer("abc \\\\= def"), + (Some("abc"), Some(Operator::Filter), Some("def")) + ) + } +} diff --git a/members/lexers/src/assignments/operator.rs b/members/lexers/src/assignments/operator.rs new file mode 100644 index 00000000..96126a72 --- /dev/null +++ b/members/lexers/src/assignments/operator.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum Operator { + Add, + Concatenate, + ConcatenateHead, + Divide, + Equal, + Exponent, + Filter, + IntegerDivide, + Multiply, + Subtract, +} + +impl Operator { + pub(crate) fn parse_single(data: u8) -> Option<Operator> { + match data { + b'+' => Some(Operator::Add), + b'-' => Some(Operator::Subtract), + b'/' => Some(Operator::Divide), + b'*' => Some(Operator::Multiply), + _ => None, + } + } + + pub(crate) fn parse_double(data: &[u8]) -> Option<Operator> { + match data { + b"//" => Some(Operator::IntegerDivide), + b"**" => Some(Operator::Exponent), + b"++" => Some(Operator::Concatenate), + b"::" => Some(Operator::ConcatenateHead), + b"\\\\" => Some(Operator::Filter), + _ => None, + } + } +} + +impl Display for Operator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", match *self { + Operator::Add => "+=", + Operator::Concatenate => "++=", + Operator::ConcatenateHead => "::=", + Operator::Filter => "\\\\=", + Operator::Divide => "/=", + Operator::Equal => "=", + Operator::Exponent => "**=", + Operator::IntegerDivide => "//=", + Operator::Multiply => "*=", + Operator::Subtract => "-=", + }) + } +} diff --git a/members/lexers/src/assignments/primitive.rs b/members/lexers/src/assignments/primitive.rs new file mode 100644 index 00000000..001a519b --- /dev/null +++ b/members/lexers/src/assignments/primitive.rs @@ -0,0 +1,95 @@ +use std::fmt::{self, Display, Formatter}; + +/// A primitive defines the type that a requested value should satisfy. +#[derive(Debug, PartialEq, Clone)] +pub enum Primitive { + Any, + AnyArray, + Str, + StrArray, + Boolean, + BooleanArray, + Integer, + IntegerArray, + Float, + FloatArray, + HashMap(Box<Primitive>), + BTreeMap(Box<Primitive>), + Indexed(String, Box<Primitive>), +} + +impl Primitive { + pub(crate) fn parse(data: &str) -> Option<Primitive> { + let data = match data { + "[]" => Primitive::AnyArray, + "str" => Primitive::Str, + "str[]" => Primitive::StrArray, + "bool" => Primitive::Boolean, + "bool[]" => Primitive::BooleanArray, + "int" => Primitive::Integer, + "int[]" => Primitive::IntegerArray, + "float" => Primitive::Float, + "float[]" => Primitive::FloatArray, + kind => { + fn parse_inner_hash_map(inner: &str) -> Option<Primitive> { + match inner { + "" => Some(Primitive::HashMap(Box::new(Primitive::Any))), + _ => Primitive::parse(inner).map(|p| Primitive::HashMap(Box::new(p))) + } + } + fn parse_inner_btree_map(inner: &str) -> Option<Primitive> { + match inner { + "" => Some(Primitive::BTreeMap(Box::new(Primitive::Any))), + _ => Primitive::parse(inner).map(|p| Primitive::BTreeMap(Box::new(p))) + } + } + + let res = if kind.starts_with("hmap[") { + let kind = &kind[5..]; + kind.rfind(']').map(|found| &kind[..found]).and_then(parse_inner_hash_map) + } else if kind.starts_with("bmap[") { + let kind = &kind[5..]; + kind.rfind(']').map(|found| &kind[..found]).and_then(parse_inner_btree_map) + } else { + None + }; + + if let Some(data) = res { + data + } else { + return None; + } + } + }; + Some(data) + } +} + +impl Display for Primitive { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + Primitive::Any | Primitive::Str => write!(f, "str"), + Primitive::AnyArray => write!(f, "[]"), + Primitive::Boolean => write!(f, "bool"), + Primitive::BooleanArray => write!(f, "bool[]"), + Primitive::Float => write!(f, "float"), + Primitive::FloatArray => write!(f, "float[]"), + Primitive::Integer => write!(f, "int"), + Primitive::IntegerArray => write!(f, "int[]"), + Primitive::StrArray => write!(f, "str[]"), + Primitive::HashMap(ref kind) => { + match **kind { + Primitive::Any | Primitive::Str => write!(f, "hmap[]"), + ref kind => write!(f, "hmap[{}]", kind), + } + } + Primitive::BTreeMap(ref kind) => { + match **kind { + Primitive::Any | Primitive::Str => write!(f, "bmap[]"), + ref kind => write!(f, "bmap[{}]", kind), + } + } + Primitive::Indexed(_, ref kind) => write!(f, "{}", kind), + } + } +} diff --git a/members/lexers/src/lib.rs b/members/lexers/src/lib.rs index 35638230..7d273c01 100644 --- a/members/lexers/src/lib.rs +++ b/members/lexers/src/lib.rs @@ -1,7 +1,9 @@ +#![feature(nll)] #[macro_use] extern crate bitflags; +pub mod assignments; pub mod arguments; pub mod designators; -pub use self::{arguments::*, designators::*}; +pub use self::{assignments::*, arguments::*, designators::*}; diff --git a/src/lib/parser/assignments/actions.rs b/src/lib/parser/assignments/actions.rs index ebf6c0a1..011b5403 100644 --- a/src/lib/parser/assignments/actions.rs +++ b/src/lib/parser/assignments/actions.rs @@ -1,10 +1,9 @@ -use lexers::ArgumentSplitter; -use super::{checker::*, *}; +use lexers::{ArgumentSplitter, assignments::{Key, KeyIterator, Operator, Primitive, TypeError}}; +use super::checker::*; use std::fmt::{self, Display, Formatter}; #[derive(Debug, PartialEq)] pub(crate) enum AssignmentError<'a> { - InvalidOperator(&'a str), InvalidValue(Primitive, Primitive), TypeError(TypeError), ExtraValues(&'a str, &'a str), @@ -14,7 +13,6 @@ pub(crate) enum AssignmentError<'a> { impl<'a> Display for AssignmentError<'a> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { - AssignmentError::InvalidOperator(op) => write!(f, "invalid operator supplied: {}", op), AssignmentError::InvalidValue(ref expected, ref actual) => { write!(f, "expected {}, but received {}", expected, actual) } @@ -124,10 +122,10 @@ mod tests { use super::*; fn split(input: &str) -> (String, Operator, String) { - let (keys, op, vals) = split_assignment(input); + let (keys, op, vals) = assignment_lexer(input); ( keys.unwrap().into(), - Operator::parse(op.unwrap()).unwrap(), + op.unwrap(), vals.unwrap().into(), ) } diff --git a/src/lib/parser/assignments/checker.rs b/src/lib/parser/assignments/checker.rs index 335f0a97..2dd7f9e2 100644 --- a/src/lib/parser/assignments/checker.rs +++ b/src/lib/parser/assignments/checker.rs @@ -1,7 +1,5 @@ -use super::{ - super::{expand_string, Expander}, Primitive, TypeError, -}; - +use super::super::{expand_string, Expander}; +use lexers::assignments::{Primitive, TypeError}; use shell::variables::VariableType; use types::*; use std::iter::Iterator; diff --git a/src/lib/parser/assignments/mod.rs b/src/lib/parser/assignments/mod.rs index a63aab31..fb853171 100644 --- a/src/lib/parser/assignments/mod.rs +++ b/src/lib/parser/assignments/mod.rs @@ -1,11 +1,5 @@ mod actions; mod checker; -mod keys; -mod operator; -mod splitter; - -pub use self::keys::Primitive; pub(crate) use self::{ - actions::{Action, AssignmentActions, AssignmentError}, checker::{is_array, value_check}, - keys::{Key, KeyBuf, KeyIterator, TypeError}, operator::Operator, splitter::split_assignment, + actions::{Action, AssignmentActions}, checker::{is_array, value_check} }; diff --git a/src/lib/parser/assignments/operator.rs b/src/lib/parser/assignments/operator.rs deleted file mode 100644 index 332444b5..00000000 --- a/src/lib/parser/assignments/operator.rs +++ /dev/null @@ -1,42 +0,0 @@ -use super::AssignmentError; -use std::fmt::{self, Display, Formatter}; - -#[derive(Debug, PartialEq, Clone, Copy)] -pub(crate) enum Operator { - Add, - Subtract, - Divide, - IntegerDivide, - Multiply, - Exponent, - Equal, -} - -impl Operator { - pub(crate) fn parse(data: &str) -> Result<Operator, AssignmentError> { - match data { - "=" => Ok(Operator::Equal), - "+=" => Ok(Operator::Add), - "-=" => Ok(Operator::Subtract), - "/=" => Ok(Operator::Divide), - "//=" => Ok(Operator::IntegerDivide), - "*=" => Ok(Operator::Multiply), - "**=" => Ok(Operator::Exponent), - _ => Err(AssignmentError::InvalidOperator(data)), - } - } -} - -impl Display for Operator { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match *self { - Operator::Add => write!(f, "+="), - Operator::Subtract => write!(f, "-="), - Operator::Divide => write!(f, "/="), - Operator::IntegerDivide => write!(f, "//="), - Operator::Multiply => write!(f, "*="), - Operator::Exponent => write!(f, "**="), - Operator::Equal => write!(f, "="), - } - } -} diff --git a/src/lib/parser/assignments/splitter.rs b/src/lib/parser/assignments/splitter.rs deleted file mode 100644 index 1dba4168..00000000 --- a/src/lib/parser/assignments/splitter.rs +++ /dev/null @@ -1,79 +0,0 @@ -/// Given an valid assignment expression, this will split it into `keys`, -/// `operator`, `values`. -pub(crate) fn split_assignment(statement: &str) -> (Option<&str>, Option<&str>, Option<&str>) { - let statement = statement.trim(); - if statement.is_empty() { - return (None, None, None); - } - - let mut read = 0; - let mut bytes = statement.bytes(); - let mut start = 0; - - while let Some(byte) = bytes.next() { - if b'=' == byte { - if statement.as_bytes().get(read + 1).is_none() { - return (Some(&statement[..read].trim()), Some("="), None); - } - start = read; - read += 1; - break; - } else if is_operator(byte) { - start = read; - read += 1; - while let Some(byte) = bytes.next() { - read += 1; - if byte == b'=' { - break; - } - } - break; - } - read += 1; - } - - if statement.len() == read { - return (Some(statement.trim()), None, None); - } - - let keys = statement[..start].trim_right(); - - let operator = &statement[start..read]; - if read == statement.len() { - return (Some(keys), Some(operator), None); - } - - let values = &statement[read..]; - (Some(keys), Some(operator), Some(values.trim())) -} - -fn is_operator(byte: u8) -> bool { byte == b'+' || byte == b'-' || byte == b'*' || byte == b'/' } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn assignment_splitting() { - assert_eq!(split_assignment(""), (None, None, None)); - assert_eq!(split_assignment("abc"), (Some("abc"), None, None)); - assert_eq!( - split_assignment("abc+=def"), - (Some("abc"), Some("+="), Some("def")) - ); - assert_eq!(split_assignment("abc ="), (Some("abc"), Some("="), None)); - assert_eq!(split_assignment("abc = "), (Some("abc"), Some("="), None)); - assert_eq!( - split_assignment("abc = def"), - (Some("abc"), Some("="), Some("def")) - ); - assert_eq!( - split_assignment("abc=def"), - (Some("abc"), Some("="), Some("def")) - ); - assert_eq!( - split_assignment("def ghi += 124 523"), - (Some("def ghi"), Some("+="), Some("124 523")) - ) - } -} diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 9dcd0efe..c28a4b18 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -5,7 +5,7 @@ mod quotes; pub(crate) mod shell_expand; mod statement; -pub use self::{assignments::Primitive, quotes::Terminator}; +pub use self::quotes::Terminator; pub(crate) use self::{ loops::ForExpression, shell_expand::{expand_string, Expander, Select}, statement::{parse_and_validate, StatementSplitter}, diff --git a/src/lib/parser/statement/functions.rs b/src/lib/parser/statement/functions.rs index a78f58f7..c12421b1 100644 --- a/src/lib/parser/statement/functions.rs +++ b/src/lib/parser/statement/functions.rs @@ -1,6 +1,5 @@ -use super::{ - super::assignments::{KeyBuf, KeyIterator, TypeError}, split_pattern, -}; +use super::split_pattern; +use lexers::assignments::{KeyBuf, KeyIterator, TypeError}; /// The arguments expression given to a function declaration goes into here, which will be /// converted into a tuple consisting of a `KeyIterator` iterator, which will collect type diff --git a/src/lib/parser/statement/parse.rs b/src/lib/parser/statement/parse.rs index 1efead19..bab71b16 100644 --- a/src/lib/parser/statement/parse.rs +++ b/src/lib/parser/statement/parse.rs @@ -1,6 +1,6 @@ -use lexers::ArgumentSplitter; +use lexers::{assignment_lexer, ArgumentSplitter}; use super::{ - super::{assignments::{split_assignment, Operator}, pipelines::{self, Pipeline}}, + super::pipelines::{self, Pipeline}, case, functions::{collect_arguments, parse_function}, }; use shell::flow_control::{Case, ElseIf, ExportAction, LocalAction, Statement}; @@ -36,7 +36,7 @@ pub(crate) fn parse(code: &str) -> Statement { } _ if cmd.starts_with("let ") => { // Split the let expression and ensure that the statement is valid. - let (keys, op, vals) = split_assignment(cmd[4..].trim_left()); + let (keys, op, vals) = assignment_lexer(cmd[4..].trim_left()); let (keys, op, values) = match vals { Some(vals) => { // If the values exist, then the keys and operator also exists. @@ -52,24 +52,14 @@ pub(crate) fn parse(code: &str) -> Statement { } }; - // After also ensuring the the operator is a valid operator, create the let - // statement. - match Operator::parse(op) { - Ok(operator) => { - return Statement::Let(LocalAction::Assign(keys, operator, values)); - } - Err(why) => { - eprintln!("ion: assignment error: {}", why); - return Statement::Default; - } - } + return Statement::Let(LocalAction::Assign(keys, op, values)); } "export" => { return Statement::Export(ExportAction::List); } _ if cmd.starts_with("export ") => { // Split the let expression and ensure that the statement is valid. - let (keys, op, vals) = split_assignment(cmd[7..].trim_left()); + let (keys, op, vals) = assignment_lexer(cmd[7..].trim_left()); let (keys, op, values) = match vals { Some(vals) => { // If the values exist, then the keys and operator also exists. @@ -87,17 +77,7 @@ pub(crate) fn parse(code: &str) -> Statement { } }; - // After also ensuring the the operator is a valid operator, create the let - // statement. - match Operator::parse(op) { - Ok(operator) => { - return Statement::Export(ExportAction::Assign(keys, operator, values)); - } - Err(why) => { - eprintln!("ion: assignment error: {}", why); - return Statement::Default; - } - } + return Statement::Export(ExportAction::Assign(keys, op, values)); } _ if cmd.starts_with("if ") => { return collect(cmd[3..].trim_left(), |pipeline| Statement::If { diff --git a/src/lib/shell/assignments.rs b/src/lib/shell/assignments.rs index 0fad4fe7..dd3ed026 100644 --- a/src/lib/shell/assignments.rs +++ b/src/lib/shell/assignments.rs @@ -2,6 +2,7 @@ use super::{ flow_control::{ExportAction, LocalAction}, status::*, Shell, }; use itoa; +use lexers::assignments::{Operator, Primitive}; use parser::assignments::*; use smallvec::SmallVec; use shell::{ @@ -457,6 +458,7 @@ fn math<'a, F: FnMut(&[u8])>( return Err(MathError::Unsupported); }, Operator::Equal => writefn(value.as_bytes()), + _ => return Err(MathError::Unsupported) }; Ok(()) diff --git a/src/lib/shell/flow_control.rs b/src/lib/shell/flow_control.rs index 6b7402a2..2515fb55 100644 --- a/src/lib/shell/flow_control.rs +++ b/src/lib/shell/flow_control.rs @@ -3,6 +3,7 @@ use parser::{assignments::*, pipelines::Pipeline}; use smallvec::SmallVec; use std::fmt::{self, Display, Formatter}; use types::Identifier; +use lexers::assignments::{KeyBuf, Operator, Primitive}; #[derive(Debug, PartialEq, Clone)] pub(crate) struct ElseIf { -- GitLab