feat: working AST parsing

This commit is contained in:
Daniel Bulant 2021-12-08 21:29:59 +01:00
parent 78d4cea4fe
commit 847e49ec92
5 changed files with 333 additions and 95 deletions

View file

@ -1,17 +1,16 @@
mod parser; mod parser;
use std::io::{self, BufRead, Read, Stdout, Write}; use std::io::{self, BufRead, Stdout, Write};
use std::cmp; use std::cmp;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::ops::Add;
use std::process; use std::process;
use termion::raw::{IntoRawMode, RawTerminal}; use termion::raw::{IntoRawMode, RawTerminal};
use termion::input::TermRead; use termion::input::TermRead;
use termion::cursor::{self, DetectCursorPos}; use termion::cursor::{DetectCursorPos};
use termion::event::*; use termion::event::*;
use termion::input::{MouseTerminal}; // use termion::input::{MouseTerminal};
struct Term { struct Term {
input: String, input: String,
@ -72,6 +71,8 @@ impl Shell {
fn main() { fn main() {
loop { loop {
print!("$: ");
io::stdout().flush();
let mut shell = collect(); let mut shell = collect();
shell.term.input += "\n"; shell.term.input += "\n";
parser::exec(&mut shell.term.input.as_bytes(), shell.ctx); parser::exec(&mut shell.term.input.as_bytes(), shell.ctx);

View file

@ -1,12 +1,23 @@
use crate::parser::tokens::Tokens; use crate::parser::tokens::Tokens;
use crate::parser::vars::Variable;
#[derive(Debug)] #[derive(Debug)]
pub struct LetExpression { pub struct LetExpression {
pub key: String, pub key: Box<Value>,
pub value: Box<Value> pub value: Box<Value>
} }
#[derive(Debug)]
pub struct AndExpression {
pub first: Box<Expression>,
pub second: Box<Expression>
}
#[derive(Debug)]
pub struct OrExpression {
pub first: Box<Expression>,
pub second: Box<Expression>
}
#[derive(Debug)] #[derive(Debug)]
pub struct IfExpression { pub struct IfExpression {
pub condition: Box<Expression>, pub condition: Box<Expression>,
@ -47,6 +58,7 @@ pub enum Value {
ArrayFunction(DefinedFunction), ArrayFunction(DefinedFunction),
StringFunction(DefinedFunction), StringFunction(DefinedFunction),
Expressions(Vec<Expression>), Expressions(Vec<Expression>),
Expression(Expression),
Values(Vec<Value>) Values(Vec<Value>)
} }
@ -84,108 +96,197 @@ pub enum CommandValue {
pub enum Expression { pub enum Expression {
LetExpression(LetExpression), LetExpression(LetExpression),
Command(Vec<CommandValue>), Command(Vec<CommandValue>),
JobCommand(Box<Expression>),
Function(FunctionDefinitionExpression), Function(FunctionDefinitionExpression),
IfExpression(IfExpression), IfExpression(IfExpression),
WhileExpression(WhileExpression), WhileExpression(WhileExpression),
ForExpression(ForExpression), ForExpression(ForExpression),
RedirectTargetExpression(RedirectTargetExpression), RedirectTargetExpression(RedirectTargetExpression),
FileTargetExpression(FileTargetExpression), FileTargetExpression(FileTargetExpression),
FileSourceExpression(FileSourceExpression) FileSourceExpression(FileSourceExpression),
Expressions(Vec<Expression>),
OrExpression(OrExpression),
AndExpression(AndExpression)
} }
#[derive(Debug)]
struct Tree { struct Tree {
tokens: Vec<Tokens>, tokens: Vec<Tokens>,
i: usize i: usize
} }
impl Tree { impl Tree {
fn parse_call(&mut self) -> Vec<CommandValue> { fn parse_call(&mut self, end: usize) -> Expression {
let mut values: Vec<CommandValue> = Vec::new(); let mut values: Vec<CommandValue> = Vec::new();
let mut token = self.get_current_token();
let mut buf: Vec<Value> = Vec::new(); let mut buf: Vec<Value> = Vec::new();
dbg!("call parse");
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.len() > 0 {
values.push(CommandValue::Value(Value::Values(buf))); values.push(CommandValue::Value(Value::Values(buf)));
buf = Vec::new(); buf = Vec::new();
} }
token = self.next(); if self.i >= end - 1 { break }
self.i += 1;
token = self.get_current_token();
dbg!("skip space");
continue; continue;
} }
let val = match token { let val = match &token {
Tokens::Literal(str) => Value::Literal(str.clone()), Tokens::Literal(str) => Value::Literal(str.clone()),
Tokens::SubStart => Value::Expressions(self.parse_sub()), Tokens::SubStart => {
let val = self.get_value(end);
token = self.get_current_token();
val
},
Tokens::StringVariable(str, _) => Value::Variable(str.clone()), Tokens::StringVariable(str, _) => Value::Variable(str.clone()),
Tokens::ArrayVariable(str, _) => Value::ArrayVariable(str.clone()), Tokens::ArrayVariable(str, _) => Value::ArrayVariable(str.clone()),
Tokens::FileWrite => { Tokens::FileWrite => break,
Tokens::FileRead => break,
Tokens::RedirectInto => break,
Tokens::ParenthesisEnd => {
if self.i >= end - 1 {
break;
}
Value::Literal(token.to_str())
} }
_ => { _ => {
Value::Literal(token.to_str()) Value::Literal(token.to_str())
} }
}; };
buf.push(val); buf.push(val);
if self.i == self.tokens.len() { break } if self.i >= end - 1 { break }
token = self.next(); self.i += 1;
token = self.tokens.get(self.i).unwrap();
if matches!(token, Tokens::CommandEnd(_)) { break } if matches!(token, Tokens::CommandEnd(_)) { break }
dbg!("parse call loop");
} }
dbg!(&token);
match &token {
Tokens::FileWrite | Tokens::FileRead | Tokens::RedirectInto => self.i -= 1,
_ => {}
}
dbg!(&self);
// self.next();
if buf.len() > 0 { if buf.len() > 0 {
values.push(CommandValue::Value(Value::Values(buf))); values.push(CommandValue::Value(Value::Values(buf)));
} }
values Expression::Command(values)
} }
fn parse_let(&self) -> LetExpression { fn parse_let(&mut self, end: usize) -> Expression {
panic!("Let not yet implemented"); if end < self.i + 2 { panic!("Let needs name and equal sign (=) at minimum") }
self.inc();
let mut len = 0;
for token in &self.tokens[self.i..] {
match token {
Tokens::ExportSet => { break },
_ => len += 1
}
}
let key = Box::new(self.get_value(self.i + len));
self.inc(); // ????
self.inc();
let value = Box::new(self.get_value(end));
Expression::LetExpression(LetExpression { key, value })
} }
fn parse_read(&self) -> FileSourceExpression { fn parse_read(&mut self, target: Option<Expression>, end: usize) -> Expression {
panic!("Read not yet implemented"); let target = match target {
Some(source) => Some(Box::new(source)),
None => None
};
self.i += 1;
let mut val_end = self.i;
let mut found_first = false;
for token in &self.tokens[self.i..] {
dbg!(&token);
val_end += 1;
match token {
Tokens::Space => if found_first { break },
Tokens::CommandEnd(_) => if !found_first { panic!("Unexpected command end") } else { break },
Tokens::FileRead => panic!("Unexpected file read (<)"),
Tokens::FileWrite => panic!("Unexpected file write (>)"),
_ => { found_first = true; }
}
}
dbg!(&self.tokens[self.i..val_end]);
val_end -= 1;
let source = Box::new(self.get_value(val_end));
self.inc();
Expression::FileSourceExpression(FileSourceExpression { source, target })
} }
fn parse_write(&self, source: Option<Expression>) -> FileTargetExpression { fn parse_write(&mut self, source: Option<Expression>, end: usize) -> Expression {
let source = match source { let source = match source {
Some(source) => Some(Box::new(source)), Some(source) => Some(Box::new(source)),
None => None None => None
}; };
self.i += 1;
let mut val_end = self.i;
let mut found_first = false;
for token in &self.tokens[self.i..] {
val_end += 1;
match token {
Tokens::Space => if found_first { break },
Tokens::CommandEnd(_) => if !found_first { panic!("Unexpected command end") } else { break },
Tokens::FileRead => panic!("Unexpected file read (<)"),
Tokens::FileWrite => panic!("Unexpected file write (>)"),
_ => { found_first = true; }
}
}
val_end -= 1;
let target = Box::new(self.get_value(val_end));
self.inc();
Expression::FileTargetExpression(FileTargetExpression { source, target })
} }
fn parse_function(&self) -> FunctionDefinitionExpression { fn parse_function(&self, end: usize) -> FunctionDefinitionExpression {
panic!("Functions not yet implemented") panic!("Functions not yet implemented")
} }
fn parse_array_func(&self, str: String) -> DefinedFunction { fn parse_array_func(&self, str: String, end: usize) -> DefinedFunction {
panic!("Array functions not yet implemented"); panic!("Array functions not yet implemented");
} }
fn parse_for(&self) -> ForExpression { fn parse_string_func(&self, str: String, end: usize) -> DefinedFunction {
panic!("Array functions not yet implemented");
}
fn parse_for(&self, end: usize) -> ForExpression {
panic!("For loop not yet implemented"); panic!("For loop not yet implemented");
} }
fn parse_if(&self) -> IfExpression { fn parse_if(&self, end: usize) -> IfExpression {
panic!("If not yet implemented"); panic!("If not yet implemented");
} }
fn parse_while(&self) -> WhileExpression { fn parse_while(&self, end: usize) -> WhileExpression {
panic!("While not yet implemented"); panic!("While not yet implemented");
} }
fn parse_sub(&self) -> Vec<Expression> { fn parse_sub(&mut self, end: usize) -> Vec<Expression> {
panic!("Sub not yet implemented") let mut expressions: Vec<Expression> = Vec::new();
loop {
if self.i >= end - 1 { break; }
expressions.push(self.get_expression(end));
dbg!(&expressions);
}
expressions
} }
fn get_value(&mut self) -> Value { fn get_value(&mut self, end: usize) -> 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 { continue; } if buf.len() == 0 { 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 }
}, },
Tokens::CommandEnd(_) => break, Tokens::CommandEnd(_) => break,
Tokens::Literal(str) => buf.push(Value::Literal(str.clone())), Tokens::Literal(str) => buf.push(Value::Literal(str.clone())),
@ -194,57 +295,155 @@ impl Tree {
Tokens::Function => buf.push(Value::Literal(token.to_str())), Tokens::Function => buf.push(Value::Literal(token.to_str())),
Tokens::FileWrite => buf.push(Value::Literal(token.to_str())), Tokens::FileWrite => buf.push(Value::Literal(token.to_str())),
Tokens::RedirectInto => panic!("Unexpected token REDIRECT (|)"), Tokens::RedirectInto => panic!("Unexpected token REDIRECT (|)"),
Tokens::FunctionCallEnd => panic!("Unexpected token FUNCTION CALL END ())"), Tokens::ParenthesisEnd => panic!("Unexpected token FUNCTION CALL END ())"),
Tokens::ArrayFunction(_) => panic!("Unexpected array function"), Tokens::ArrayFunction(_) => panic!("Unexpected array function"),
Tokens::StringFunction(_) => panic!("Unexpected string function"), Tokens::StringFunction(_) => panic!("Unexpected string function"),
Tokens::SubStart => /* SUB START PROCESS */, Tokens::ParenthesisStart => panic!("Parenthesis not yet implemented"),
Tokens::SubEnd => panic!("Unexpected token SUB END ())"), Tokens::SubStart => {
let mut len = 1;
let mut lvl = 1;
self.inc();
for token in &self.tokens[self.i..] {
match token {
Tokens::SubStart => lvl += 1,
Tokens::ParenthesisEnd => lvl -= 1,
_ => {}
}
if lvl == 0 {
break;
}
if len + self.i == end { break }
len += 1;
}
// self.inc();
dbg!(&self);
dbg!(len, lvl);
if lvl != 0 {
panic!("Sub not ended properly");
}
return Value::Expressions(self.parse_sub(self.i + len));
},
Tokens::Else => buf.push(Value::Literal(token.to_str())), Tokens::Else => buf.push(Value::Literal(token.to_str())),
Tokens::End => buf.push(Value::Literal(token.to_str())), Tokens::End => buf.push(Value::Literal(token.to_str())),
Tokens::For => return Expression::ForExpression(self.parse_for()), Tokens::For => buf.push(Value::Literal(token.to_str())),
Tokens::If => return Expression::IfExpression(self.parse_if()), Tokens::If => buf.push(Value::Literal(token.to_str())),
Tokens::Let => return Expression::LetExpression(self.parse_let()), Tokens::Let => buf.push(Value::Literal(token.to_str())),
Tokens::While => return Expression::WhileExpression(self.parse_while()), Tokens::While => buf.push(Value::Literal(token.to_str())),
Tokens::StringVariable(_, _) => return Expression::Command(self.parse_call()), Tokens::StringVariable(str, _) => {
Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable") if buf.len() != 0 {
values.push(Value::Values(buf));
buf = Vec::new();
}
values.push(Value::Variable(str.clone()));
},
Tokens::ArrayVariable(str, _) => {
if buf.len() != 0 {
values.push(Value::Values(buf));
buf = Vec::new();
}
values.push(Value::ArrayVariable(str.clone()));
},
Tokens::And => panic!("Unexpected AND (&&)"),
Tokens::Or => panic!("Unexpected OR (||)"),
Tokens::JobCommandEnd => panic!("Unexpected job command end (&)"),
} }
token = self.next(); if self.i >= end - 1 { break }
token = self.inc().get_current_token();
} }
if buf.len() > 0 {
values.push(Value::Values(buf));
}
Value::Values(values)
} }
fn get_expression(&mut self, is_sub: bool) -> Expression { fn get_expression(&mut self, end: usize) -> Expression {
let mut token = self.get_current_token(); let mut token = self.get_current_token();
dbg!("expr");
let mut expr: Option<Expression> = None;
loop { loop {
dbg!(&token);
match token { match token {
Tokens::Space => continue, Tokens::Space => {self.inc();},
Tokens::CommandEnd(_) => continue, Tokens::CommandEnd(_) => {self.inc();},
Tokens::Literal(_) => return Expression::Command(self.parse_call()), Tokens::Literal(t) => if matches!(expr, Some(_)) {
dbg!(t);
dbg!(expr);
panic!("Unexpected literal. After file redirect, you need to use a semicolon or newline.");
} else {
expr = Some(self.parse_call(end));
dbg!(&self);
},
Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"), Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"),
Tokens::FileRead => return Expression::FileSourceExpression(self.parse_read()), Tokens::Function => return Expression::Function(self.parse_function(end)),
Tokens::Function => return Expression::Function(self.parse_function()), Tokens::FileRead => expr = Some(self.parse_read(expr, end)),
Tokens::FileWrite => return Expression::FileTargetExpression(self.parse_write(None)), Tokens::FileWrite => expr = Some(self.parse_write(expr, end)),
Tokens::RedirectInto => panic!("Unexpected token REDIRECT (|)"), Tokens::RedirectInto => match expr {
Tokens::FunctionCallEnd => panic!("Unexpected token FUNCTION CALL END ())"), None => panic!("Unexpected token REDIRECT (|)"),
Some(_) => {
self.i += 1;
dbg!(&self);
expr = Some(Expression::RedirectTargetExpression(RedirectTargetExpression { source: Box::new(expr.unwrap()), target: Box::new(self.get_expression(end)) }));
dbg!("after redirect");
}
},
Tokens::ParenthesisStart => if matches!(expr, Some(_)) {
dbg!(expr);
panic!("Unexpected parenthesis. After file redirect, you need to use a semicolon or newline.");
} else {
let mut len = 1;
let mut lvl = 1;
self.inc();
for token in &self.tokens[self.i..] {
match token {
Tokens::ParenthesisStart => lvl += 1,
Tokens::ParenthesisEnd => lvl -= 1,
_ => {}
}
if lvl == 0 {
break;
}
if len + self.i == end { break }
len += 1;
}
if lvl != 0 {
panic!("Parenthesis not ended properly.");
}
expr = Some(self.get_expression(self.i + len));
dbg!(&self);
},
Tokens::ParenthesisEnd => panic!("Unexpected token PARENTHESIS END ())"),
Tokens::ArrayFunction(_) => panic!("Unexpected array function"), Tokens::ArrayFunction(_) => panic!("Unexpected array function"),
Tokens::StringFunction(_) => panic!("Unexpected string function"), Tokens::StringFunction(_) => panic!("Unexpected string function"),
Tokens::SubStart => return Expression::Command(self.parse_call()), Tokens::SubStart => return self.parse_call(end),
Tokens::SubEnd => if !is_sub { panic!("Unexpected token SUB END ())") },
Tokens::Else => panic!("Unexpected token ELSE"), Tokens::Else => panic!("Unexpected token ELSE"),
Tokens::End => panic!("Unexpected token END"), Tokens::End => panic!("Unexpected token END"),
Tokens::For => return Expression::ForExpression(self.parse_for()), Tokens::For => return Expression::ForExpression(self.parse_for(end)),
Tokens::If => return Expression::IfExpression(self.parse_if()), Tokens::If => return Expression::IfExpression(self.parse_if(end)),
Tokens::Let => return Expression::LetExpression(self.parse_let()), Tokens::Let => return self.parse_let(end),
Tokens::While => return Expression::WhileExpression(self.parse_while()), Tokens::While => return Expression::WhileExpression(self.parse_while(end)),
Tokens::StringVariable(_, _) => return Expression::Command(self.parse_call()), Tokens::StringVariable(_, _) => if matches!(expr, Some(_)) {
Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable") dbg!(expr);
panic!("Unexpected variable. After file redirect, you need to use a semicolon or newline.");
} else {
expr = Some(self.parse_call(end));
dbg!(&self);
},
Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable"),
Tokens::And => panic!("And not yet implemented"),
Tokens::Or => panic!("Or not yet implemented"),
Tokens::JobCommandEnd => panic!("Jobs not yet implemented")
} }
token = self.next(); if self.i >= end - 1 { break }
token = self.get_current_token();
} }
expr.unwrap()
} }
fn next(&mut self) -> &Tokens { fn inc(&mut self) -> &Self {
self.i += 1; self.i += 1;
self.get_current_token() self
} }
fn get_current_token(&self) -> &Tokens { fn get_current_token(&self) -> &Tokens {
self.tokens.get(self.i).unwrap() self.tokens.get(self.i).unwrap()
@ -255,12 +454,15 @@ impl Tree {
} }
pub fn build_tree(tokens: Vec<Tokens>) -> Vec<Expression> { pub fn build_tree(tokens: Vec<Tokens>) -> Vec<Expression> {
println!("Building tree");
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 {
if tree.i == tree.tokens.len() - 1 { break; } if tree.i == tree.tokens.len() - 1 { break; }
expressions.push(tree.get_expression()); let val = tree.get_expression(tree.tokens.len());
expressions.push(val);
} }
dbg!(&expressions);
expressions expressions
} }

