small fixes, array definition support

This commit is contained in:
Daniel Bulant 2023-08-05 11:40:27 +02:00
parent b000e924e8
commit b0a774994f
5 changed files with 193 additions and 62 deletions

View file

@ -33,9 +33,10 @@ impl Term {
fn format(self: &Self, stdout: &mut RawTerminal<Stdout>) -> String {
let (_, y) = stdout.cursor_pos().unwrap();
format!(
"{}{}{}{}{}",
"{}{}{}{}{}{}",
termion::clear::CurrentLine,
termion::cursor::Goto(1, y),
"$: ",
&self.input,
termion::cursor::Left((self.input.len() - self.idx).try_into().unwrap()),
termion::cursor::Right(if self.input.len() > 0 { 1 } else { 0 } )
@ -141,6 +142,9 @@ impl Shell {
print!("$: ");
io::stdout().flush().unwrap();
shell.collect();
if shell.term.input == "exit" {
break;
}
shell.term.input += "\n";
let res = parser::exec(&mut shell.term.input.as_bytes(), &mut shell.ctx);
match res {

View file

@ -58,6 +58,7 @@ pub enum Value {
Literal(String),
Variable(String),
ArrayVariable(String),
ArrayDefinition(Vec<Value>),
ArrayFunction(DefinedFunction),
StringFunction(DefinedFunction),
Expressions(Vec<Expression>),
@ -137,7 +138,7 @@ impl Tree {
let mut token = self.get_current_token();
loop {
if matches!(token, Tokens::Space) {
if buf.len() > 0 {
if !buf.is_empty() {
values.push(CommandValue::Value(Value::Values(buf)));
buf = Vec::new();
}
@ -149,12 +150,12 @@ impl Tree {
let val = match &token {
Tokens::Literal(str) => Value::Literal(str.clone()),
Tokens::SubStart => {
let val = self.get_value(end)?;
let val = self.get_value(end, false)?;
token = self.get_current_token();
val
},
Tokens::StringVariable(str, _) => {
if str.len() == 0 { bail!("Expected variable name"); }
if str.is_empty() { bail!("Expected variable name"); }
Value::Variable(str.clone())
},
Tokens::ArrayVariable(str, _) => Value::ArrayVariable(str.clone()),
@ -185,7 +186,7 @@ impl Tree {
_ => {}
}
// self.next();
if buf.len() > 0 {
if !buf.is_empty() {
values.push(CommandValue::Value(Value::Values(buf)));
}
Ok(Expression::Command(values))
@ -201,18 +202,15 @@ impl Tree {
_ => 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();
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 }))
}
fn parse_read(&mut self, target: Option<Expression>, _end: usize) -> Result<Expression> {
let target = match target {
Some(source) => Some(Box::new(source)),
None => None
};
let target = target.map(Box::new);
self.i += 1;
let mut val_end = self.i;
let mut found_first = false;
@ -227,16 +225,13 @@ impl Tree {
}
}
val_end -= 1;
let source = Box::new(self.get_value(val_end)?);
let source = Box::new(self.get_value(val_end, false)?);
self.inc();
Ok(Expression::FileSourceExpression(FileSourceExpression { source, target }))
}
fn parse_write(&mut self, source: Option<Expression>, _end: usize) -> Result<Expression> {
let source = match source {
Some(source) => Some(Box::new(source)),
None => None
};
let source = source.map(Box::new);
self.i += 1;
let mut val_end = self.i;
let mut found_first = false;
@ -251,7 +246,7 @@ impl Tree {
}
}
val_end -= 1;
let target = Box::new(self.get_value(val_end)?);
let target = Box::new(self.get_value(val_end, false)?);
self.inc();
Ok(Expression::FileTargetExpression(FileTargetExpression { source, target }))
}
@ -353,14 +348,27 @@ impl Tree {
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 values: Vec<Value> = Vec::new();
let mut buf: Vec<Value> = Vec::new();
loop {
match token {
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));
buf = Vec::new();
if self.i >= end - 1 { break }
@ -376,6 +384,31 @@ impl Tree {
Tokens::ArrayFunction(_) => bail!("Unexpected array function"),
Tokens::StringFunction(_) => bail!("Unexpected string function"),
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 => {
let mut len = 0;
let mut lvl = 1;
@ -411,14 +444,14 @@ impl Tree {
Tokens::Let => buf.push(Value::Literal(token.to_str())),
Tokens::While => buf.push(Value::Literal(token.to_str())),
Tokens::StringVariable(str, _) => {
if buf.len() != 0 {
if !buf.is_empty() {
values.push(Value::Values(buf));
buf = Vec::new();
}
values.push(Value::Variable(str.clone()));
},
Tokens::ArrayVariable(str, _) => {
if buf.len() != 0 {
if !buf.is_empty() {
values.push(Value::Values(buf));
buf = Vec::new();
}
@ -432,9 +465,12 @@ impl Tree {
if self.i >= end - 1 { break }
token = self.inc().get_current_token();
}
if buf.len() > 0 {
if !buf.is_empty() {
values.push(Value::Values(buf));
}
if values.len() == 1 {
return Ok(values.into_iter().next().unwrap());
}
Ok(Value::Values(values))
}
@ -487,6 +523,8 @@ impl Tree {
self.inc();
},
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::StringFunction(_) => bail!("Unexpected string function"),
Tokens::SubStart => match expr {
@ -528,7 +566,7 @@ impl Tree {
Tokens::Break => match expr {
None => {
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")
}
@ -552,6 +590,7 @@ impl Tree {
}
pub fn build_tree(tokens: Vec<Token>) -> Result<Vec<Expression>> {
dbg!(&tokens);
let mut expressions: Vec<Expression> = Vec::new();
let mut tree = Tree { tokens, i: 0 };
loop {

View file

@ -131,7 +131,7 @@ impl GetValue for Value {
ctx.pop_scope();
Ok(Variable::String(out))
},
Value::Values(vec) => {
Value::Values(vec) | Value::ArrayDefinition(vec) => {
let mut out = Vec::new();
for val in vec {
out.push(val.get(ctx)?);

View file

@ -19,6 +19,8 @@ pub enum Tokens {
StringFunction(String),
ParenthesisStart,
ParenthesisEnd,
ArrayStart,
ArrayEnd,
CommandEnd(char),
If,
Else,
@ -49,10 +51,12 @@ impl Tokens {
"$(" => Tokens::SubStart,
"(" => Tokens::ParenthesisStart,
")" => Tokens::ParenthesisEnd,
"[" => Tokens::ArrayStart,
"]" => Tokens::ArrayEnd,
">" => Tokens::FileWrite,
"<" => Tokens::FileRead,
"|" => Tokens::RedirectInto,
"\r\n" | "\n" | ";" => Tokens::CommandEnd(str.chars().nth(0).unwrap()),
"\r\n" | "\n" | ";" => Tokens::CommandEnd(str.chars().next().unwrap()),
"&&" => Tokens::And,
"||" => Tokens::Or,
"=" => Tokens::ExportSet,
@ -81,6 +85,8 @@ impl Tokens {
Tokens::SubStart => "$(".to_string(),
Tokens::ParenthesisStart => "(".to_string(),
Tokens::ParenthesisEnd => ")".to_string(),
Tokens::ArrayStart => "[".to_string(),
Tokens::ArrayEnd => "]".to_string(),
Tokens::RedirectInto => "|".to_string(),
Tokens::FileRead => "<".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 buf = String::new();
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();
match letter {
'a'..='z' | 'A'..='Z' | '0'..='9' | ':' | '_' => {
buf.push(letter.clone());
buf.push(letter);
}
'}' => {
if parens_mode {
@ -112,19 +118,19 @@ fn read_var_ahead(i: usize, text: &String) -> (usize, Token) {
break;
}
'?' => {
buf.push(letter.clone());
buf.push(letter);
x += 1;
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() {
'$' => Token { token: Tokens::StringVariable(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>> {
@ -133,12 +139,12 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
let mut escape_active = false;
let mut text = String::new();
reader.read_to_string(&mut text)?;
let mut text_length = text.len();
let text_length = text.len();
let mut tokens: Vec<Token> = Vec::new();
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();
@ -153,24 +159,20 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result<Vec<Token>> {
match letter {
'"' => 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 && !quote_active {
'$' | '@' => if !escape_active && !quote_active {
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 });
skipper = 1;
buf_add = false;
} else {
let (skippers, mut token) = read_var_ahead(i, &text);
let (skippers, mut token) = read_var_ahead(i, &text)?;
match token.token {
Tokens::StringVariable(ref str, bool) => if !bool && !double_quote_active {
if text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
token = Token { token: Tokens::StringFunction(str.clone()), end: i + skippers, start: i };
}
Tokens::StringVariable(ref str, bool) => if !bool && !double_quote_active && text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
token = Token { token: Tokens::StringFunction(str.clone()), end: i + skippers, start: i };
},
Tokens::ArrayVariable(ref str, bool) => if !bool && !double_quote_active {
if text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
token = Token { token: Tokens::ArrayFunction(str.clone()), end: i+skippers, start: i };
}
Tokens::ArrayVariable(ref str, bool) => if !bool && !double_quote_active && text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
token = Token { token: Tokens::ArrayFunction(str.clone()), end: i+skippers, start: i };
}
_ => 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 {
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;
while x < text.len() - 1 && matches!(text.chars().nth(x).unwrap(), '\n' | '\r' | ';' | ' ') {
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 });
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 {
escape_active = true;
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 {
buf.push(*letter);
}

View file

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use anyhow::{bail, Result};
use crate::parser::ast::FunctionDefinitionExpression;
@ -17,9 +18,9 @@ pub enum Variable {
Array(Vec<Variable>)
}
impl Variable {
pub fn to_string(self: &Self) -> String {
match self {
impl Display for Variable {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
Variable::String(var) => {
var.clone()
},
@ -36,23 +37,98 @@ impl Variable {
},
Variable::Array(vars) => {
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 i = 0;
for var in vars {
for (i, var) in vars.iter().enumerate() {
str += &*var.clone().to_string();
if i < len - 1 {
str += " ";
}
i += 1;
}
str
}
}
})
}
}
pub fn index(self: &Self, index: &Variable) -> Result<&Variable> {
impl Variable {
pub fn index(&self, index: &Variable) -> Result<&Variable> {
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")
}
}
@ -100,11 +176,11 @@ impl Context {
}
pub fn get_var(self: &mut Self, var: &str) -> Option<&mut Variable> {
for mut scope in self.scopes.iter_mut().rev() {
let mut vars = &mut scope.vars;
for scope in self.scopes.iter_mut().rev() {
let vars = &mut scope.vars;
let val = vars.get_mut(var);
match val {
None => {},
None => {}
Some(val) => {
return Some(val);
}
@ -114,16 +190,16 @@ impl Context {
}
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);
}
pub fn get_func(self: &mut Self, key: &str) -> Option<&mut FunctionDefinitionExpression> {
for mut scope in self.scopes.iter_mut().rev() {
let mut funcs = &mut scope.func;
for scope in self.scopes.iter_mut().rev() {
let funcs = &mut scope.func;
let val = funcs.get_mut(key);
match val {
None => {},
None => {}
Some(val) => {
return Some(val);
}