diff --git a/bellos_scripts/basic_math.bellos b/bellos_scripts/basic_math.bellos
index bdeea06..bf2e354 100644
--- a/bellos_scripts/basic_math.bellos
+++ b/bellos_scripts/basic_math.bellos
@@ -3,38 +3,43 @@
# Demonstrating arithmetic operations
-echo Basic Math Operations
+# Addition
+result=$((5 + 3))
+echo Addition: 5 + 3 = $result
-# Simple echo statements for arithmetic
-echo Addition:
-echo 5 + 3 = 8
+# Subtraction
+result=$((10 - 4))
+echo Subtraction: 10 - 4 = $result
-echo Subtraction:
-echo 10 - 4 = 6
+# Multiplication
+result=$((6 * 7))
+echo Multiplication: 6 * 7 = $result
-echo Multiplication:
-echo 6 * 7 = 42
+# Division
+result=$((20 / 4))
+echo Division: 20 / 4 = $result
-echo Division:
-echo 20 / 4 = 5
+# Modulus
+result=$((17 % 5))
+echo Modulus: 17 % 5 = $result
-echo Modulus:
-echo 17 % 5 = 2
+# Compound operation
+result=$(( (10 + 5) * 2 ))
+echo Compound: (10 + 5) * 2 = $result
-echo Compound operation:
-echo (10 + 5) * 2 = 30
-
-# Using variables (without arithmetic)
-echo Using variables:
+# Using variables
a=7
b=3
-echo a = $a
-echo b = $b
+result=$((a + b))
+echo Variables: $a + $b = $result
-# Simple increments and decrements
-echo Increment and Decrement:
-echo count = 0
-echo count after increment: 1
-echo count after decrement: 0
+# Increment
+count=0
+count=$((count + 1))
+echo Increment: count after increment = $count
+
+# Decrement
+count=$((count - 1))
+echo Decrement: count after decrement = $count
echo Basic math operations completed.
diff --git a/dependencies.txt b/dependencies.txt
index a25ed55..4e72c59 100644
--- a/dependencies.txt
+++ b/dependencies.txt
@@ -1,3 +1,4 @@
glob = "0.3.0"
tempfile = "3.2"
shellexpand = "3.1.0"
+meval = "0.2"
diff --git a/executable/bellos b/executable/bellos
index 59a3bc1..fbca1db 100755
Binary files a/executable/bellos and b/executable/bellos differ
diff --git a/src/bellos.rs b/src/bellos.rs
index 7e915bc..e34b188 100644
--- a/src/bellos.rs
+++ b/src/bellos.rs
@@ -13,22 +13,19 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-mod executor;
+mod executor_processes;
mod interpreter;
mod lexer;
mod parser;
mod utilities;
-use crate::executor::executor::Executor;
-use std::env;
-use std::process;
+use crate::executor_processes::executor::Executor;
fn main() {
- let args: Vec = env::args().collect();
+ let args: Vec = std::env::args().collect();
let mut executor = Executor::new();
-
if let Err(e) = executor.run(args) {
eprintln!("Application error: {}", e);
- process::exit(1);
+ std::process::exit(1);
}
}
diff --git a/src/executor/executor.rs b/src/executor/executor.rs
deleted file mode 100644
index 07cc9be..0000000
--- a/src/executor/executor.rs
+++ /dev/null
@@ -1,413 +0,0 @@
-// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-use crate::interpreter::interpreter::Interpreter;
-use crate::lexer::lexer::Lexer;
-use crate::parser::parser::Parser;
-use crate::utilities::utilities::{ASTNode, RedirectType, Token};
-use shellexpand;
-use std::collections::HashMap;
-use std::fs::{File, OpenOptions};
-use std::io::{self, BufRead, Read, Write};
-use std::process::{Command, Stdio};
-
-pub struct Executor {
- interpreter: Interpreter,
- variables: HashMap,
- functions: HashMap,
- last_exit_status: i32,
-}
-
-impl Executor {
- pub fn new() -> Self {
- Executor {
- interpreter: Interpreter::new(),
- variables: HashMap::new(),
- functions: HashMap::new(),
- last_exit_status: 0,
- }
- }
-
- pub fn run(&mut self, args: Vec) -> Result<(), String> {
- if args.len() > 1 {
- // Execute script file
- self.execute_script(&args[1])
- } else {
- // Interactive mode
- self.run_interactive_mode()
- }
- }
-
- fn execute_script(&mut self, filename: &str) -> Result<(), String> {
- let file =
- File::open(filename).map_err(|e| format!("Error opening file {}: {}", filename, e))?;
- let reader = io::BufReader::new(file);
-
- for (line_num, line) in reader.lines().enumerate() {
- let line = line.map_err(|e| format!("Error reading line: {}", e))?;
- self.process_line(&line, line_num + 1)?;
- }
- Ok(())
- }
-
- fn process_line(&mut self, line: &str, line_num: usize) -> Result<(), String> {
- let trimmed_line = line.trim();
- if trimmed_line.is_empty() || trimmed_line.starts_with('#') {
- return Ok(()); // Skip empty lines and comments
- }
-
- let lexer = Lexer::new(line.to_string());
- let tokens: Vec = lexer.into_iter().collect();
- let mut parser = Parser::new(tokens);
- match parser.parse() {
- Ok(ast) => {
- if let Err(e) = self.execute(ast) {
- eprintln!("Error on line {}: {}", line_num, e);
- }
- }
- Err(e) => eprintln!("Parse error on line {}: {}", line_num, e),
- }
- Ok(())
- }
-
- fn run_interactive_mode(&mut self) -> Result<(), String> {
- loop {
- print!("bellos> ");
- io::stdout().flush().unwrap();
- let mut input = String::new();
- io::stdin().read_line(&mut input).unwrap();
-
- if input.trim().is_empty() {
- continue;
- }
-
- let lexer = Lexer::new(input);
- let tokens: Vec = lexer.into_iter().collect();
- let mut parser = Parser::new(tokens);
- match parser.parse() {
- Ok(ast) => {
- if let Err(e) = self.execute(ast) {
- eprintln!("Error: {}", e);
- }
- }
- Err(e) => eprintln!("Parse error: {}", e),
- }
- }
- }
-
- pub fn execute(&mut self, nodes: Vec) -> Result<(), String> {
- for node in nodes {
- self.execute_node(node)?;
- }
- Ok(())
- }
-
- fn execute_node(&mut self, node: ASTNode) -> Result {
- match node {
- ASTNode::Command { name, args } => self.execute_command(name, args),
- ASTNode::Assignment { name, value } => {
- let expanded_value = self.expand_variables(&value);
- self.variables.insert(name, expanded_value);
- Ok(String::new())
- }
- ASTNode::Pipeline(commands) => self.execute_pipeline(commands),
- ASTNode::Redirect {
- node,
- direction,
- target,
- } => self.execute_redirect(*node, direction, target),
- ASTNode::Block(nodes) => {
- let mut last_output = String::new();
- for node in nodes {
- last_output = self.execute_node(node)?;
- }
- Ok(last_output)
- }
- ASTNode::If {
- condition,
- then_block,
- else_block,
- } => self.execute_if(*condition, *then_block, else_block.map(|b| *b)),
- ASTNode::While { condition, block } => self.execute_while(*condition, *block),
- ASTNode::For { var, list, block } => self.execute_for(var, list, *block),
- ASTNode::Function { name, body } => {
- self.functions.insert(name, *body);
- Ok(String::new())
- }
- ASTNode::Background(node) => self.execute_background(*node),
- }
- }
-
- fn execute_command(&mut self, name: String, args: Vec) -> Result {
- let expanded_args: Vec =
- args.iter().map(|arg| self.expand_variables(arg)).collect();
-
- let result = match name.as_str() {
- "cd" => self.change_directory(&expanded_args),
- "echo" => {
- let output = expanded_args.join(" ");
- println!("{}", output);
- Ok(output)
- }
- "exit" => std::process::exit(0),
- "write" => self.handle_write(&expanded_args),
- "append" => self.handle_append(&expanded_args),
- "read" => self.handle_read(&expanded_args),
- "read_lines" => self.handle_read_lines(&expanded_args),
- "delete" => self.handle_delete(&expanded_args),
- _ => {
- if let Some(function) = self.functions.get(&name) {
- self.execute_node(function.clone())
- } else {
- // Execute external command
- let output = Command::new(&name)
- .args(&expanded_args)
- .output()
- .map_err(|e| format!("Failed to execute command: {}", e))?;
-
- if output.status.success() {
- Ok(String::from_utf8_lossy(&output.stdout).to_string())
- } else {
- Err(String::from_utf8_lossy(&output.stderr).to_string())
- }
- }
- }
- };
-
- self.last_exit_status = if result.is_ok() { 0 } else { 1 };
- result
- }
-
- fn change_directory(&self, args: &[String]) -> Result {
- let new_dir = args.get(0).map(|s| s.as_str()).unwrap_or("~");
- let path = shellexpand::tilde(new_dir);
- std::env::set_current_dir(path.as_ref())
- .map_err(|e| format!("Failed to change directory: {}", e))?;
- Ok(String::new())
- }
-
- fn execute_pipeline(&mut self, commands: Vec) -> Result {
- let mut last_output = Vec::new();
-
- for (i, command) in commands.iter().enumerate() {
- let mut child = match command {
- ASTNode::Command { name, args } => {
- let mut cmd = Command::new(name);
- cmd.args(args);
-
- if i > 0 {
- cmd.stdin(Stdio::piped());
- }
- if i < commands.len() - 1 {
- cmd.stdout(Stdio::piped());
- }
-
- cmd.spawn()
- .map_err(|e| format!("Failed to spawn command: {}", e))?
- }
- _ => return Err("Invalid command in pipeline".to_string()),
- };
-
- if i > 0 {
- if let Some(mut stdin) = child.stdin.take() {
- stdin
- .write_all(&last_output)
- .map_err(|e| format!("Failed to write to stdin: {}", e))?;
- }
- }
-
- let output = child
- .wait_with_output()
- .map_err(|e| format!("Failed to wait for command: {}", e))?;
- last_output = output.stdout;
- }
-
- Ok(String::from_utf8_lossy(&last_output).to_string())
- }
-
- fn execute_redirect(
- &mut self,
- node: ASTNode,
- direction: RedirectType,
- target: String,
- ) -> Result {
- let output = self.execute_node(node)?;
-
- match direction {
- RedirectType::Out => {
- let mut file =
- File::create(&target).map_err(|e| format!("Failed to create file: {}", e))?;
- file.write_all(output.as_bytes())
- .map_err(|e| format!("Failed to write to file: {}", e))?;
- }
- RedirectType::Append => {
- let mut file = OpenOptions::new()
- .append(true)
- .create(true)
- .open(&target)
- .map_err(|e| format!("Failed to open file: {}", e))?;
- file.write_all(output.as_bytes())
- .map_err(|e| format!("Failed to append to file: {}", e))?;
- }
- RedirectType::In => {
- let mut file =
- File::open(&target).map_err(|e| format!("Failed to open file: {}", e))?;
- let mut content = String::new();
- file.read_to_string(&mut content)
- .map_err(|e| format!("Failed to read file: {}", e))?;
- return Ok(content);
- }
- }
-
- Ok(String::new())
- }
-
- fn execute_if(
- &mut self,
- condition: ASTNode,
- then_block: ASTNode,
- else_block: Option,
- ) -> Result {
- let condition_result = self.execute_node(condition)?;
- if !condition_result.trim().is_empty() && condition_result.trim() != "0" {
- self.execute_node(then_block)
- } else if let Some(else_block) = else_block {
- self.execute_node(else_block)
- } else {
- Ok(String::new())
- }
- }
-
- fn execute_while(&mut self, condition: ASTNode, block: ASTNode) -> Result {
- let mut last_output = String::new();
- while {
- let condition_result = self.execute_node(condition.clone())?;
- !condition_result.trim().is_empty() && condition_result.trim() != "0"
- } {
- last_output = self.execute_node(block.clone())?;
- }
- Ok(last_output)
- }
-
- fn execute_for(
- &mut self,
- var: String,
- list: Vec,
- block: ASTNode,
- ) -> Result {
- let mut last_output = String::new();
- for item in list {
- self.variables.insert(var.clone(), item);
- last_output = self.execute_node(block.clone())?;
- }
- Ok(last_output)
- }
-
- fn execute_background(&mut self, node: ASTNode) -> Result {
- std::thread::spawn(move || {
- let mut executor = Executor::new();
- if let Err(e) = executor.execute_node(node) {
- eprintln!("Background job error: {}", e);
- }
- });
- Ok(String::new())
- }
-
- fn expand_variables(&self, input: &str) -> String {
- let mut result = String::new();
- let mut chars = input.chars().peekable();
- while let Some(c) = chars.next() {
- if c == '$' {
- let var_name: String = chars
- .by_ref()
- .take_while(|&c| c.is_alphanumeric() || c == '_')
- .collect();
- if var_name == "?" {
- result.push_str(&self.last_exit_status.to_string());
- } else if var_name == "#" {
- // Assuming we don't have access to script arguments in this context
- result.push_str("0");
- } else if let Some(value) = self.variables.get(&var_name) {
- result.push_str(value);
- } else if let Ok(value) = std::env::var(&var_name) {
- result.push_str(&value);
- }
- } else {
- result.push(c);
- }
- }
- result
- }
-
- // File handling methods
- fn handle_write(&self, args: &[String]) -> Result {
- if args.len() != 2 {
- return Err("Usage: write ".to_string());
- }
- let filename = &args[0];
- let content = &args[1];
-
- std::fs::write(filename, content).map_err(|e| format!("Failed to write to file: {}", e))?;
- Ok(format!("Successfully wrote to {}", filename))
- }
-
- fn handle_append(&self, args: &[String]) -> Result {
- if args.len() != 2 {
- return Err("Usage: append ".to_string());
- }
- let filename = &args[0];
- let content = &args[1];
-
- use std::fs::OpenOptions;
- use std::io::Write;
-
- let mut file = OpenOptions::new()
- .append(true)
- .create(true)
- .open(filename)
- .map_err(|e| format!("Failed to open file for appending: {}", e))?;
-
- writeln!(file, "{}", content).map_err(|e| format!("Failed to append to file: {}", e))?;
- Ok(format!("Successfully appended to {}", filename))
- }
-
- fn handle_read(&self, args: &[String]) -> Result {
- if args.len() != 1 {
- return Err("Usage: read ".to_string());
- }
- let filename = &args[0];
-
- let content =
- std::fs::read_to_string(filename).map_err(|e| format!("Failed to read file: {}", e))?;
- Ok(content)
- }
-
- fn handle_read_lines(&self, args: &[String]) -> Result {
- if args.len() != 1 {
- return Err("Usage: read_lines ".to_string());
- }
- self.handle_read(args)
- }
-
- fn handle_delete(&self, args: &[String]) -> Result {
- if args.len() != 1 {
- return Err("Usage: delete ".to_string());
- }
- let filename = &args[0];
-
- std::fs::remove_file(filename).map_err(|e| format!("Failed to delete file: {}", e))?;
- Ok(format!("Successfully deleted {}", filename))
- }
-}
diff --git a/src/executor/mod.rs b/src/executor/mod.rs
deleted file mode 100644
index 0c95fda..0000000
--- a/src/executor/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod executor;
diff --git a/src/executor_processes/executor.rs b/src/executor_processes/executor.rs
new file mode 100644
index 0000000..dab6f21
--- /dev/null
+++ b/src/executor_processes/executor.rs
@@ -0,0 +1,115 @@
+// Copyright (C) 2024 Bellande Architecture Mechanism Research Innovation Center, Ronaldson Bellande
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use crate::executor_processes::processes::Processes;
+use crate::interpreter::interpreter::Interpreter;
+use crate::lexer::lexer::Lexer;
+use crate::parser::parser::Parser;
+use crate::utilities::utilities::ASTNode;
+use std::fs::File;
+use std::io::{self, BufRead, BufReader, Write};
+use std::sync::Arc;
+
+pub struct Executor {
+ interpreter: Interpreter,
+ processes: Arc,
+}
+
+impl Executor {
+ pub fn new() -> Self {
+ Executor {
+ interpreter: Interpreter::new(),
+ processes: Arc::new(Processes::new()),
+ }
+ }
+
+ pub fn run(&mut self, args: Vec) -> Result<(), String> {
+ if args.len() > 1 {
+ // Execute script file
+ self.execute_script(&args[1])
+ } else {
+ // Interactive mode
+ self.run_interactive_mode()
+ }
+ }
+
+ fn execute_script(&mut self, filename: &str) -> Result<(), String> {
+ let file =
+ File::open(filename).map_err(|e| format!("Error opening file {}: {}", filename, e))?;
+ let reader = BufReader::new(file);
+ for line in reader.lines() {
+ let line = line.map_err(|e| format!("Error reading line: {}", e))?;
+ self.process_content(&line)?;
+ }
+ Ok(())
+ }
+
+ fn run_interactive_mode(&mut self) -> Result<(), String> {
+ loop {
+ print!("bellos> ");
+ io::stdout().flush().unwrap();
+ let mut input = String::new();
+ io::stdin().read_line(&mut input).unwrap();
+
+ if input.trim().is_empty() {
+ continue;
+ }
+
+ if let Err(e) = self.process_content(&input) {
+ eprintln!("Error: {}", e);
+ }
+ }
+ }
+
+ fn process_content(&mut self, content: &str) -> Result<(), String> {
+ let ast_nodes = self.parse_content(content)?;
+ self.execute(ast_nodes)
+ }
+
+ fn parse_content(&self, content: &str) -> Result, String> {
+ let mut lexer = Lexer::new(content.to_string());
+ let tokens = lexer.tokenize();
+ let mut parser = Parser::new(tokens);
+ parser.parse()
+ }
+
+ pub fn execute(&mut self, nodes: Vec) -> Result<(), String> {
+ for node in nodes {
+ self.execute_node(node)?;
+ }
+ Ok(())
+ }
+
+ fn execute_node(&mut self, node: ASTNode) -> Result