added arithmetic substitution
This commit is contained in:
345
src/expand.rs
345
src/expand.rs
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::str::FromStr;
|
use std::iter::Peekable;
|
||||||
|
use std::str::{Chars, FromStr};
|
||||||
|
|
||||||
use glob::Pattern;
|
use glob::Pattern;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
@@ -22,6 +23,8 @@ pub const SNG_QUOTE: char = '\u{fdd2}';
|
|||||||
pub const TILDE_SUB: char = '\u{fdd3}';
|
pub const TILDE_SUB: char = '\u{fdd3}';
|
||||||
/// Subshell marker
|
/// Subshell marker
|
||||||
pub const SUBSH: char = '\u{fdd4}';
|
pub const SUBSH: char = '\u{fdd4}';
|
||||||
|
/// Arithmetic substitution marker
|
||||||
|
pub const ARITH_SUB: char = '\u{fdd5}';
|
||||||
|
|
||||||
impl Tk {
|
impl Tk {
|
||||||
/// Create a new expanded token
|
/// Create a new expanded token
|
||||||
@@ -95,8 +98,6 @@ impl Expander {
|
|||||||
pub fn expand_raw(&self) -> ShResult<String> {
|
pub fn expand_raw(&self) -> ShResult<String> {
|
||||||
let mut chars = self.raw.chars().peekable();
|
let mut chars = self.raw.chars().peekable();
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let mut var_name = String::new();
|
|
||||||
let mut in_brace = false;
|
|
||||||
flog!(INFO, self.raw);
|
flog!(INFO, self.raw);
|
||||||
|
|
||||||
while let Some(ch) = chars.next() {
|
while let Some(ch) = chars.next() {
|
||||||
@@ -105,51 +106,34 @@ impl Expander {
|
|||||||
let home = env::var("HOME").unwrap_or_default();
|
let home = env::var("HOME").unwrap_or_default();
|
||||||
result.push_str(&home);
|
result.push_str(&home);
|
||||||
}
|
}
|
||||||
VAR_SUB => {
|
ARITH_SUB => {
|
||||||
while let Some(ch) = chars.next() {
|
let mut body = String::new();
|
||||||
flog!(INFO,ch);
|
while let Some(arith_ch) = chars.next() {
|
||||||
flog!(INFO,var_name);
|
match arith_ch {
|
||||||
match ch {
|
VAR_SUB => {
|
||||||
SUBSH if var_name.is_empty() => {
|
let expanded = expand_var(&mut chars)?;
|
||||||
let mut subsh_body = String::new();
|
if is_a_number(&expanded) {
|
||||||
while let Some(ch) = chars.next() {
|
body.push_str(&expanded);
|
||||||
match ch {
|
} else {
|
||||||
SUBSH => {
|
return Err(
|
||||||
break
|
ShErr::Simple {
|
||||||
|
kind: ShErrKind::ParseErr,
|
||||||
|
msg: format!("Expected a number during substitution, found '{}'",&expanded),
|
||||||
|
notes: vec![],
|
||||||
}
|
}
|
||||||
_ => subsh_body.push(ch)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let expanded = expand_cmd_sub(&subsh_body)?;
|
|
||||||
flog!(INFO, expanded);
|
|
||||||
result.push_str(&expanded);
|
|
||||||
}
|
}
|
||||||
'{' if var_name.is_empty() => in_brace = true,
|
ARITH_SUB => break,
|
||||||
'}' if in_brace => {
|
_ => body.push(arith_ch)
|
||||||
flog!(DEBUG, var_name);
|
|
||||||
let var_val = perform_param_expansion(&var_name)?;
|
|
||||||
result.push_str(&var_val);
|
|
||||||
var_name.clear();
|
|
||||||
break
|
|
||||||
}
|
|
||||||
_ if in_brace => {
|
|
||||||
var_name.push(ch)
|
|
||||||
}
|
|
||||||
_ if is_hard_sep(ch) || ch == DUB_QUOTE || ch == SUBSH || ch == '/' => {
|
|
||||||
let var_val = read_vars(|v| v.get_var(&var_name));
|
|
||||||
result.push_str(&var_val);
|
|
||||||
result.push(ch);
|
|
||||||
var_name.clear();
|
|
||||||
break
|
|
||||||
}
|
|
||||||
_ => var_name.push(ch),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !var_name.is_empty() {
|
let expanded = expand_arithmetic(&body)?;
|
||||||
let var_val = read_vars(|v| v.get_var(&var_name));
|
result.push_str(&expanded);
|
||||||
result.push_str(&var_val);
|
}
|
||||||
var_name.clear();
|
VAR_SUB => {
|
||||||
}
|
let expanded = expand_var(&mut chars)?;
|
||||||
|
result.push_str(&expanded);
|
||||||
}
|
}
|
||||||
_ => result.push(ch)
|
_ => result.push(ch)
|
||||||
}
|
}
|
||||||
@@ -158,6 +142,52 @@ impl Expander {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expand_var(chars: &mut Peekable<Chars<'_>>) -> ShResult<String> {
|
||||||
|
let mut var_name = String::new();
|
||||||
|
let mut in_brace = false;
|
||||||
|
while let Some(&ch) = chars.peek() {
|
||||||
|
match ch {
|
||||||
|
SUBSH if var_name.is_empty() => {
|
||||||
|
chars.next(); // now safe to consume
|
||||||
|
let mut subsh_body = String::new();
|
||||||
|
while let Some(c) = chars.next() {
|
||||||
|
if c == SUBSH { break }
|
||||||
|
subsh_body.push(c);
|
||||||
|
}
|
||||||
|
let expanded = expand_cmd_sub(&subsh_body)?;
|
||||||
|
return Ok(expanded);
|
||||||
|
}
|
||||||
|
'{' if var_name.is_empty() => {
|
||||||
|
chars.next(); // consume the brace
|
||||||
|
in_brace = true;
|
||||||
|
}
|
||||||
|
'}' if in_brace => {
|
||||||
|
chars.next(); // consume the brace
|
||||||
|
let val = perform_param_expansion(&var_name)?;
|
||||||
|
return Ok(val);
|
||||||
|
}
|
||||||
|
ch if in_brace => {
|
||||||
|
chars.next(); // safe to consume
|
||||||
|
var_name.push(ch);
|
||||||
|
}
|
||||||
|
ch if is_hard_sep(ch) || ch == ARITH_SUB || ch == DUB_QUOTE || ch == SUBSH || ch == '/' => {
|
||||||
|
let val = read_vars(|v| v.get_var(&var_name));
|
||||||
|
return Ok(val);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
chars.next();
|
||||||
|
var_name.push(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !var_name.is_empty() {
|
||||||
|
let var_val = read_vars(|v| v.get_var(&var_name));
|
||||||
|
Ok(var_val)
|
||||||
|
} else {
|
||||||
|
Ok(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expand_glob(raw: &str) -> ShResult<String> {
|
pub fn expand_glob(raw: &str) -> ShResult<String> {
|
||||||
let mut words = vec![];
|
let mut words = vec![];
|
||||||
|
|
||||||
@@ -171,6 +201,178 @@ pub fn expand_glob(raw: &str) -> ShResult<String> {
|
|||||||
Ok(words.join(" "))
|
Ok(words.join(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_a_number(raw: &str) -> bool {
|
||||||
|
let trimmed = raw.trim();
|
||||||
|
trimmed.parse::<i32>().is_ok() || trimmed.parse::<f64>().is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ArithTk {
|
||||||
|
Num(f64),
|
||||||
|
Op(ArithOp),
|
||||||
|
LParen,
|
||||||
|
RParen
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArithTk {
|
||||||
|
pub fn tokenize(raw: &str) -> ShResult<Vec<Self>> {
|
||||||
|
let mut tokens = Vec::new();
|
||||||
|
let mut chars = raw.chars().peekable();
|
||||||
|
|
||||||
|
while let Some(&ch) = chars.peek() {
|
||||||
|
match ch {
|
||||||
|
' ' | '\t' => { chars.next(); }
|
||||||
|
'0'..='9' | '.' => {
|
||||||
|
let mut num = String::new();
|
||||||
|
while let Some(&digit) = chars.peek() {
|
||||||
|
if digit.is_ascii_digit() || digit == '.' {
|
||||||
|
num.push(digit);
|
||||||
|
chars.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Ok(num) = num.parse::<f64>() else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
tokens.push(Self::Num(num));
|
||||||
|
}
|
||||||
|
'+' | '-' | '*' | '/' | '%' => {
|
||||||
|
let mut buf = String::new();
|
||||||
|
buf.push(ch);
|
||||||
|
tokens.push(Self::Op(buf.parse::<ArithOp>().unwrap()));
|
||||||
|
chars.next();
|
||||||
|
}
|
||||||
|
'(' => { tokens.push(Self::LParen); chars.next(); }
|
||||||
|
')' => { tokens.push(Self::RParen); chars.next(); }
|
||||||
|
_ => return Err(ShErr::Simple { kind: ShErrKind::ParseErr, msg: "Invalid character in arithmetic substitution".into(), notes: vec![] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(tokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_rpn(tokens: Vec<ArithTk>) -> ShResult<Vec<ArithTk>> {
|
||||||
|
let mut output = Vec::new();
|
||||||
|
let mut ops = Vec::new();
|
||||||
|
|
||||||
|
fn precedence(op: &ArithOp) -> usize {
|
||||||
|
match op {
|
||||||
|
ArithOp::Add |
|
||||||
|
ArithOp::Sub => 1,
|
||||||
|
ArithOp::Mul |
|
||||||
|
ArithOp::Div |
|
||||||
|
ArithOp::Mod => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for token in tokens {
|
||||||
|
match token {
|
||||||
|
ArithTk::Num(_) => output.push(token),
|
||||||
|
ArithTk::Op(op1) => {
|
||||||
|
while let Some(ArithTk::Op(op2)) = ops.last() {
|
||||||
|
if precedence(op2) >= precedence(&op1) {
|
||||||
|
output.push(ops.pop().unwrap());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ops.push(ArithTk::Op(op1));
|
||||||
|
}
|
||||||
|
ArithTk::LParen => ops.push(ArithTk::LParen),
|
||||||
|
ArithTk::RParen => {
|
||||||
|
while let Some(top) = ops.pop() {
|
||||||
|
if let ArithTk::LParen = top {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
output.push(top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(op) = ops.pop() {
|
||||||
|
output.push(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
pub fn eval_rpn(tokens: Vec<ArithTk>) -> ShResult<f64> {
|
||||||
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
for token in tokens {
|
||||||
|
match token {
|
||||||
|
ArithTk::Num(n) => stack.push(n),
|
||||||
|
ArithTk::Op(op) => {
|
||||||
|
let rhs = stack.pop().ok_or(ShErr::Simple {
|
||||||
|
kind: ShErrKind::ParseErr,
|
||||||
|
msg: "Missing right-hand operand".into(),
|
||||||
|
notes: vec![],
|
||||||
|
})?;
|
||||||
|
let lhs = stack.pop().ok_or(ShErr::Simple {
|
||||||
|
kind: ShErrKind::ParseErr,
|
||||||
|
msg: "Missing left-hand operand".into(),
|
||||||
|
notes: vec![],
|
||||||
|
})?;
|
||||||
|
let result = match op {
|
||||||
|
ArithOp::Add => lhs + rhs,
|
||||||
|
ArithOp::Sub => lhs - rhs,
|
||||||
|
ArithOp::Mul => lhs * rhs,
|
||||||
|
ArithOp::Div => lhs / rhs,
|
||||||
|
ArithOp::Mod => lhs % rhs,
|
||||||
|
};
|
||||||
|
stack.push(result);
|
||||||
|
}
|
||||||
|
_ => return Err(ShErr::Simple {
|
||||||
|
kind: ShErrKind::ParseErr,
|
||||||
|
msg: "Unexpected token during evaluation".into(),
|
||||||
|
notes: vec![],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if stack.len() != 1 {
|
||||||
|
return Err(ShErr::Simple {
|
||||||
|
kind: ShErrKind::ParseErr,
|
||||||
|
msg: "Invalid arithmetic expression".into(),
|
||||||
|
notes: vec![],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(stack[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ArithOp {
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ArithOp {
|
||||||
|
type Err = ShErr;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
assert!(s.len() == 1);
|
||||||
|
match s.chars().next().unwrap() {
|
||||||
|
'+' => Ok(Self::Add),
|
||||||
|
'-' => Ok(Self::Sub),
|
||||||
|
'*' => Ok(Self::Mul),
|
||||||
|
'/' => Ok(Self::Div),
|
||||||
|
'%' => Ok(Self::Mod),
|
||||||
|
_ => Err(ShErr::Simple { kind: ShErrKind::ParseErr, msg: "Invalid arithmetic operator".into(), notes: vec![] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand_arithmetic(raw: &str) -> ShResult<String> {
|
||||||
|
let tokens = ArithTk::tokenize(raw)?;
|
||||||
|
let rpn = ArithTk::to_rpn(tokens)?;
|
||||||
|
let result = ArithTk::eval_rpn(rpn)?;
|
||||||
|
Ok(result.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the command output of a given command input as a String
|
/// Get the command output of a given command input as a String
|
||||||
pub fn expand_cmd_sub(raw: &str) -> ShResult<String> {
|
pub fn expand_cmd_sub(raw: &str) -> ShResult<String> {
|
||||||
flog!(DEBUG, "in expand_cmd_sub");
|
flog!(DEBUG, "in expand_cmd_sub");
|
||||||
@@ -229,6 +431,63 @@ pub fn unescape_str(raw: &str) -> String {
|
|||||||
result.push(next_ch)
|
result.push(next_ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
'`' => {
|
||||||
|
result.push(ARITH_SUB);
|
||||||
|
let mut closed = false;
|
||||||
|
while let Some(arith_ch) = chars.next() {
|
||||||
|
match arith_ch {
|
||||||
|
'\\' => {
|
||||||
|
result.push(arith_ch);
|
||||||
|
if let Some(next_ch) = chars.next() {
|
||||||
|
result.push(next_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'`' => {
|
||||||
|
closed = true;
|
||||||
|
result.push(ARITH_SUB);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
'$' if chars.peek() == Some(&'(') => {
|
||||||
|
result.push(VAR_SUB);
|
||||||
|
result.push(SUBSH);
|
||||||
|
chars.next();
|
||||||
|
let mut cmdsub_count = 1;
|
||||||
|
while let Some(cmdsub_ch) = chars.next() {
|
||||||
|
flog!(DEBUG, cmdsub_count);
|
||||||
|
flog!(DEBUG, cmdsub_ch);
|
||||||
|
match cmdsub_ch {
|
||||||
|
'\\' => {
|
||||||
|
result.push(cmdsub_ch);
|
||||||
|
if let Some(next_ch) = chars.next() {
|
||||||
|
result.push(next_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'$' if chars.peek() == Some(&'(') => {
|
||||||
|
cmdsub_count += 1;
|
||||||
|
result.push(cmdsub_ch);
|
||||||
|
result.push(chars.next().unwrap());
|
||||||
|
}
|
||||||
|
')' => {
|
||||||
|
cmdsub_count -= 1;
|
||||||
|
flog!(DEBUG, cmdsub_count);
|
||||||
|
if cmdsub_count == 0 {
|
||||||
|
result.push(SUBSH);
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
result.push(cmdsub_ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => result.push(cmdsub_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'$' => {
|
||||||
|
result.push(VAR_SUB);
|
||||||
|
}
|
||||||
|
_ => result.push(arith_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
'(' => {
|
'(' => {
|
||||||
result.push(SUBSH);
|
result.push(SUBSH);
|
||||||
let mut paren_count = 1;
|
let mut paren_count = 1;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::{collections::VecDeque, fmt::Display, iter::Peekable, ops::{Bound, Dere
|
|||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
use crate::{builtin::BUILTINS, libsh::{error::{ShErr, ShErrKind, ShResult}, utils::CharDequeUtils}, prelude::*};
|
use crate::{builtin::BUILTINS, libsh::{error::{ShErr, ShErrKind, ShResult}, utils::CharDequeUtils}, parse::parse_err_full, prelude::*};
|
||||||
|
|
||||||
pub const KEYWORDS: [&str;16] = [
|
pub const KEYWORDS: [&str;16] = [
|
||||||
"if",
|
"if",
|
||||||
@@ -327,6 +327,7 @@ impl LexStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while let Some(ch) = chars.next() {
|
while let Some(ch) = chars.next() {
|
||||||
|
flog!(DEBUG, "we are in the loop");
|
||||||
match ch {
|
match ch {
|
||||||
_ if self.flags.contains(LexFlags::RAW) => {
|
_ if self.flags.contains(LexFlags::RAW) => {
|
||||||
if ch.is_whitespace() {
|
if ch.is_whitespace() {
|
||||||
@@ -341,6 +342,61 @@ impl LexStream {
|
|||||||
pos += ch.len_utf8();
|
pos += ch.len_utf8();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
'`' => {
|
||||||
|
let arith_pos = pos;
|
||||||
|
pos += 1;
|
||||||
|
let mut closed = false;
|
||||||
|
while let Some(arith_ch) = chars.next() {
|
||||||
|
match arith_ch {
|
||||||
|
'\\' => {
|
||||||
|
pos += 1;
|
||||||
|
if let Some(ch) = chars.next() {
|
||||||
|
pos += ch.len_utf8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'`' => {
|
||||||
|
pos += 1;
|
||||||
|
closed = true;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
'$' if chars.peek() == Some(&'(') => {
|
||||||
|
pos += 2;
|
||||||
|
chars.next();
|
||||||
|
let mut cmdsub_count = 1;
|
||||||
|
while let Some(cmdsub_ch) = chars.next() {
|
||||||
|
match cmdsub_ch {
|
||||||
|
'$' if chars.peek() == Some(&'(') => {
|
||||||
|
pos += 2;
|
||||||
|
chars.next();
|
||||||
|
cmdsub_count += 1;
|
||||||
|
}
|
||||||
|
')' => {
|
||||||
|
pos += 1;
|
||||||
|
cmdsub_count -= 1;
|
||||||
|
if cmdsub_count == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => pos += cmdsub_ch.len_utf8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => pos += arith_ch.len_utf8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flog!(DEBUG, "we have left the loop");
|
||||||
|
flog!(DEBUG, closed);
|
||||||
|
if !closed && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
|
||||||
|
self.cursor = pos;
|
||||||
|
return Err(
|
||||||
|
ShErr::full(
|
||||||
|
ShErrKind::ParseErr,
|
||||||
|
"Unclosed arithmetic substitution",
|
||||||
|
Span::new(arith_pos..arith_pos + 1, self.source.clone())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
'$' if chars.peek() == Some(&'{') => {
|
'$' if chars.peek() == Some(&'{') => {
|
||||||
pos += 2;
|
pos += 2;
|
||||||
chars.next();
|
chars.next();
|
||||||
@@ -396,6 +452,7 @@ impl LexStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !paren_count == 0 && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
|
if !paren_count == 0 && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
|
||||||
|
self.cursor = pos;
|
||||||
return Err(
|
return Err(
|
||||||
ShErr::full(
|
ShErr::full(
|
||||||
ShErrKind::ParseErr,
|
ShErrKind::ParseErr,
|
||||||
@@ -718,7 +775,10 @@ impl Iterator for LexStream {
|
|||||||
} else {
|
} else {
|
||||||
match self.read_string() {
|
match self.read_string() {
|
||||||
Ok(tk) => tk,
|
Ok(tk) => tk,
|
||||||
Err(e) => return Some(Err(e))
|
Err(e) => {
|
||||||
|
flog!(ERROR, e);
|
||||||
|
return Some(Err(e))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ impl ParsedSrc {
|
|||||||
pub fn parse_src(&mut self) -> Result<(),Vec<ShErr>> {
|
pub fn parse_src(&mut self) -> Result<(),Vec<ShErr>> {
|
||||||
let mut tokens = vec![];
|
let mut tokens = vec![];
|
||||||
for lex_result in LexStream::new(self.src.clone(), LexFlags::empty()) {
|
for lex_result in LexStream::new(self.src.clone(), LexFlags::empty()) {
|
||||||
|
flog!(DEBUG, lex_result);
|
||||||
match lex_result {
|
match lex_result {
|
||||||
Ok(token) => tokens.push(token),
|
Ok(token) => tokens.push(token),
|
||||||
Err(error) => return Err(vec![error])
|
Err(error) => return Err(vec![error])
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::{env, os::unix::fs::PermissionsExt, path::{Path, PathBuf}, sync::Arc};
|
use std::{env, os::unix::fs::PermissionsExt, path::{Path, PathBuf}, sync::Arc};
|
||||||
use crate::{builtin::BUILTINS, prelude::*};
|
use crate::builtin::BUILTINS;
|
||||||
|
|
||||||
use rustyline::highlight::Highlighter;
|
use rustyline::highlight::Highlighter;
|
||||||
use crate::{libsh::term::{Style, StyleSet, Styled}, parse::lex::{LexFlags, LexStream, Tk, TkFlags, TkRule}, state::read_logic};
|
use crate::{libsh::term::{Style, StyleSet, Styled}, parse::lex::{LexFlags, LexStream, Tk, TkFlags, TkRule}, state::read_logic};
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use rustyline::{completion::Completer, hint::{Hint, Hinter}, history::SearchDirection, validate::{ValidationResult, Validator}, Helper};
|
use rustyline::{completion::Completer, hint::{Hint, Hinter}, history::SearchDirection, validate::{ValidationResult, Validator}, Helper};
|
||||||
|
|
||||||
use crate::{libsh::term::{Style, Styled}, parse::{lex::{LexFlags, LexStream}, ParseStream}};
|
use crate::{libsh::term::{Style, Styled}, parse::{lex::{LexFlags, LexStream}, ParseStream}};
|
||||||
|
|||||||
Reference in New Issue
Block a user