From b0a774994fd2557de773277f655946ddd28011e7 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Sat, 5 Aug 2023 11:40:27 +0200 Subject: [PATCH] small fixes, array definition support --- src/main.rs | 6 ++- src/parser/ast.rs | 83 ++++++++++++++++++++++++--------- src/parser/exec.rs | 2 +- src/parser/tokens.rs | 56 +++++++++++++--------- src/parser/vars.rs | 108 ++++++++++++++++++++++++++++++++++++------- 5 files changed, 193 insertions(+), 62 deletions(-) diff --git a/src/main.rs b/src/main.rs index 36c4de8..4a9765a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,9 +33,10 @@ impl Term { fn format(self: &Self, stdout: &mut RawTerminal) -> 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 { diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 2e3e7a1..969184c 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -58,6 +58,7 @@ pub enum Value { Literal(String), Variable(String), ArrayVariable(String), + ArrayDefinition(Vec), ArrayFunction(DefinedFunction), StringFunction(DefinedFunction), Expressions(Vec), @@ -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, _end: usize) -> Result { - 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, _end: usize) -> Result { - 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 { + fn parse_array_definition(&mut self, end: usize) -> Result> { + let mut values: Vec = 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 { let mut token = self.get_current_token(); let mut values: Vec = Vec::new(); let mut buf: Vec = 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) -> Result> { + dbg!(&tokens); let mut expressions: Vec = Vec::new(); let mut tree = Tree { tokens, i: 0 }; loop { diff --git a/src/parser/exec.rs b/src/parser/exec.rs index 863be9a..97ab9c6 100644 --- a/src/parser/exec.rs +++ b/src/parser/exec.rs @@ -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)?); diff --git a/src/parser/tokens.rs b/src/parser/tokens.rs index 6d9a974..a775cc4 100644 --- a/src/parser/tokens.rs +++ b/src/parser/tokens.rs @@ -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> { @@ -133,12 +139,12 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> Result> { 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 = Vec::new(); fn save_buf(buf: &mut String, tokens: &mut Vec, 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> { 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> { }, ';' | '\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> { 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> { } _ => {} } - if letter.clone() != '\\' { escape_active = false; } + if *letter != '\\' { escape_active = false; } if buf_add { buf.push(*letter); } diff --git a/src/parser/vars.rs b/src/parser/vars.rs index b726a26..c845775 100644 --- a/src/parser/vars.rs +++ b/src/parser/vars.rs @@ -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) } -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::()?) { + 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); }