diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml
new file mode 100644
index 0000000..8fb785b
--- /dev/null
+++ b/.idea/git_toolbox_prj.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 8332f5d..7fed5f5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -14,6 +14,17 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+[[package]]
+name = "filedescriptor"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed3d8a5e20435ff00469e51a0d82049bae66504b5c429920dadf9bb54d47b3f"
+dependencies = [
+ "libc",
+ "thiserror",
+ "winapi",
+]
+
[[package]]
name = "libc"
version = "0.2.107"
@@ -26,6 +37,24 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
+[[package]]
+name = "proc-macro2"
+version = "1.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+dependencies = [
+ "proc-macro2",
+]
+
[[package]]
name = "redox_syscall"
version = "0.2.10"
@@ -48,10 +77,22 @@ dependencies = [
name = "rush"
version = "0.1.0"
dependencies = [
+ "filedescriptor",
"termion",
"utf8-chars",
]
+[[package]]
+name = "syn"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
[[package]]
name = "termion"
version = "1.5.6"
@@ -64,6 +105,32 @@ dependencies = [
"redox_termios",
]
+[[package]]
+name = "thiserror"
+version = "1.0.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
[[package]]
name = "utf8-chars"
version = "1.0.2"
@@ -72,3 +139,25 @@ checksum = "c1348d8face79d019be7cbc0198e36bf93e160ddbfaa7bb54c9592627b9ec841"
dependencies = [
"arrayvec",
]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index 576cd1f..9df853f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,4 +8,5 @@ edition = "2018"
[dependencies]
utf8-chars = "1.0.0"
-termion = "1.5.6"
\ No newline at end of file
+termion = "1.5.6"
+filedescriptor = "0.8.1"
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 4e43920..8624fe9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,8 @@
mod parser;
-use std::io::{self, Read, Stdout, Write};
+use std::io::{self, BufRead, Read, Stdout, Write};
use std::cmp;
+use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::Add;
use std::process;
@@ -62,7 +63,8 @@ impl Shell {
term: Term::new(),
ctx: parser::vars::Context {
scopes: Vec::new(),
- parent_context: None,
+ fd: Vec::new(),
+ exports: HashMap::new()
},
};
}
@@ -70,17 +72,24 @@ impl Shell {
fn main() {
loop {
- let mut shell = editor();
+ let mut shell = collect();
shell.term.input += "\n";
parser::exec(&mut shell.term.input.as_bytes(), shell.ctx);
}
}
+fn collect() -> Shell {
+ let mut shell = Shell::new();
+ let stdin = std::io::stdin();
+ let v = stdin.lock().lines().next().unwrap().unwrap();
+ shell.term.input = v;
+ shell
+}
+
fn editor() -> Shell {
let stdin = io::stdin();
let mut stdout = io::stdout().into_raw_mode().unwrap();
let mut shell = Shell::new();
- let mut should_execute = true;
for c in stdin.keys() {
let c = c.unwrap();
match c {
@@ -134,6 +143,6 @@ fn editor() -> Shell {
shell.term.print(&mut stdout);
stdout.flush().unwrap();
}
- stdout.suspend_raw_mode();
+ stdout.suspend_raw_mode().unwrap();
shell
}
diff --git a/src/parser/ast.rs b/src/parser/ast.rs
index ff22cac..c07bf4c 100644
--- a/src/parser/ast.rs
+++ b/src/parser/ast.rs
@@ -1,59 +1,266 @@
+use crate::parser::tokens::Tokens;
use crate::parser::vars::Variable;
#[derive(Debug)]
pub struct LetExpression {
pub key: String,
- pub value: Value
+ pub value: Box
}
#[derive(Debug)]
pub struct IfExpression {
- pub condition: Expression,
+ pub condition: Box,
pub contents: Vec
}
#[derive(Debug)]
pub struct WhileExpression {
- pub condition: Expression,
+ pub condition: Box,
pub contents: Vec
}
#[derive(Debug)]
pub struct ForExpression {
pub key: String,
- pub list: Value,
+ pub list: Box,
pub contents: Vec
}
#[derive(Debug)]
pub enum ForValue {
Value(Value),
- Range(Some(u32), Some(u32))
+ Range(Option, Option)
+}
+
+#[derive(Debug)]
+pub struct DefinedFunction {
+ name: String,
+ args: Vec,
+ body: Vec
}
#[derive(Debug)]
pub enum Value {
Literal(String),
- Variable(Variable),
- Expression(Expression)
+ Variable(String),
+ ArrayVariable(String),
+ ArrayFunction(DefinedFunction),
+ StringFunction(DefinedFunction),
+ Expressions(Vec),
+ Values(Vec)
}
#[derive(Debug)]
-pub struct FunctionExpression {
- pub args: Vec,
- pub body: Expression
+pub struct FunctionDefinitionExpression {
+ pub args: Vec,
+ pub body: Box
}
+#[derive(Debug)]
pub struct RedirectTargetExpression {
+ pub source: Box,
+ pub target: Box
+}
+#[derive(Debug)]
+pub struct FileTargetExpression {
+ pub source: Option>,
+ pub target: Box
+}
+
+#[derive(Debug)]
+pub struct FileSourceExpression {
+ pub source: Box,
+ pub target: Option>
+}
+
+#[derive(Debug)]
+pub enum CommandValue {
+ Value(Value),
+ Var(String, Value)
}
#[derive(Debug)]
pub enum Expression {
LetExpression(LetExpression),
- Command(Vec),
- Function(FunctionExpression),
+ Command(Vec),
+ Function(FunctionDefinitionExpression),
IfExpression(IfExpression),
WhileExpression(WhileExpression),
- ForExpression(ForExpression)
+ ForExpression(ForExpression),
+ RedirectTargetExpression(RedirectTargetExpression),
+ FileTargetExpression(FileTargetExpression),
+ FileSourceExpression(FileSourceExpression)
+}
+
+struct Tree {
+ tokens: Vec,
+ i: usize
+}
+
+impl Tree {
+ fn parse_call(&mut self) -> Vec {
+ let mut values: Vec = Vec::new();
+ let mut token = self.get_current_token();
+ let mut buf: Vec = Vec::new();
+
+ loop {
+ if matches!(token, Tokens::Space) {
+ if buf.len() > 0 {
+ values.push(CommandValue::Value(Value::Values(buf)));
+ buf = Vec::new();
+ }
+ token = self.next();
+ continue;
+ }
+ let val = match token {
+ Tokens::Literal(str) => Value::Literal(str.clone()),
+ Tokens::SubStart => Value::Expressions(self.parse_sub()),
+ Tokens::StringVariable(str, _) => Value::Variable(str.clone()),
+ Tokens::ArrayVariable(str, _) => Value::ArrayVariable(str.clone()),
+ Tokens::FileWrite => {
+
+ }
+ _ => {
+ Value::Literal(token.to_str())
+ }
+ };
+ buf.push(val);
+ if self.i == self.tokens.len() { break }
+ token = self.next();
+ if matches!(token, Tokens::CommandEnd(_)) { break }
+ }
+ if buf.len() > 0 {
+ values.push(CommandValue::Value(Value::Values(buf)));
+ }
+ values
+ }
+
+ fn parse_let(&self) -> LetExpression {
+ panic!("Let not yet implemented");
+ }
+
+ fn parse_read(&self) -> FileSourceExpression {
+ panic!("Read not yet implemented");
+ }
+
+ fn parse_write(&self, source: Option) -> FileTargetExpression {
+ let source = match source {
+ Some(source) => Some(Box::new(source)),
+ None => None
+ };
+
+ }
+
+ fn parse_function(&self) -> FunctionDefinitionExpression {
+ panic!("Functions not yet implemented")
+ }
+
+ fn parse_array_func(&self, str: String) -> DefinedFunction {
+ panic!("Array functions not yet implemented");
+ }
+
+ fn parse_for(&self) -> ForExpression {
+ panic!("For loop not yet implemented");
+ }
+
+ fn parse_if(&self) -> IfExpression {
+ panic!("If not yet implemented");
+ }
+
+ fn parse_while(&self) -> WhileExpression {
+ panic!("While not yet implemented");
+ }
+
+ fn parse_sub(&self) -> Vec {
+ panic!("Sub not yet implemented")
+ }
+
+ fn get_value(&mut self) -> Value {
+ 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 { continue; }
+ values.push(Value::Values(buf));
+ buf = Vec::new();
+ },
+ Tokens::CommandEnd(_) => break,
+ Tokens::Literal(str) => buf.push(Value::Literal(str.clone())),
+ Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"),
+ Tokens::FileRead => 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::RedirectInto => panic!("Unexpected token REDIRECT (|)"),
+ Tokens::FunctionCallEnd => panic!("Unexpected token FUNCTION CALL END ())"),
+ Tokens::ArrayFunction(_) => panic!("Unexpected array function"),
+ Tokens::StringFunction(_) => panic!("Unexpected string function"),
+ Tokens::SubStart => /* SUB START PROCESS */,
+ Tokens::SubEnd => panic!("Unexpected token SUB END ())"),
+ Tokens::Else => 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::If => return Expression::IfExpression(self.parse_if()),
+ Tokens::Let => return Expression::LetExpression(self.parse_let()),
+ Tokens::While => return Expression::WhileExpression(self.parse_while()),
+ Tokens::StringVariable(_, _) => return Expression::Command(self.parse_call()),
+ Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable")
+ }
+ token = self.next();
+ }
+ }
+
+ fn get_expression(&mut self, is_sub: bool) -> Expression {
+ let mut token = self.get_current_token();
+ loop {
+ match token {
+ Tokens::Space => continue,
+ Tokens::CommandEnd(_) => continue,
+ Tokens::Literal(_) => return Expression::Command(self.parse_call()),
+ Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"),
+ Tokens::FileRead => return Expression::FileSourceExpression(self.parse_read()),
+ Tokens::Function => return Expression::Function(self.parse_function()),
+ Tokens::FileWrite => return Expression::FileTargetExpression(self.parse_write(None)),
+ Tokens::RedirectInto => panic!("Unexpected token REDIRECT (|)"),
+ Tokens::FunctionCallEnd => panic!("Unexpected token FUNCTION CALL END ())"),
+ Tokens::ArrayFunction(_) => panic!("Unexpected array function"),
+ Tokens::StringFunction(_) => panic!("Unexpected string function"),
+ Tokens::SubStart => return Expression::Command(self.parse_call()),
+ Tokens::SubEnd => if !is_sub { panic!("Unexpected token SUB END ())") },
+ Tokens::Else => panic!("Unexpected token ELSE"),
+ Tokens::End => panic!("Unexpected token END"),
+ Tokens::For => return Expression::ForExpression(self.parse_for()),
+ Tokens::If => return Expression::IfExpression(self.parse_if()),
+ Tokens::Let => return Expression::LetExpression(self.parse_let()),
+ Tokens::While => return Expression::WhileExpression(self.parse_while()),
+ Tokens::StringVariable(_, _) => return Expression::Command(self.parse_call()),
+ Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable")
+ }
+ token = self.next();
+ }
+ }
+
+ fn next(&mut self) -> &Tokens {
+ self.i += 1;
+ self.get_current_token()
+ }
+ fn get_current_token(&self) -> &Tokens {
+ self.tokens.get(self.i).unwrap()
+ }
+ fn get_next_token(&self) -> &Tokens {
+ self.tokens.get(self.i + 1).unwrap()
+ }
+}
+
+pub fn build_tree(tokens: Vec) -> Vec {
+ let mut expressions: Vec = Vec::new();
+ let mut tree = Tree { tokens, i: 0 };
+ loop {
+ if tree.i == tree.tokens.len() - 1 { break; }
+ expressions.push(tree.get_expression());
+ }
+
+ expressions
}
\ No newline at end of file
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 2bd790c..a1f8df1 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -1,94 +1,23 @@
pub mod vars;
pub mod ast;
+pub mod tokens;
use std::io;
+use std::io::Read;
//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) -> io::Result<()> {
- println!("got result");
- let mut word = String::new();
- let mut if_active = false;
- let mut quote_active = false;
- let mut double_quote_active = false;
- let mut var_active = false;
- let mut var_parens_active = false;
- let mut command = String::new();
- let mut args: Vec = Vec::new();
- let mut var_name = String::new();
- let mut prev_char: Option = None;
+pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) {
+ let tokens = tokenize(reader).unwrap();
- for c in reader.chars().map(|x| x.unwrap()) {
- print!("{}\r", c);
- // loop runs once, allows early exit
- loop {
- match c {
- '$' => {
- if quote_active {
- word.push('$');
- }
- var_active = true;
- }
- '{' => {
- if var_active {
- var_parens_active = true;
- } else {
- word.push('{');
- }
- }
- '}' => {
- if !var_parens_active {
- word.push('}');
- }
- }
- ' ' => {
- if quote_active || double_quote_active {
- word.push(' ');
- break;
- }
- if var_parens_active { break; }
- if var_active {}
- if command.len() == 0 {
- if word == "if" {
- if_active = true;
- } else if word == "end" {
- ctx.pop_scope();
- } else {
- command = word;
- word = String::new();
- }
- } else {
- args.push(word.clone());
- word = String::new();
- }
- }
- ';' | '\n' => {
- let mut arg_strings: Vec<&str> = Vec::new();
- for arg in &args {
- arg_strings.push(&*arg);
- }
- println!("Will execute {} with {}", command, arg_strings.join(" "));
- if if_active {
- println!("Will execute below only if the previous command succeeded");
- }
- if_active = false;
+ dbg!(&tokens);
- let exit_code = 0;
- ctx.add_scope(exit_code == 0);
- }
- char => {
- if var_active {
- var_name.push(char);
- } else {
- word.push(char);
- }
- }
- };
- break;
- }
- prev_char = Some(c);
- }
- Ok(())
+ println!("Building tree");
+ let expressions = build_tree(tokens);
+
+ dbg!(&expressions);
}
pub fn escape(str: String) -> String {
diff --git a/src/parser/tokens.rs b/src/parser/tokens.rs
new file mode 100644
index 0000000..22f9bbf
--- /dev/null
+++ b/src/parser/tokens.rs
@@ -0,0 +1,295 @@
+use std::fmt::format;
+use std::io;
+use crate::parser::vars;
+
+#[derive(Debug)]
+pub enum Tokens {
+ Space,
+ Literal(String),
+ Let,
+ ExportSet,
+ StringVariable(String, bool),
+ ArrayVariable(String, bool),
+ ArrayFunction(String),
+ StringFunction(String),
+ FunctionCallEnd,
+ CommandEnd(char),
+ If,
+ Else,
+ While,
+ For,
+ Function,
+ End,
+ SubStart,
+ SubEnd,
+ RedirectInto,
+ FileRead,
+ FileWrite,
+}
+
+impl Tokens {
+ fn detect(str: String) -> Tokens {
+ match str.as_str() {
+ "if" => Tokens::If,
+ "while" => Tokens::While,
+ "for" => Tokens::For,
+ "let" => Tokens::Let,
+ " " => Tokens::Space,
+ "else" => Tokens::Else,
+ "end" => Tokens::End,
+ "$(" => Tokens::SubStart,
+ ")" => Tokens::SubEnd,
+ ">" => Tokens::FileWrite,
+ "<" => Tokens::FileRead,
+ "|" => Tokens::RedirectInto,
+ "\n" | ";" => Tokens::CommandEnd(str.chars().nth(0).unwrap()),
+ "=" => Tokens::ExportSet,
+ _ => Tokens::Literal(str)
+ }
+ }
+
+ pub(crate) fn to_str(&self) -> String {
+ match self {
+ Tokens::Space => " ".to_string(),
+ Tokens::Literal(str) => str.clone(),
+ Tokens::Let => "let".to_string(),
+ Tokens::StringVariable(str, bool) => format!("${}{}{}", match bool { true => "{", false => ""}, str.as_str(), match bool { true => "{", false => "" }),
+ Tokens::ArrayVariable(str, bool) => format!("@{}{}{}", match bool { true => "{", false => ""}, str.as_str(), match bool { true => "{", false => "" }),
+ Tokens::ArrayFunction(str) => format!("@{}", str.as_str()),
+ Tokens::StringFunction(str) => format!("${}", str.as_str()),
+ Tokens::CommandEnd(str) => str.to_string(),
+ Tokens::ExportSet => "=".to_string(),
+ Tokens::FunctionCallEnd => ")".to_string(),
+ Tokens::Function => "function".to_string(),
+ Tokens::If => "if".to_string(),
+ Tokens::Else => "else".to_string(),
+ Tokens::While => "while".to_string(),
+ Tokens::For => "for".to_string(),
+ Tokens::End => "end".to_string(),
+ Tokens::SubStart => "$(".to_string(),
+ Tokens::SubEnd => ")".to_string(),
+ Tokens::RedirectInto => "|".to_string(),
+ Tokens::FileRead => "<".to_string(),
+ Tokens::FileWrite => ">".to_string()
+ }
+ }
+}
+
+
+fn read_var_ahead(i: usize, text: &String) -> (usize, Tokens) {
+ let mut x = i;
+ let mut buf = String::new();
+ let parens_mode = text.chars().nth(x + 1).unwrap() == '{';
+ loop {
+ x += 1;
+ let letter: char = text.chars().nth(x).unwrap();
+ match letter {
+ 'a'...'z' | 'A'...'Z' | '0'...'9' | ':' => {
+ buf.push(letter.clone());
+ }
+ '}' => {
+ if parens_mode {
+ x += 1;
+ }
+ break;
+ }
+ _ => { if !parens_mode { break } }
+ }
+ }
+ let token = match text.chars().nth(i).unwrap() {
+ '$' => Tokens::StringVariable(buf, parens_mode),
+ '@' => Tokens::ArrayVariable(buf, parens_mode),
+ a => panic!("Invalid value {}", a)
+ };
+ (x - i - 1, token)
+}
+
+fn check_keyword(text: &String, i: usize, keyword: &str) -> bool {
+ let text_length = text.len();
+ if text_length < i + keyword.len() + 1 { return false; }
+ text.chars().skip(i).take(keyword.len()).collect::() == keyword
+}
+
+pub fn tokenize(reader: &mut dyn std::io::BufRead) -> io::Result> {
+ let mut quote_active = false;
+ let mut double_quote_active = false;
+ let mut escape_active = false;
+ let mut text = String::new();
+ reader.read_to_string(&mut text);
+ let mut text_length = text.len();
+
+ let mut tokens: Vec = Vec::new();
+
+ let mut buf = String::new();
+ let mut skipper = 0;
+ for i in 0..text_length {
+ if skipper > 0 {
+ skipper -= 1;
+ continue;
+ }
+ let letter: &char = &text.chars().nth(i).unwrap();
+ let mut buf_add = true;
+ 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 buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ if text_length > i && text.chars().nth(i + 1).unwrap() == '(' {
+ tokens.push(Tokens::SubStart);
+ skipper = 1;
+ buf_add = false;
+ } else {
+ let (skippers, mut token) = read_var_ahead(i, &text);
+ match token {
+ Tokens::StringVariable(ref str, bool) => if !bool && !double_quote_active {
+ if text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
+ token = Tokens::StringFunction(str.clone());
+ }
+ },
+ Tokens::ArrayVariable(ref str, bool) => if !bool && !double_quote_active {
+ if text.len() > i + skippers && text.chars().nth(i + skippers).unwrap() == '(' {
+ token = Tokens::ArrayFunction(str.clone());
+ }
+ }
+ _ => panic!("Cannot happen")
+ }
+ tokens.push(token);
+ skipper = skippers;
+ buf_add = false;
+ }
+ },
+ ' ' => if !escape_active && !quote_active && !double_quote_active {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ tokens.push(Tokens::Space);
+ let mut x = i;
+ while text.chars().nth(x).unwrap() == ' ' {
+ x += 1;
+ }
+ skipper = x - i - 1;
+ buf_add = false;
+ },
+ ')' => if !quote_active && !double_quote_active {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ tokens.push(Tokens::FunctionCallEnd);
+ buf_add = false;
+ },
+ 'i' => if !quote_active && !double_quote_active {
+ if check_keyword(&text, i, "if") {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ skipper = 2;
+ tokens.push(Tokens::If);
+ buf_add = false;
+ }
+ },
+ 'e' => if !quote_active && !double_quote_active {
+ if check_keyword(&text, i, "else") {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ skipper = 4;
+ tokens.push(Tokens::Else);
+ buf_add = false;
+ } else if check_keyword(&text, i , "end") {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ skipper = 3;
+ tokens.push(Tokens::End);
+ buf_add = false;
+ }
+ },
+ 'w' => if !quote_active && !double_quote_active {
+ if check_keyword(&text, i, "while") {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ skipper = 5;
+ tokens.push(Tokens::While);
+ buf_add = false;
+ }
+ },
+ 'f' => if !quote_active && !double_quote_active {
+ if check_keyword(&text, i, "for") {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ skipper = 3;
+ tokens.push(Tokens::If);
+ buf_add = false;
+ }
+ },
+ '|' => if !escape_active && !quote_active && !double_quote_active {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ 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();
+ }
+ tokens.push(Tokens::FileWrite);
+ buf_add = false;
+ },
+ '<' => if !escape_active && !quote_active && !double_quote_active {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ tokens.push(Tokens::FileRead);
+ buf_add = false;
+ },
+ ';' | '\n' => if !escape_active && !quote_active && !double_quote_active {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ tokens.push(Tokens::CommandEnd(letter.clone()));
+ buf_add = false;
+ },
+ '\\' => if !escape_active {
+ escape_active = true;
+ buf_add = false;
+ } else {
+ escape_active = false;
+ },
+ '=' => if !escape_active && !quote_active && !double_quote_active {
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ buf = String::new();
+ }
+ tokens.push(Tokens::ExportSet);
+ buf_add = false;
+ },
+ _ => {}
+ }
+ if letter.clone() != '\\' { escape_active = false; }
+ if buf_add {
+ buf.push(*letter);
+ }
+ }
+ if buf.len() > 0 {
+ tokens.push(Tokens::Literal(buf));
+ }
+
+ Ok(tokens)
+}
\ No newline at end of file
diff --git a/src/parser/vars.rs b/src/parser/vars.rs
index 7d9b95a..236dc81 100644
--- a/src/parser/vars.rs
+++ b/src/parser/vars.rs
@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::ops::{Add, Deref};
-use crate::parser::ast::FunctionExpression;
+use crate::parser::ast::FunctionDefinitionExpression;
use crate::parser::escape;
#[derive(Debug)]
@@ -55,19 +55,22 @@ impl Variable {
pub struct Scope {
pub active: bool,
pub vars: HashMap,
- pub func: HashMap
+ pub func: HashMap
}
#[derive(Debug)]
pub struct Context {
pub scopes: Vec,
- pub exports: HashMap
+ pub exports: HashMap,
+ pub fd: Vec
}
impl Context {
pub fn new() -> Context {
Context {
- scopes: Vec::new()
+ scopes: Vec::new(),
+ exports: HashMap::new(),
+ fd: Vec::new()
}
}
pub fn pop_scope(self: &mut Self) -> Option {
@@ -100,4 +103,23 @@ impl Context {
let mut 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;
+ let val = funcs.get_mut(key);
+ match val {
+ None => {},
+ Some(val) => {
+ return Some(val);
+ }
+ }
+ }
+ None
+ }
+
+ pub fn set_func(&mut self, key: String, val: FunctionDefinitionExpression) {
+ let mut func = &mut self.scopes.last_mut().unwrap().func;
+ func.insert(key, val);
+ }
}
\ No newline at end of file