View file

@ -2,19 +2,14 @@ pub mod vars;
pub mod ast; pub mod ast;
pub mod tokens; pub mod tokens;
use std::io; use crate::parser::ast::{build_tree};
use std::io::Read; use crate::parser::tokens::{tokenize};
//use std::io::prelude::*;
use utf8_chars::BufReadCharsExt;
use crate::parser::ast::{build_tree, Expression};
use crate::parser::tokens::{tokenize, Tokens};
pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) { pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) {
let tokens = tokenize(reader).unwrap(); let tokens = tokenize(reader).unwrap();
dbg!(&tokens); dbg!(&tokens);
println!("Building tree");
let expressions = build_tree(tokens); let expressions = build_tree(tokens);
dbg!(&expressions); dbg!(&expressions);

View file

@ -1,6 +1,4 @@
use std::fmt::format;
use std::io; use std::io;
use crate::parser::vars;
#[derive(Debug)] #[derive(Debug)]
pub enum Tokens { pub enum Tokens {
@ -12,7 +10,8 @@ pub enum Tokens {
ArrayVariable(String, bool), ArrayVariable(String, bool),
ArrayFunction(String), ArrayFunction(String),
StringFunction(String), StringFunction(String),
FunctionCallEnd, ParenthesisStart,
ParenthesisEnd,
CommandEnd(char), CommandEnd(char),
If, If,
Else, Else,
@ -21,10 +20,12 @@ pub enum Tokens {
Function, Function,
End, End,
SubStart, SubStart,
SubEnd,
RedirectInto, RedirectInto,
FileRead, FileRead,
FileWrite, FileWrite,
And,
Or,
JobCommandEnd
} }
impl Tokens { impl Tokens {
@ -38,7 +39,8 @@ impl Tokens {
"else" => Tokens::Else, "else" => Tokens::Else,
"end" => Tokens::End, "end" => Tokens::End,
"$(" => Tokens::SubStart, "$(" => Tokens::SubStart,
")" => Tokens::SubEnd, "(" => Tokens::ParenthesisStart,
")" => Tokens::ParenthesisEnd,
">" => Tokens::FileWrite, ">" => Tokens::FileWrite,
"<" => Tokens::FileRead, "<" => Tokens::FileRead,
"|" => Tokens::RedirectInto, "|" => Tokens::RedirectInto,
@ -59,7 +61,6 @@ impl Tokens {
Tokens::StringFunction(str) => format!("${}", str.as_str()), Tokens::StringFunction(str) => format!("${}", str.as_str()),
Tokens::CommandEnd(str) => str.to_string(), Tokens::CommandEnd(str) => str.to_string(),
Tokens::ExportSet => "=".to_string(), Tokens::ExportSet => "=".to_string(),
Tokens::FunctionCallEnd => ")".to_string(),
Tokens::Function => "function".to_string(), Tokens::Function => "function".to_string(),
Tokens::If => "if".to_string(), Tokens::If => "if".to_string(),
Tokens::Else => "else".to_string(), Tokens::Else => "else".to_string(),
@ -67,10 +68,14 @@ impl Tokens {
Tokens::For => "for".to_string(), Tokens::For => "for".to_string(),
Tokens::End => "end".to_string(), Tokens::End => "end".to_string(),
Tokens::SubStart => "$(".to_string(), Tokens::SubStart => "$(".to_string(),
Tokens::SubEnd => ")".to_string(), Tokens::ParenthesisStart => "(".to_string(),
Tokens::ParenthesisEnd => ")".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(),
Tokens::And => "&&".to_string(),
Tokens::Or => "||".to_string(),
Tokens::JobCommandEnd => "&".to_string()
} }
} }
} }
@ -84,7 +89,7 @@ fn read_var_ahead(i: usize, text: &String) -> (usize, Tokens) {
x += 1; x += 1;
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.clone());
} }
'}' => { '}' => {
@ -93,7 +98,7 @@ fn read_var_ahead(i: usize, text: &String) -> (usize, Tokens) {
} }
break; break;
} }
_ => { if !parens_mode { break } } _ => { if !parens_mode { break } else { panic!("Invalid variable name") } }
} }
} }
let token = match text.chars().nth(i).unwrap() { let token = match text.chars().nth(i).unwrap() {
@ -174,15 +179,23 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> io::Result<Vec<Tokens>> {
skipper = x - i - 1; skipper = x - i - 1;
buf_add = false; buf_add = false;
}, },
')' => if !quote_active && !double_quote_active { '(' => if !quote_active && !double_quote_active && !escape_active {
if buf.len() > 0 { if buf.len() > 0 {
tokens.push(Tokens::Literal(buf)); tokens.push(Tokens::Literal(buf));
buf = String::new(); buf = String::new();
} }
tokens.push(Tokens::FunctionCallEnd); tokens.push(Tokens::ParenthesisStart);
buf_add = false;
}
')' => if !quote_active && !double_quote_active && !escape_active {
if buf.len() > 0 {
tokens.push(Tokens::Literal(buf));
buf = String::new();
}
tokens.push(Tokens::ParenthesisEnd);
buf_add = false; buf_add = false;
}, },
'i' => if !quote_active && !double_quote_active { 'i' => if !quote_active && !double_quote_active && !escape_active {
if check_keyword(&text, i, "if") { if check_keyword(&text, i, "if") {
if buf.len() > 0 { if buf.len() > 0 {
tokens.push(Tokens::Literal(buf)); tokens.push(Tokens::Literal(buf));
@ -193,7 +206,7 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> io::Result<Vec<Tokens>> {
buf_add = false; buf_add = false;
} }
}, },
'e' => if !quote_active && !double_quote_active { 'e' => if !quote_active && !double_quote_active && !escape_active {
if check_keyword(&text, i, "else") { if check_keyword(&text, i, "else") {
if buf.len() > 0 { if buf.len() > 0 {
tokens.push(Tokens::Literal(buf)); tokens.push(Tokens::Literal(buf));
@ -212,7 +225,18 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> io::Result<Vec<Tokens>> {
buf_add = false; buf_add = false;
} }
}, },
'w' => if !quote_active && !double_quote_active { 'l' => if !quote_active && !double_quote_active && !escape_active {
if check_keyword(&text, i, "let") {
if buf.len() > 0 {
tokens.push(Tokens::Literal(buf));
buf = String::new();
}
skipper = 3;
tokens.push(Tokens::Let);
buf_add = false;
}
},
'w' => if !quote_active && !double_quote_active && !escape_active {
if check_keyword(&text, i, "while") { if check_keyword(&text, i, "while") {
if buf.len() > 0 { if buf.len() > 0 {
tokens.push(Tokens::Literal(buf)); tokens.push(Tokens::Literal(buf));
@ -223,7 +247,7 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> io::Result<Vec<Tokens>> {
buf_add = false; buf_add = false;
} }
}, },
'f' => if !quote_active && !double_quote_active { 'f' => if !quote_active && !double_quote_active && !escape_active {
if check_keyword(&text, i, "for") { if check_keyword(&text, i, "for") {
if buf.len() > 0 { if buf.len() > 0 {
tokens.push(Tokens::Literal(buf)); tokens.push(Tokens::Literal(buf));
@ -239,7 +263,25 @@ pub fn tokenize(reader: &mut dyn std::io::BufRead) -> io::Result<Vec<Tokens>> {
tokens.push(Tokens::Literal(buf)); tokens.push(Tokens::Literal(buf));
buf = String::new(); buf = String::new();
} }
tokens.push(Tokens::RedirectInto); if check_keyword(&text, i, "||") {
skipper = 1;
tokens.push(Tokens::Or);
} else {
tokens.push(Tokens::RedirectInto);
}
buf_add = false;
},
'&' => if !escape_active && !quote_active && !double_quote_active {
if buf.len() > 0 {
tokens.push(Tokens::Literal(buf));
buf = String::new();
}
if check_keyword(&text, i, "&&") {
skipper = 1;
tokens.push(Tokens::And);
} else {
tokens.push(Tokens::JobCommandEnd);
}
buf_add = false; buf_add = false;
}, },
'>' => if !escape_active && !quote_active && !double_quote_active { '>' => if !escape_active && !quote_active && !double_quote_active {

View file

@ -1,7 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Add, Deref};
use crate::parser::ast::FunctionDefinitionExpression; use crate::parser::ast::FunctionDefinitionExpression;
use crate::parser::escape;
#[derive(Debug)] #[derive(Debug)]
pub enum Variable { pub enum Variable {
@ -30,7 +28,7 @@ impl Variable {
Variable::U128(num) => num.to_string(), Variable::U128(num) => num.to_string(),
Variable::F32(num) => num.to_string(), Variable::F32(num) => num.to_string(),
Variable::F64(num) => num.to_string(), Variable::F64(num) => num.to_string(),
Variable::HMap(map) => { Variable::HMap(_map) => {
String::from("[Object object]") String::from("[Object object]")
}, },
Variable::Array(vars) => { Variable::Array(vars) => {