mirror of
https://github.com/danbulant/rush
synced 2026-05-24 12:35:38 +00:00
feat: working executing simple commands
This commit is contained in:
parent
847e49ec92
commit
bd72bdb17f
5 changed files with 198 additions and 48 deletions
26
src/main.rs
26
src/main.rs
|
|
@ -67,24 +67,24 @@ impl Shell {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn collect(&mut self) {
|
||||||
loop {
|
let stdin = std::io::stdin();
|
||||||
print!("$: ");
|
let v = stdin.lock().lines().next().unwrap().unwrap();
|
||||||
io::stdout().flush();
|
self.term.input = v;
|
||||||
let mut shell = collect();
|
|
||||||
shell.term.input += "\n";
|
|
||||||
parser::exec(&mut shell.term.input.as_bytes(), shell.ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect() -> Shell {
|
fn main() {
|
||||||
let mut shell = Shell::new();
|
let mut shell = Shell::new();
|
||||||
let stdin = std::io::stdin();
|
shell.ctx.add_scope(true);
|
||||||
let v = stdin.lock().lines().next().unwrap().unwrap();
|
loop {
|
||||||
shell.term.input = v;
|
print!("$: ");
|
||||||
shell
|
io::stdout().flush();
|
||||||
|
shell.collect();
|
||||||
|
shell.term.input += "\n";
|
||||||
|
parser::exec(&mut shell.term.input.as_bytes(), &mut shell.ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor() -> Shell {
|
fn editor() -> Shell {
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ 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>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +118,6 @@ impl Tree {
|
||||||
fn parse_call(&mut self, end: usize) -> Expression {
|
fn parse_call(&mut self, end: usize) -> Expression {
|
||||||
let mut values: Vec<CommandValue> = Vec::new();
|
let mut values: Vec<CommandValue> = Vec::new();
|
||||||
let mut buf: Vec<Value> = Vec::new();
|
let mut buf: Vec<Value> = Vec::new();
|
||||||
dbg!("call parse");
|
|
||||||
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) {
|
||||||
|
|
@ -130,7 +128,6 @@ impl Tree {
|
||||||
if self.i >= end - 1 { break }
|
if self.i >= end - 1 { break }
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
token = self.get_current_token();
|
token = self.get_current_token();
|
||||||
dbg!("skip space");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let val = match &token {
|
let val = match &token {
|
||||||
|
|
@ -145,6 +142,9 @@ impl Tree {
|
||||||
Tokens::FileWrite => break,
|
Tokens::FileWrite => break,
|
||||||
Tokens::FileRead => break,
|
Tokens::FileRead => break,
|
||||||
Tokens::RedirectInto => break,
|
Tokens::RedirectInto => break,
|
||||||
|
Tokens::And => break,
|
||||||
|
Tokens::Or => break,
|
||||||
|
Tokens::JobCommandEnd => break,
|
||||||
Tokens::ParenthesisEnd => {
|
Tokens::ParenthesisEnd => {
|
||||||
if self.i >= end - 1 {
|
if self.i >= end - 1 {
|
||||||
break;
|
break;
|
||||||
|
|
@ -160,14 +160,11 @@ impl Tree {
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
token = self.tokens.get(self.i).unwrap();
|
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 {
|
match &token {
|
||||||
Tokens::FileWrite | Tokens::FileRead | Tokens::RedirectInto => self.i -= 1,
|
Tokens::FileWrite | Tokens::FileRead | Tokens::RedirectInto => self.i -= 1,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
dbg!(&self);
|
|
||||||
// self.next();
|
// self.next();
|
||||||
if buf.len() > 0 {
|
if buf.len() > 0 {
|
||||||
values.push(CommandValue::Value(Value::Values(buf)));
|
values.push(CommandValue::Value(Value::Values(buf)));
|
||||||
|
|
@ -201,7 +198,6 @@ impl Tree {
|
||||||
let mut val_end = self.i;
|
let mut val_end = self.i;
|
||||||
let mut found_first = false;
|
let mut found_first = false;
|
||||||
for token in &self.tokens[self.i..] {
|
for token in &self.tokens[self.i..] {
|
||||||
dbg!(&token);
|
|
||||||
val_end += 1;
|
val_end += 1;
|
||||||
match token {
|
match token {
|
||||||
Tokens::Space => if found_first { break },
|
Tokens::Space => if found_first { break },
|
||||||
|
|
@ -211,7 +207,6 @@ impl Tree {
|
||||||
_ => { found_first = true; }
|
_ => { found_first = true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbg!(&self.tokens[self.i..val_end]);
|
|
||||||
val_end -= 1;
|
val_end -= 1;
|
||||||
let source = Box::new(self.get_value(val_end));
|
let source = Box::new(self.get_value(val_end));
|
||||||
self.inc();
|
self.inc();
|
||||||
|
|
@ -271,7 +266,6 @@ impl Tree {
|
||||||
loop {
|
loop {
|
||||||
if self.i >= end - 1 { break; }
|
if self.i >= end - 1 { break; }
|
||||||
expressions.push(self.get_expression(end));
|
expressions.push(self.get_expression(end));
|
||||||
dbg!(&expressions);
|
|
||||||
}
|
}
|
||||||
expressions
|
expressions
|
||||||
}
|
}
|
||||||
|
|
@ -317,8 +311,6 @@ impl Tree {
|
||||||
len += 1;
|
len += 1;
|
||||||
}
|
}
|
||||||
// self.inc();
|
// self.inc();
|
||||||
dbg!(&self);
|
|
||||||
dbg!(len, lvl);
|
|
||||||
if lvl != 0 {
|
if lvl != 0 {
|
||||||
panic!("Sub not ended properly");
|
panic!("Sub not ended properly");
|
||||||
}
|
}
|
||||||
|
|
@ -359,20 +351,15 @@ impl Tree {
|
||||||
|
|
||||||
fn get_expression(&mut self, end: usize) -> 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;
|
let mut expr: Option<Expression> = None;
|
||||||
loop {
|
loop {
|
||||||
dbg!(&token);
|
|
||||||
match token {
|
match token {
|
||||||
Tokens::Space => {self.inc();},
|
Tokens::Space => {self.inc();},
|
||||||
Tokens::CommandEnd(_) => {self.inc();},
|
Tokens::CommandEnd(_) => { if matches!(expr, Some(_)) { break }; self.inc();},
|
||||||
Tokens::Literal(t) => if matches!(expr, Some(_)) {
|
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.");
|
panic!("Unexpected literal. After file redirect, you need to use a semicolon or newline.");
|
||||||
} else {
|
} else {
|
||||||
expr = Some(self.parse_call(end));
|
expr = Some(self.parse_call(end));
|
||||||
dbg!(&self);
|
|
||||||
},
|
},
|
||||||
Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"),
|
Tokens::ExportSet => panic!("Unexpected token EXPORT_SET (=)"),
|
||||||
Tokens::Function => return Expression::Function(self.parse_function(end)),
|
Tokens::Function => return Expression::Function(self.parse_function(end)),
|
||||||
|
|
@ -382,13 +369,10 @@ impl Tree {
|
||||||
None => panic!("Unexpected token REDIRECT (|)"),
|
None => panic!("Unexpected token REDIRECT (|)"),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
self.i += 1;
|
self.i += 1;
|
||||||
dbg!(&self);
|
|
||||||
expr = Some(Expression::RedirectTargetExpression(RedirectTargetExpression { source: Box::new(expr.unwrap()), target: Box::new(self.get_expression(end)) }));
|
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(_)) {
|
Tokens::ParenthesisStart => if matches!(expr, Some(_)) {
|
||||||
dbg!(expr);
|
|
||||||
panic!("Unexpected parenthesis. After file redirect, you need to use a semicolon or newline.");
|
panic!("Unexpected parenthesis. After file redirect, you need to use a semicolon or newline.");
|
||||||
} else {
|
} else {
|
||||||
let mut len = 1;
|
let mut len = 1;
|
||||||
|
|
@ -411,28 +395,48 @@ impl Tree {
|
||||||
panic!("Parenthesis not ended properly.");
|
panic!("Parenthesis not ended properly.");
|
||||||
}
|
}
|
||||||
expr = Some(self.get_expression(self.i + len));
|
expr = Some(self.get_expression(self.i + len));
|
||||||
dbg!(&self);
|
self.inc();
|
||||||
},
|
},
|
||||||
Tokens::ParenthesisEnd => panic!("Unexpected token PARENTHESIS END ())"),
|
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 self.parse_call(end),
|
Tokens::SubStart => if matches!(expr, Some(_)) {
|
||||||
|
panic!("Unexpected literal. After file redirect, you need to use a semicolon or newline.");
|
||||||
|
} else {
|
||||||
|
expr = Some(self.parse_call(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(end)),
|
Tokens::For => match expr {
|
||||||
Tokens::If => return Expression::IfExpression(self.parse_if(end)),
|
Some(_) => panic!("Commands must be ended properly"),
|
||||||
|
None => expr = Some(Expression::ForExpression(self.parse_for(end))),
|
||||||
|
},
|
||||||
|
Tokens::If => match expr {
|
||||||
|
Some(_) => panic!("Commands must be ended properly"),
|
||||||
|
None => expr = Some(Expression::IfExpression(self.parse_if(end))),
|
||||||
|
}
|
||||||
Tokens::Let => return self.parse_let(end),
|
Tokens::Let => return self.parse_let(end),
|
||||||
Tokens::While => return Expression::WhileExpression(self.parse_while(end)),
|
Tokens::While => return Expression::WhileExpression(self.parse_while(end)),
|
||||||
Tokens::StringVariable(_, _) => if matches!(expr, Some(_)) {
|
Tokens::StringVariable(_, _) => if matches!(expr, Some(_)) {
|
||||||
dbg!(expr);
|
|
||||||
panic!("Unexpected variable. After file redirect, you need to use a semicolon or newline.");
|
panic!("Unexpected variable. After file redirect, you need to use a semicolon or newline.");
|
||||||
} else {
|
} else {
|
||||||
expr = Some(self.parse_call(end));
|
expr = Some(self.parse_call(end));
|
||||||
dbg!(&self);
|
|
||||||
},
|
},
|
||||||
Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable"),
|
Tokens::ArrayVariable(_, _) => panic!("Unexpected array variable"),
|
||||||
Tokens::And => panic!("And not yet implemented"),
|
Tokens::And => match expr {
|
||||||
Tokens::Or => panic!("Or not yet implemented"),
|
None => panic!("Unexpected AND (&&)"),
|
||||||
|
Some(_) => {
|
||||||
|
self.inc();
|
||||||
|
expr = Some(Expression::AndExpression(AndExpression { first: Box::new(expr.unwrap()), second: Box::new(self.get_expression(end)) }));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Tokens::Or => match expr {
|
||||||
|
None => panic!("Unexpected OR (||)"),
|
||||||
|
Some(_) => {
|
||||||
|
self.inc();
|
||||||
|
expr = Some(Expression::OrExpression(OrExpression { first: Box::new(expr.unwrap()), second: Box::new(self.get_expression(end)) }));
|
||||||
|
}
|
||||||
|
},
|
||||||
Tokens::JobCommandEnd => panic!("Jobs not yet implemented")
|
Tokens::JobCommandEnd => panic!("Jobs not yet implemented")
|
||||||
}
|
}
|
||||||
if self.i >= end - 1 { break }
|
if self.i >= end - 1 { break }
|
||||||
|
|
@ -454,7 +458,6 @@ 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 {
|
||||||
|
|
@ -462,7 +465,5 @@ pub fn build_tree(tokens: Vec<Tokens>) -> Vec<Expression> {
|
||||||
let val = tree.get_expression(tree.tokens.len());
|
let val = tree.get_expression(tree.tokens.len());
|
||||||
expressions.push(val);
|
expressions.push(val);
|
||||||
}
|
}
|
||||||
dbg!(&expressions);
|
|
||||||
|
|
||||||
expressions
|
expressions
|
||||||
}
|
}
|
||||||
|
|
|
||||||
137
src/parser/exec.rs
Normal file
137
src/parser/exec.rs
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::io;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use crate::parser::ast::{CommandValue, Expression, LetExpression, RedirectTargetExpression, Value};
|
||||||
|
use crate::parser::vars;
|
||||||
|
use crate::parser::vars::Variable;
|
||||||
|
|
||||||
|
trait ExecExpression {
|
||||||
|
fn exec(self, ctx: &mut vars::Context) -> Option<Command>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait GetValue {
|
||||||
|
fn get(self, ctx: &mut vars::Context) -> Variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetValue for CommandValue {
|
||||||
|
fn get(self, ctx: &mut vars::Context) -> Variable {
|
||||||
|
match self {
|
||||||
|
CommandValue::Value(val) => val.get(ctx),
|
||||||
|
CommandValue::Var(_, _) => panic!("Broken executor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetValue for Value {
|
||||||
|
fn get(self, ctx: &mut vars::Context) -> Variable {
|
||||||
|
match self {
|
||||||
|
Value::Literal(str) => {
|
||||||
|
Variable::String(str)
|
||||||
|
},
|
||||||
|
Value::Variable(str) => ctx.get_var(&str).unwrap_or(&mut Variable::String(String::from(""))).clone(),
|
||||||
|
Value::ArrayVariable(str) => ctx.get_var(&str).unwrap_or(&mut Variable::Array(Vec::new())).clone(),
|
||||||
|
Value::ArrayFunction(_) => panic!("Not implemented yet"),
|
||||||
|
Value::StringFunction(_) => panic!("Not implemented yet"),
|
||||||
|
Value::Expressions(expressions) => {
|
||||||
|
let mut out = String::new();
|
||||||
|
ctx.add_scope(true);
|
||||||
|
for mut expr in expressions {
|
||||||
|
let res = expr.exec(ctx);
|
||||||
|
match res {
|
||||||
|
None => {},
|
||||||
|
Some(mut cmd) => {
|
||||||
|
out += &*String::from_utf8_lossy(&cmd.output().expect("Failed to read output of command").stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.pop_scope();
|
||||||
|
Variable::String(out)
|
||||||
|
},
|
||||||
|
Value::Values(vec) => {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
for mut val in vec {
|
||||||
|
out.push(val.get(ctx));
|
||||||
|
}
|
||||||
|
Variable::Array(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecExpression for Expression {
|
||||||
|
fn exec(self, ctx: &mut vars::Context) -> Option<Command> {
|
||||||
|
match self {
|
||||||
|
Expression::LetExpression(expr) => expr.exec(ctx),
|
||||||
|
Expression::Command(expr) => expr.exec(ctx),
|
||||||
|
Expression::JobCommand(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::Function(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::IfExpression(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::WhileExpression(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::ForExpression(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::RedirectTargetExpression(expr) => expr.exec(ctx),
|
||||||
|
Expression::FileTargetExpression(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::FileSourceExpression(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::Expressions(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::OrExpression(_) => panic!("Not implemented yet"),
|
||||||
|
Expression::AndExpression(_) => panic!("Not implemented yet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecExpression for LetExpression {
|
||||||
|
fn exec(mut self, ctx: &mut vars::Context) -> Option<Command> {
|
||||||
|
let key = self.key.get(ctx);
|
||||||
|
let val = self.value.get(ctx);
|
||||||
|
ctx.set_var(key.to_string(), val);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecExpression for Vec<CommandValue> {
|
||||||
|
fn exec(mut self, ctx: &mut vars::Context) -> Option<Command> {
|
||||||
|
if self.len() == 0 { panic!("Command with 0 length"); }
|
||||||
|
let mut first = self.remove(0);
|
||||||
|
let command_name = first.get(ctx).to_string();
|
||||||
|
let mut cmd = Command::new(command_name);
|
||||||
|
for mut value in self {
|
||||||
|
cmd.arg(value.get(ctx).to_string());
|
||||||
|
}
|
||||||
|
Some(cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecExpression for RedirectTargetExpression {
|
||||||
|
fn exec(mut self, ctx: &mut vars::Context) -> Option<Command> {
|
||||||
|
let mut src = self.source.exec(ctx).unwrap();
|
||||||
|
let mut target = self.target.exec(ctx).unwrap();
|
||||||
|
src.stdout(Stdio::piped());
|
||||||
|
match src.spawn() {
|
||||||
|
Result::Err(e) => { println!("Error executing: {}", e)},
|
||||||
|
Result::Ok(mut res) => {
|
||||||
|
target.stdin(res.stdout.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec_tree(tree: Vec<Expression>, ctx: &mut vars::Context) {
|
||||||
|
println!("Executing");
|
||||||
|
for mut expression in tree {
|
||||||
|
let mut cmd = expression.exec(ctx);
|
||||||
|
match cmd {
|
||||||
|
None => {},
|
||||||
|
Some(mut cmd) => match cmd.spawn() {
|
||||||
|
Result::Err(e) => {
|
||||||
|
println!("Error executing: {}", e);
|
||||||
|
},
|
||||||
|
Result::Ok(mut res) => {
|
||||||
|
let out = res.wait().unwrap();
|
||||||
|
ctx.set_var(String::from("!"), Variable::I32(out.code().unwrap_or(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
pub mod vars;
|
pub mod vars;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod tokens;
|
pub mod tokens;
|
||||||
|
mod exec;
|
||||||
|
|
||||||
use crate::parser::ast::{build_tree};
|
use crate::parser::ast::{build_tree};
|
||||||
|
use crate::parser::exec::exec_tree;
|
||||||
use crate::parser::tokens::{tokenize};
|
use crate::parser::tokens::{tokenize};
|
||||||
|
|
||||||
pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) {
|
pub fn exec(reader: &mut dyn std::io::BufRead, ctx: &mut vars::Context) {
|
||||||
let tokens = tokenize(reader).unwrap();
|
let tokens = tokenize(reader).unwrap();
|
||||||
|
|
||||||
dbg!(&tokens);
|
dbg!(&tokens);
|
||||||
|
|
@ -13,6 +15,8 @@ pub fn exec(reader: &mut dyn std::io::BufRead, ctx: vars::Context) {
|
||||||
let expressions = build_tree(tokens);
|
let expressions = build_tree(tokens);
|
||||||
|
|
||||||
dbg!(&expressions);
|
dbg!(&expressions);
|
||||||
|
|
||||||
|
exec_tree(expressions, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn escape(str: String) -> String {
|
pub fn escape(str: String) -> String {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::parser::ast::FunctionDefinitionExpression;
|
use crate::parser::ast::FunctionDefinitionExpression;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Variable {
|
pub enum Variable {
|
||||||
String(String),
|
String(String),
|
||||||
I32(i32),
|
I32(i32),
|
||||||
|
|
@ -19,7 +19,9 @@ pub enum Variable {
|
||||||
impl Variable {
|
impl Variable {
|
||||||
pub fn to_string(self: &Self) -> String {
|
pub fn to_string(self: &Self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Variable::String(var) => String::from(var),
|
Variable::String(var) => {
|
||||||
|
var.clone()
|
||||||
|
},
|
||||||
Variable::I32(num) => num.to_string(),
|
Variable::I32(num) => num.to_string(),
|
||||||
Variable::I64(num) => num.to_string(),
|
Variable::I64(num) => num.to_string(),
|
||||||
Variable::I128(num) => num.to_string(),
|
Variable::I128(num) => num.to_string(),
|
||||||
|
|
@ -32,10 +34,16 @@ impl Variable {
|
||||||
String::from("[Object object]")
|
String::from("[Object object]")
|
||||||
},
|
},
|
||||||
Variable::Array(vars) => {
|
Variable::Array(vars) => {
|
||||||
|
let len = vars.len();
|
||||||
|
if len == 1 { return vars.get(0).unwrap().to_string(); }
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
|
let mut i = 0;
|
||||||
for var in vars {
|
for var in vars {
|
||||||
str += &*var.clone().to_string();
|
str += &*var.clone().to_string();
|
||||||
str += " ";
|
if i < len - 1 {
|
||||||
|
str += " ";
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
str
|
str
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue