mirror of
https://github.com/danbulant/rush
synced 2026-06-09 17:50:11 +00:00
small fixes, array definition support
This commit is contained in:
parent
b000e924e8
commit
b0a774994f
5 changed files with 193 additions and 62 deletions
|
|
@ -33,9 +33,10 @@ impl Term {
|
||||||
fn format(self: &Self, stdout: &mut RawTerminal<Stdout>) -> String {
|
fn format(self: &Self, stdout: &mut RawTerminal<Stdout>) -> String {
|
||||||
let (_, y) = stdout.cursor_pos().unwrap();
|
let (_, y) = stdout.cursor_pos().unwrap();
|
||||||
format!(
|
format!(
|
||||||
"{}{}{}{}{}",
|
"{}{}{}{}{}{}",
|
||||||
termion::clear::CurrentLine,
|
termion::clear::CurrentLine,
|
||||||
termion::cursor::Goto(1, y),
|
termion::cursor::Goto(1, y),
|
||||||
|
"$: ",
|
||||||
&self.input,
|
&self.input,
|
||||||
termion::cursor::Left((self.input.len() - self.idx).try_into().unwrap()),
|
termion::cursor::Left((self.input.len() - self.idx).try_into().unwrap()),
|
||||||
termion::cursor::Right(if self.input.len() > 0 { 1 } else { 0 } )
|
termion::cursor::Right(if self.input.len() > 0 { 1 } else { 0 } )
|
||||||
|
|
@ -141,6 +142,9 @@ impl Shell {
|
||||||
print!("$: ");
|
print!("$: ");
|
||||||
io::stdout().flush().unwrap();
|
io::stdout().flush().unwrap();
|
||||||
shell.collect();
|
shell.collect();
|
||||||
|
if shell.term.input == "exit" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
shell.term.input += "\n";
|
shell.term.input += "\n";
|
||||||
let res = parser::exec(&mut shell.term.input.as_bytes(), &mut shell.ctx);
|
let res = parser::exec(&mut shell.term.input.as_bytes(), &mut shell.ctx);
|
||||||
match res {
|
match res {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ pub enum Value {
|
||||||
Literal(String),
|
Literal(String),
|
||||||
Variable(String),
|
Variable(String),
|
||||||
ArrayVariable(String),
|
ArrayVariable(String),
|
||||||
|
ArrayDefinition(Vec<Value>),
|
||||||
ArrayFunction(DefinedFunction),
|
ArrayFunction(DefinedFunction),
|
||||||
StringFunction(DefinedFunction),
|
StringFunction(DefinedFunction),
|
||||||
Expressions(Vec<Expression>),
|
Expressions(Vec<Expression>),
|
||||||
|
|
@ -137,7 +138,7 @@ impl Tree {
|
||||||
let mut token = self.get_current_token();
|
let mut token = self.get_current_token();
|
||||||
loop {
|
loop {
|
||||||
if matches!(token, Tokens::Space) {
|
if matches!(token, Tokens::Space) {
|
||||||
if buf.len() > 0 {
|
if !buf.is_empty() {
|
||||||
values.push(CommandValue::Value(Value::Values(buf)));
|
values.push(CommandValue::Value(Value::Values(buf)));
|
||||||
buf = Vec::new();
|
buf = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
@ -149,12 +150,12 @@ impl Tree {
|
||||||
let val = match &token {
|
let val = match &token {
|
||||||
Tokens::Literal(str) => Value::Literal(str.clone()),
|
Tokens::Literal(str) => Value::Literal(str.clone()),
|
||||||
Tokens::SubStart => {
|
Tokens::SubStart => {
|
||||||
let val = self.get_value(end)?;
|
let val = self.get_value(end, false)?;
|
||||||
token = self.get_current_token();
|
token = self.get_current_token();
|
||||||
val
|
val
|
||||||
},
|
},
|
||||||
Tokens::StringVariable(str, _) => {
|
Tokens::StringVariable(str, _) => {
|
||||||
if str.len() == 0 { bail!("Expected variable name"); }
|
if str.is_empty() { bail!("Expected variable name"); }
|
||||||
Value::Variable(str.clone())
|
Value::Variable(str.clone())
|
||||||
},
|
},
|
||||||
Tokens::ArrayVariable(str, _) => Value::ArrayVariable(str.clone()),
|
Tokens::ArrayVariable(str, _) => Value::ArrayVariable(str.clone()),
|
||||||
|
|
@ -185,7 +186,7 @@ impl Tree {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// self.next();
|
// self.next();
|
||||||
if buf.len() > 0 {
|
if !buf.is_empty() {
|
||||||
values.push(CommandValue::Value(Value::Values(buf)));
|
values.push(CommandValue::Value(Value::Values(buf)));
|
||||||
}
|
}
|
||||||
Ok(Expression::Command(values))
|
Ok(Expression::Command(values))
|
||||||
|
|
@ -201,18 +202,15 @@ impl Tree {
|
||||||
_ => len += 1
|
_ => len += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let key = Box::new(self.get_value(self.i + len)?);
|
let key = Box::new(self.get_value(self.i + len, false)?);
|
||||||
self.inc(); // ????
|
self.inc(); // ????
|
||||||
self.inc();
|
self.inc();
|
||||||
let value = Box::new(self.get_value(end)?);
|
let value = Box::new(self.get_value(end, false)?);
|
||||||
Ok(Expression::LetExpression(LetExpression { key, vartype: None, value }))
|
Ok(Expression::LetExpression(LetExpression { key, vartype: None, value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_read(&mut self, target: Option<Expression>, _end: usize) -> Result<Expression> {
|
fn parse_read(&mut self, target: Option<Expression>, _end: usize) -> Result<Expression> {
|
||||||
let target = match target {
|
let target = target.map(Box::new);
|
||||||
Some(source) => Some(Box::new(source)),
|
|
||||||
None => None
|
|
||||||
};
|
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
let mut val_end = self.i;
|
let mut val_end = self.i;
|
||||||
let mut found_first = false;
|
let mut found_first = false;
|
||||||
|
|
@ -227,16 +225,13 @@ impl Tree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val_end -= 1;
|
val_end -= 1;
|
||||||
let source = Box::new(self.get_value(val_end)?);
|
let source = Box::new(self.get_value(val_end, false)?);
|
||||||
self.inc();
|
self.inc();
|
||||||
Ok(Expression::FileSourceExpression(FileSourceExpression { source, target }))
|
Ok(Expression::FileSourceExpression(FileSourceExpression { source, target }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_write(&mut self, source: Option<Expression>, _end: usize) -> Result<Expression> {
|
fn parse_write(&mut self, source: Option<Expression>, _end: usize) -> Result<Expression> {
|
||||||
let source = match source {
|
let source = source.map(Box::new);
|
||||||
Some(source) => Some(Box::new(source)),
|
|
||||||
None => None
|
|
||||||
};
|
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
let mut val_end = self.i;
|
let mut val_end = self.i;
|
||||||
let mut found_first = false;
|
let mut found_first = false;
|
||||||
|
|
@ -251,7 +246,7 @@ impl Tree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val_end -= 1;
|
val_end -= 1;
|
||||||
let target = Box::new(self.get_value(val_end)?);
|
let target = Box::new(self.get_value(val_end, false)?);
|
||||||
self.inc();
|
self.inc();
|
||||||
Ok(Expression::FileTargetExpression(FileTargetExpression { source, target }))
|
Ok(Expression::FileTargetExpression(FileTargetExpression { source, target }))
|
||||||
}
|
}
|
||||||
|
|
@ -353,14 +348,27 @@ impl Tree {
|
||||||
Ok(expressions)
|
Ok(expressions)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_value(&mut self, end: usize) -> Result<Value> {
|
fn parse_array_definition(&mut self, end: usize) -> Result<Vec<Value>> {
|
||||||
|
let mut values: Vec<Value> = Vec::new();
|
||||||
|
if matches!(self.get_current_token(), Tokens::Space) { self.inc(); }
|
||||||
|
loop {
|
||||||
|
if self.i >= end - 1 { break; }
|
||||||
|
let val = self.get_value(end, true)?;
|
||||||
|
values.push(val);
|
||||||
|
if matches!(self.get_current_token(), Tokens::Space) { self.inc(); }
|
||||||
|
}
|
||||||
|
Ok(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_value(&mut self, end: usize, stop_on_space: bool) -> Result<Value> {
|
||||||
let mut token = self.get_current_token();
|
let mut token = self.get_current_token();
|
||||||
let mut values: Vec<Value> = Vec::new();
|
let mut values: Vec<Value> = Vec::new();
|
||||||
let mut buf: Vec<Value> = Vec::new();
|
let mut buf: Vec<Value> = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
match token {
|
match token {
|
||||||
Tokens::Space => {
|
Tokens::Space => {
|
||||||
if buf.len() == 0 { token = self.inc().get_current_token(); continue; }
|
if stop_on_space { break; }
|
||||||
|
if buf.is_empty() { token = self.inc().get_current_token(); continue; }
|
||||||
values.push(Value::Values(buf));
|
values.push(Value::Values(buf));
|
||||||
buf = Vec::new();
|
buf = Vec::new();
|
||||||
if self.i >= end - 1 { break }
|
if self.i >= end - 1 { break }
|
||||||
|
|
@ -376,6 +384,31 @@ impl Tree {
|
||||||
Tokens::ArrayFunction(_) => bail!("Unexpected array function"),
|
Tokens::ArrayFunction(_) => bail!("Unexpected array function"),
|
||||||
Tokens::StringFunction(_) => bail!("Unexpected string function"),
|
Tokens::StringFunction(_) => bail!("Unexpected string function"),
|
||||||
Tokens::ParenthesisStart => bail!("Parenthesis not yet implemented"),
|
Tokens::ParenthesisStart => bail!("Parenthesis not yet implemented"),
|
||||||
|
Tokens::ArrayStart => {
|
||||||
|
let mut len = 0;
|
||||||
|
let mut lvl = 1;
|
||||||
|
self.inc();
|
||||||
|
for token in &self.tokens[self.i..] {
|
||||||
|
match token.token {
|
||||||
|
Tokens::ArrayStart => lvl += 1,
|
||||||
|
Tokens::ArrayEnd => lvl -= 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if lvl == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if len + self.i == end { break }
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
if lvl != 0 {
|
||||||
|
bail!("Parenthesis do not match");
|
||||||
|
}
|
||||||
|
let val = Value::ArrayDefinition(self.parse_array_definition(self.i + len)?);
|
||||||
|
values.push(val);
|
||||||
|
self.inc();
|
||||||
|
},
|
||||||
|
Tokens::ArrayEnd => bail!("Unexpected token ARRAY END (])"),
|
||||||
Tokens::SubStart => {
|
Tokens::SubStart => {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
let mut lvl = 1;
|
let mut lvl = 1;
|
||||||
|
|
@ -411,14 +444,14 @@ impl Tree {
|
||||||
Tokens::Let => buf.push(Value::Literal(token.to_str())),
|
Tokens::Let => buf.push(Value::Literal(token.to_str())),
|
||||||
Tokens::While => buf.push(Value::Literal(token.to_str())),
|
Tokens::While => buf.push(Value::Literal(token.to_str())),
|
||||||
Tokens::StringVariable(str, _) => {
|
Tokens::StringVariable(str, _) => {
|
||||||
if buf.len() != 0 {
|
if !buf.is_empty() {
|
||||||
values.push(Value::Values(buf));
|
values.push(Value::Values(buf));
|
||||||
buf = Vec::new();
|
buf = Vec::new();
|
||||||
}
|
}
|
||||||
values.push(Value::Variable(str.clone()));
|
values.push(Value::Variable(str.clone()));
|
||||||
},
|
},
|
||||||
Tokens::ArrayVariable(str, _) => {
|
Tokens::ArrayVariable(str, _) => {
|
||||||
if buf.len() != 0 {
|
if !buf.is_empty() {
|
||||||
values.push(Value::Values(buf));
|
values.push(Value::Values(buf));
|
||||||
buf = Vec::new();
|
buf = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
@ -432,9 +465,12 @@ impl Tree {
|
||||||
if self.i >= end - 1 { break }
|
if self.i >= end - 1 { break }
|
||||||
token = self.inc().get_current_token();
|
token = self.inc().get_current_token();
|
||||||
}
|
}
|
||||||
if buf.len() > 0 {
|
if !buf.is_empty() {
|
||||||
values.push(Value::Values(buf));
|
values.push(Value::Values(buf));
|
||||||
}
|
}
|
||||||
|
if values.len() == 1 {
|
||||||
|
return Ok(values.into_iter().next().unwrap());
|
||||||
|
}
|
||||||
Ok(Value::Values(values))
|
Ok(Value::Values(values))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -487,6 +523,8 @@ impl Tree {
|
||||||
self.inc();
|
self.inc();
|
||||||
},
|
},
|
||||||
Tokens::ParenthesisEnd => bail!("Unexpected token PARENTHESIS END ())"),
|
Tokens::ParenthesisEnd => bail!("Unexpected token PARENTHESIS END ())"),
|
||||||
|
Tokens::ArrayStart => bail!("Arrays not yet implemented"),
|
||||||
|
Tokens::ArrayEnd => bail!("Unexpected token ARRAY END (])"),
|
||||||
Tokens::ArrayFunction(_) => bail!("Unexpected array function"),
|
Tokens::ArrayFunction(_) => bail!("Unexpected array function"),
|
||||||
Tokens::StringFunction(_) => bail!("Unexpected string function"),
|
Tokens::StringFunction(_) => bail!("Unexpected string function"),
|
||||||
Tokens::SubStart => match expr {
|
Tokens::SubStart => match expr {
|
||||||
|
|
@ -528,7 +566,7 @@ impl Tree {
|
||||||
Tokens::Break => match expr {
|
Tokens::Break => match expr {
|
||||||
None => {
|
None => {
|
||||||
self.inc();
|
self.inc();
|
||||||
expr = Some(Expression::BreakExpression(BreakExpression { num: Box::new(self.get_value(end)?)}));
|
expr = Some(Expression::BreakExpression(BreakExpression { num: Box::new(self.get_value(end, false)?)}));
|
||||||
},
|
},
|
||||||
Some(_) => bail!("Unexpected break")
|
Some(_) => bail!("Unexpected break")
|
||||||
}
|
}
|
||||||
|
|
@ -552,6 +590,7 @@ impl Tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_tree(tokens: Vec<Token>) -> Result<Vec<Expression>> {
|
pub fn build_tree(tokens: Vec<Token>) -> Result<Vec<Expression>> {
|
||||||
|
dbg!(&tokens);
|
||||||
let mut expressions: Vec<Expression> = Vec::new();
|
let mut expressions: Vec<Expression> = Vec::new();
|
||||||
let mut tree = Tree { tokens, i: 0 };
|
let mut tree = Tree { tokens, i: 0 };
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ impl GetValue for Value {
|
||||||
ctx.pop_scope();
|
ctx.pop_scope();
|
||||||
Ok(Variable::String(out))
|
Ok(Variable::String(out))
|
||||||
},
|
},
|
||||||
Value::Values(vec) => {
|
Value::Values(vec) | Value::ArrayDefinition(vec) => {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for val in vec {
|
for val in vec {
|
||||||
out.push(val.get(ctx)?);
|
out.push(val.get(ctx)?);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ pub enum Tokens {
|
||||||
StringFunction(String),
|
StringFunction(String),
|
||||||
ParenthesisStart,
|
ParenthesisStart,
|
||||||
ParenthesisEnd,
|
ParenthesisEnd,
|
||||||
|
ArrayStart,
|
||||||
|
ArrayEnd,
|
||||||
CommandEnd(char),
|
CommandEnd(char),
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
|
|
@ -49,10 +51,12 @@ impl Tokens {
|
||||||
"$(" => Tokens::SubStart,
|
"$(" => Tokens::SubStart,
|
||||||
"(" => Tokens::ParenthesisStart,
|
"(" => Tokens::ParenthesisStart,
|
||||||
")" => Tokens::ParenthesisEnd,
|
")" => Tokens::ParenthesisEnd,
|
||||||
|
"[" => Tokens::ArrayStart,
|
||||||
|
"]" => Tokens::ArrayEnd,
|
||||||
">" => Tokens::FileWrite,
|
">" => Tokens::FileWrite,
|
||||||
"<" => Tokens::FileRead,
|
"<" => Tokens::FileRead,
|
||||||
"|" => Tokens::RedirectInto,
|
"|" => Tokens::RedirectInto,
|
||||||
"\r\n" | "\n" | ";" => Tokens::CommandEnd(str.chars().nth(0).unwrap()),
|
"\r\n" | "\n" | ";" => Tokens::CommandEnd(str.chars().next().unwrap()),
|
||||||
"&&" => Tokens::And,
|
"&&" => Tokens::And,
|
||||||
"||" => Tokens::Or,
|
"||" => Tokens::Or,
|
||||||
"=" => Tokens::ExportSet,
|
"=" => Tokens::ExportSet,
|
||||||
|
|
@ -81,6 +85,8 @@ impl Tokens {
|
||||||
Tokens::SubStart => "$(".to_string(),
|
Tokens::SubStart => "$(".to_string(),
|
||||||
Tokens::ParenthesisStart => "(".to_string(),
|
Tokens::ParenthesisStart => "(".to_string(),
|
||||||
Tokens::ParenthesisEnd => ")".to_string(),
|
Tokens::ParenthesisEnd => ")".to_string(),
|
||||||
|
Tokens::ArrayStart => "[".to_string(),
|
||||||
|
Tokens::ArrayEnd => "]".to_string(),
|
||||||
Tokens::RedirectInto => "|".to_string(),
|
Tokens::RedirectInto => "|".to_string(),
|
||||||
Tokens::FileRead => "<".to_string(),
|
Tokens::FileRead => "<".to_string(),
|
||||||
Tokens::FileWrite => ">".to_string(),
|
Tokens::FileWrite => ">".to_string(),
|
||||||
|
|
@ -93,7 +99,7 @@ impl Tokens {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn read_var_ahead(i: usize, text: &String) -> (usize, Token) {
|
fn read_var_ahead(i: usize, text: &str) -> Result<(usize, Token)> {
|
||||||
let mut x = i;
|
let mut x = i;
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let parens_mode = text.chars().nth(x + 1).unwrap() == '{';
|
let parens_mode = text.chars().nth(x + 1).unwrap() == '{';
|
||||||
|
|
@ -103,7 +109,7 @@ fn read_var_ahead(i: usize, text: &String) -> (usize, Token) {
|
||||||
let letter: char = text.chars().nth(x).unwrap();
|
let letter: char = text.chars().nth(x).unwrap();
|
||||||
match letter {
|
match letter {
|
||||||
'a'..='z' | 'A'..='Z' | '0'..='9' | ':' | '_' => {
|
'a'..='z' | 'A'..='Z' | '0'..='9' | ':' | '_' => {
|
||||||
buf.push(letter.clone());
|
buf.push(letter);
|
||||||
}
|
}
|
||||||
'}' => {
|
'}' => {
|
||||||
if parens_mode {
|
if parens_mode {
|
||||||
|
|
@ -112,19 +118,19 @@ fn read_var_ahead(i: usize, text: &String) -> (usize, Token) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
'?' => {
|
'?' => {
|
||||||
buf.push(letter.clone());
|
buf.push(letter);
|
||||||
x += 1;
|
x += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
l => { if !parens_mode { break } else { panic!("Invalid variable name (starting with '{:?}{:?}')", buf, l) } }
|
l => { if !parens_mode { break } else { bail!("Invalid variable name (starting with '{}{}')", buf, l) } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let token = match text.chars().nth(i).unwrap() {
|
let token = match text.chars().nth(i).unwrap() {
|
||||||
'$' => Token { token: Tokens::StringVariable(buf, parens_mode), start: i, end: i + x },
|
'$' => Token { token: Tokens::StringVariable(buf, parens_mode), start: i, end: i + x },
|
||||||
'@' => Token { token: Tokens::ArrayVariable(buf, parens_mode), start:i , end: i+x },
|
'@' => Token { token: Tokens::ArrayVariable(buf, parens_mode), start:i , end: i+x },
|
||||||
a => panic!("Invalid value {}", a)
|
a => bail!("Invalid value {}", a)
|
||||||
};
|
};
|
||||||
(x - i - 1, token)
|
Ok((x - i - 1, token))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
||||||
|
|
@ -133,12 +139,12 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
||||||
let mut escape_active = false;
|
let mut escape_active = false;
|
||||||
let mut text = String::new();
|
let mut text = String::new();
|
||||||
reader.read_to_string(&mut text)?;
|
reader.read_to_string(&mut text)?;
|
||||||
let mut text_length = text.len();
|
let text_length = text.len();
|
||||||
|
|
||||||
let mut tokens: Vec<Token> = Vec::new();
|
let mut tokens: Vec<Token> = Vec::new();
|
||||||
|
|
||||||
fn save_buf(buf: &mut String, tokens: &mut Vec<Token>, i: usize) {
|
fn save_buf(buf: &mut String, tokens: &mut Vec<Token>, i: usize) {
|
||||||
if buf.len() > 0 { tokens.push(Token { token: Tokens::detect(std::mem::take(buf)), end: i, start: i - buf.len() }) }
|
if !buf.is_empty() { tokens.push(Token { token: Tokens::detect(std::mem::take(buf)), end: i, start: i - buf.len() }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
@ -153,24 +159,20 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
||||||
match letter {
|
match letter {
|
||||||
'"' => if !escape_active && !quote_active { double_quote_active = !double_quote_active; buf_add = false },
|
'"' => if !escape_active && !quote_active { double_quote_active = !double_quote_active; buf_add = false },
|
||||||
'\'' => if !escape_active && !double_quote_active { quote_active = !quote_active; buf_add = false },
|
'\'' => if !escape_active && !double_quote_active { quote_active = !quote_active; buf_add = false },
|
||||||
'$' => if !escape_active && !quote_active {
|
'$' | '@' => if !escape_active && !quote_active {
|
||||||
save_buf(&mut buf, &mut tokens, i);
|
save_buf(&mut buf, &mut tokens, i);
|
||||||
if text_length > i && text.chars().nth(i + 1).unwrap() == '(' {
|
if *letter == '$' && text_length > i && text.chars().nth(i + 1).unwrap() == '(' {
|
||||||
tokens.push(Token { token: Tokens::SubStart, start: i, end: i+1 });
|
tokens.push(Token { token: Tokens::SubStart, start: i, end: i+1 });
|
||||||
skipper = 1;
|
skipper = 1;
|
||||||
buf_add = false;
|
buf_add = false;
|
||||||
} else {
|
} else {
|
||||||
let (skippers, mut token) = read_var_ahead(i, &text);
|
let (skippers, mut token) = read_var_ahead(i, &text)?;
|
||||||
match token.token {
|
match token.token {
|
||||||
Tokens::StringVariable(ref str, bool) => if !bool && !double_quote_active {
|
Tokens::StringVariable(ref str, bool) => if !bool && !double_quote_active && text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
|
||||||
if text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
|
token = Token { token: Tokens::StringFunction(str.clone()), end: i + skippers, start: i };
|
||||||
token = Token { token: Tokens::StringFunction(str.clone()), end: i + skippers, start: i };
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Tokens::ArrayVariable(ref str, bool) => if !bool && !double_quote_active {
|
Tokens::ArrayVariable(ref str, bool) => if !bool && !double_quote_active && text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
|
||||||
if text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
|
token = Token { token: Tokens::ArrayFunction(str.clone()), end: i+skippers, start: i };
|
||||||
token = Token { token: Tokens::ArrayFunction(str.clone()), end: i+skippers, start: i };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => bail!("Cannot happen")
|
_ => bail!("Cannot happen")
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +183,7 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
||||||
},
|
},
|
||||||
';' | '\r' | '\n' => if !escape_active && !quote_active && !double_quote_active {
|
';' | '\r' | '\n' => if !escape_active && !quote_active && !double_quote_active {
|
||||||
save_buf(&mut buf, &mut tokens, i);
|
save_buf(&mut buf, &mut tokens, i);
|
||||||
tokens.push(Token { token: Tokens::CommandEnd(letter.clone()), start: i, end: i });
|
tokens.push(Token { token: Tokens::CommandEnd(*letter), start: i, end: i });
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
while x < text.len() - 1 && matches!(text.chars().nth(x).unwrap(), '\n' | '\r' | ';' | ' ') {
|
while x < text.len() - 1 && matches!(text.chars().nth(x).unwrap(), '\n' | '\r' | ';' | ' ') {
|
||||||
x += 1;
|
x += 1;
|
||||||
|
|
@ -231,6 +233,16 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
||||||
tokens.push(Token { token: Tokens::ParenthesisEnd, start: i, end: i });
|
tokens.push(Token { token: Tokens::ParenthesisEnd, start: i, end: i });
|
||||||
buf_add = false;
|
buf_add = false;
|
||||||
},
|
},
|
||||||
|
'[' => if !quote_active && !double_quote_active && !escape_active {
|
||||||
|
save_buf(&mut buf, &mut tokens, i);
|
||||||
|
tokens.push(Token { token: Tokens::ArrayStart, start: i, end: i });
|
||||||
|
buf_add = false;
|
||||||
|
},
|
||||||
|
']' => if !quote_active && !double_quote_active && !escape_active {
|
||||||
|
save_buf(&mut buf, &mut tokens, i);
|
||||||
|
tokens.push(Token { token: Tokens::ArrayEnd, start: i, end: i });
|
||||||
|
buf_add = false;
|
||||||
|
},
|
||||||
'\\' => if !escape_active {
|
'\\' => if !escape_active {
|
||||||
escape_active = true;
|
escape_active = true;
|
||||||
buf_add = false;
|
buf_add = false;
|
||||||
|
|
@ -253,7 +265,7 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if letter.clone() != '\\' { escape_active = false; }
|
if *letter != '\\' { escape_active = false; }
|
||||||
if buf_add {
|
if buf_add {
|
||||||
buf.push(*letter);
|
buf.push(*letter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use crate::parser::ast::FunctionDefinitionExpression;
|
use crate::parser::ast::FunctionDefinitionExpression;
|
||||||
|
|
||||||
|
|
@ -17,9 +18,9 @@ pub enum Variable {
|
||||||
Array(Vec<Variable>)
|
Array(Vec<Variable>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Variable {
|
impl Display for Variable {
|
||||||
pub fn to_string(self: &Self) -> String {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
write!(f, "{}", match self {
|
||||||
Variable::String(var) => {
|
Variable::String(var) => {
|
||||||
var.clone()
|
var.clone()
|
||||||
},
|
},
|
||||||
|
|
@ -36,23 +37,98 @@ impl Variable {
|
||||||
},
|
},
|
||||||
Variable::Array(vars) => {
|
Variable::Array(vars) => {
|
||||||
let len = vars.len();
|
let len = vars.len();
|
||||||
if len == 1 { return vars.get(0).unwrap().to_string(); }
|
if len == 1 {
|
||||||
|
return match vars.get(0) {
|
||||||
|
Some(var) => write!(f, "{}", var),
|
||||||
|
None => write!(f, "[]")
|
||||||
|
}
|
||||||
|
}
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
let mut i = 0;
|
for (i, var) in vars.iter().enumerate() {
|
||||||
for var in vars {
|
|
||||||
str += &*var.clone().to_string();
|
str += &*var.clone().to_string();
|
||||||
if i < len - 1 {
|
if i < len - 1 {
|
||||||
str += " ";
|
str += " ";
|
||||||
}
|
}
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
str
|
str
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn index(self: &Self, index: &Variable) -> Result<&Variable> {
|
impl Variable {
|
||||||
|
pub fn index(&self, index: &Variable) -> Result<&Variable> {
|
||||||
match self {
|
match self {
|
||||||
|
Variable::HMap(map) => {
|
||||||
|
match index {
|
||||||
|
Variable::String(key) => {
|
||||||
|
match map.get(key) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Key not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => bail!("Cannot index with non-string")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Variable::Array(arr) => {
|
||||||
|
match index {
|
||||||
|
Variable::I32(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::I64(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::I128(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::F32(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::F64(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::U32(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::U64(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::U128(idx) => {
|
||||||
|
match arr.get(*idx as usize) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variable::String(idx) => {
|
||||||
|
match arr.get(idx.parse::<usize>()?) {
|
||||||
|
Some(val) => Ok(val),
|
||||||
|
None => bail!("Index out of bounds")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => bail!("Cannot index with non-integer")
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => bail!("Cannot index unsupported types")
|
_ => bail!("Cannot index unsupported types")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -100,11 +176,11 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_var(self: &mut Self, var: &str) -> Option<&mut Variable> {
|
pub fn get_var(self: &mut Self, var: &str) -> Option<&mut Variable> {
|
||||||
for mut scope in self.scopes.iter_mut().rev() {
|
for scope in self.scopes.iter_mut().rev() {
|
||||||
let mut vars = &mut scope.vars;
|
let vars = &mut scope.vars;
|
||||||
let val = vars.get_mut(var);
|
let val = vars.get_mut(var);
|
||||||
match val {
|
match val {
|
||||||
None => {},
|
None => {}
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
return Some(val);
|
return Some(val);
|
||||||
}
|
}
|
||||||
|
|
@ -114,16 +190,16 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_var(&mut self, key: String, val: Variable) {
|
pub fn set_var(&mut self, key: String, val: Variable) {
|
||||||
let mut vars = &mut self.scopes.last_mut().unwrap().vars;
|
let vars = &mut self.scopes.last_mut().unwrap().vars;
|
||||||
vars.insert(key, val);
|
vars.insert(key, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_func(self: &mut Self, key: &str) -> Option<&mut FunctionDefinitionExpression> {
|
pub fn get_func(self: &mut Self, key: &str) -> Option<&mut FunctionDefinitionExpression> {
|
||||||
for mut scope in self.scopes.iter_mut().rev() {
|
for scope in self.scopes.iter_mut().rev() {
|
||||||
let mut funcs = &mut scope.func;
|
let funcs = &mut scope.func;
|
||||||
let val = funcs.get_mut(key);
|
let val = funcs.get_mut(key);
|
||||||
match val {
|
match val {
|
||||||
None => {},
|
None => {}
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
return Some(val);
|
return Some(val);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue