latest pushes

This commit is contained in:
Ronaldson Bellande 2024-10-04 21:12:19 -04:00
parent 159fd823a7
commit a4dfa81ed4
6 changed files with 265 additions and 129 deletions

View File

@ -4,66 +4,33 @@
# Demonstrating string manipulation # Demonstrating string manipulation
# String concatenation # String concatenation
str1="Hello" first_name=John
str2="World" last_name=Doe
concat="$str1 $str2" full_name=$first_name $last_name
echo "Concatenated string: $concat" echo Full name: $full_name
# String length # String length
echo "Length of '$concat': ${#concat}" string="Hello, World!"
echo "The string '$string' has ${#string} characters."
# Substring extraction # Substring extraction
echo "Substring (index 0-4): ${concat:0:5}" echo "The first 5 characters are: ${string:0:5}"
echo "Substring (from index 6): ${concat:6}"
# String replacement # String replacement
sentence="The quick brown fox jumps over the lazy dog" sentence="The quick brown fox jumps over the lazy dog"
echo "Original sentence: $sentence" echo "Original sentence: $sentence"
replaced=${sentence/fox/cat} new_sentence=${sentence/fox/cat}
echo "After replacing 'fox' with 'cat': $replaced" echo "Modified sentence: $new_sentence"
# Replace all occurrences # Converting to uppercase and lowercase
many_the="the the the dog the cat the mouse" echo "Uppercase: ${string^^}"
replaced_all=${many_the//the/a} echo "Lowercase: ${string,,}"
echo "Replace all 'the' with 'a': $replaced_all"
# String to uppercase # Trimming whitespace
uppercase=${sentence^^} padded_string=" trim me "
echo "Uppercase: $uppercase" echo "Original string: '$padded_string'"
trimmed_string=${padded_string## }
# String to lowercase trimmed_string=${trimmed_string%% }
lowercase=${sentence,,}
echo "Lowercase: $lowercase"
# Check if string contains substring
if [[ $sentence == *"fox"* ]]; then
echo "The sentence contains 'fox'"
else
echo "The sentence does not contain 'fox'"
fi
# Split string into array
IFS=' ' read -ra words <<< "$sentence"
echo "Words in the sentence:"
for word in "${words[@]}"; do
echo " $word"
done
# Join array elements into string
joined=$(IFS=", "; echo "${words[*]}")
echo "Joined words: $joined"
# Trim whitespace
whitespace_string=" trim me "
trimmed_string=$(echo $whitespace_string | xargs)
echo "Original string: '$whitespace_string'"
echo "Trimmed string: '$trimmed_string'" echo "Trimmed string: '$trimmed_string'"
# String comparison echo "String manipulation operations completed."
str_a="apple"
str_b="banana"
if [[ $str_a < $str_b ]]; then
echo "$str_a comes before $str_b alphabetically"
else
echo "$str_b comes before $str_a alphabetically"
fi

Binary file not shown.

View File

@ -23,6 +23,8 @@ use crate::executor_processes::executor::Executor;
fn main() { fn main() {
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
println!("Arguments: {:?}", args);
let mut executor = Executor::new(); let mut executor = Executor::new();
if let Err(e) = executor.run(args) { if let Err(e) = executor.run(args) {
eprintln!("Application error: {}", e); eprintln!("Application error: {}", e);

View File

@ -20,6 +20,7 @@ use crate::parser::parser::Parser;
use crate::utilities::utilities::ASTNode; use crate::utilities::utilities::ASTNode;
use std::fs::File; use std::fs::File;
use std::io::{self, BufRead, BufReader, Write}; use std::io::{self, BufRead, BufReader, Write};
use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
pub struct Executor { pub struct Executor {
@ -46,12 +47,53 @@ impl Executor {
} }
fn execute_script(&mut self, filename: &str) -> Result<(), String> { fn execute_script(&mut self, filename: &str) -> Result<(), String> {
println!("Executing script: {}", filename);
if !filename.ends_with(".bellos") {
return Err(format!("Not a .bellos script: {}", filename));
}
let path = Path::new(filename);
if !path.exists() {
return Err(format!("Script file does not exist: {}", filename));
}
let file = let file =
File::open(filename).map_err(|e| format!("Error opening file {}: {}", filename, e))?; File::open(path).map_err(|e| format!("Error opening file {}: {}", filename, e))?;
let reader = BufReader::new(file); let reader = BufReader::new(file);
for line in reader.lines() {
let line = line.map_err(|e| format!("Error reading line: {}", e))?; for (index, line) in reader.lines().enumerate() {
self.process_content(&line)?; let line = line.map_err(|e| format!("Error reading line {}: {}", index + 1, e))?;
let trimmed_line = line.trim();
if trimmed_line.is_empty() || trimmed_line.starts_with('#') {
continue; // Skip empty lines and comments
}
// Handle variable assignments and arithmetic operations
if trimmed_line.contains('=') {
let parts: Vec<&str> = trimmed_line.splitn(2, '=').collect();
if parts.len() == 2 {
let var_name = parts[0].trim().to_string();
let var_value = parts[1].trim().to_string();
if var_value.starts_with("$((") && var_value.ends_with("))") {
// Arithmetic expression
let result = self.interpreter.evaluate_arithmetic(&var_value)?;
self.interpreter
.variables
.insert(var_name, result.to_string());
} else {
// Regular variable assignment
let expanded_value = self.interpreter.expand_variables(&var_value);
self.interpreter.variables.insert(var_name, expanded_value);
}
continue;
}
}
if let Err(e) = self.process_content(trimmed_line) {
return Err(format!("Error on line {}: {}", index + 1, e));
}
} }
Ok(()) Ok(())
} }
@ -74,6 +116,28 @@ impl Executor {
} }
fn process_content(&mut self, content: &str) -> Result<(), String> { fn process_content(&mut self, content: &str) -> Result<(), String> {
// Handle variable assignments and arithmetic operations
if content.contains('=') {
let parts: Vec<&str> = content.splitn(2, '=').collect();
if parts.len() == 2 {
let var_name = parts[0].trim().to_string();
let var_value = parts[1].trim().to_string();
if var_value.starts_with("$((") && var_value.ends_with("))") {
// Arithmetic expression
let result = self.interpreter.evaluate_arithmetic(&var_value)?;
self.interpreter
.variables
.insert(var_name, result.to_string());
} else {
// Regular variable assignment
let expanded_value = self.interpreter.expand_variables(&var_value);
self.interpreter.variables.insert(var_name, expanded_value);
}
return Ok(());
}
}
let ast_nodes = self.parse_content(content)?; let ast_nodes = self.parse_content(content)?;
self.execute(ast_nodes) self.execute(ast_nodes)
} }
@ -94,10 +158,9 @@ impl Executor {
fn execute_node(&mut self, node: ASTNode) -> Result<Option<i32>, String> { fn execute_node(&mut self, node: ASTNode) -> Result<Option<i32>, String> {
match node { match node {
ASTNode::Command { name, args } => { ASTNode::Command { name, args } => Arc::get_mut(&mut self.processes)
self.processes .unwrap()
.execute_command(&mut self.interpreter, name, args) .execute_command(&mut self.interpreter, name, args),
}
ASTNode::Pipeline(commands) => { ASTNode::Pipeline(commands) => {
self.processes.execute_pipeline(&self.interpreter, commands) self.processes.execute_pipeline(&self.interpreter, commands)
} }
@ -105,9 +168,12 @@ impl Executor {
node, node,
direction, direction,
target, target,
} => self } => Arc::get_mut(&mut self.processes).unwrap().execute_redirect(
.processes &mut self.interpreter,
.execute_redirect(&mut self.interpreter, *node, direction, target), *node,
direction,
target,
),
ASTNode::Background(node) => self.processes.execute_background(*node), ASTNode::Background(node) => self.processes.execute_background(*node),
_ => self.interpreter.interpret_node(Box::new(node)), _ => self.interpreter.interpret_node(Box::new(node)),
} }

View File

@ -14,13 +14,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::interpreter::interpreter::Interpreter; use crate::interpreter::interpreter::Interpreter;
use crate::lexer::lexer::Lexer;
use crate::parser::parser::Parser;
use crate::utilities::utilities::{ASTNode, RedirectType}; use crate::utilities::utilities::{ASTNode, RedirectType};
use glob::glob; use glob::glob;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::io::{self, BufReader, BufWriter, Cursor, Read, Write}; use std::io::{self, BufReader, BufWriter, Cursor, Read, Write};
use std::path::Path;
use std::process::{Child, Command, Stdio}; use std::process::{Child, Command, Stdio};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
@ -37,7 +34,7 @@ impl Processes {
} }
pub fn execute_command( pub fn execute_command(
&self, &mut self,
interpreter: &mut Interpreter, interpreter: &mut Interpreter,
name: String, name: String,
args: Vec<String>, args: Vec<String>,
@ -48,9 +45,30 @@ impl Processes {
.map(|arg| interpreter.expand_variables(arg)) .map(|arg| interpreter.expand_variables(arg))
.collect(); .collect();
// Handle arithmetic assignments
if expanded_name.contains('=') {
let parts: Vec<&str> = expanded_name.splitn(2, '=').collect();
if parts.len() == 2 {
let var_name = parts[0].trim().to_string();
let var_value = parts[1].trim().to_string();
if var_value.starts_with("$((") && var_value.ends_with("))") {
// Arithmetic expression
let result = interpreter.evaluate_arithmetic(&var_value)?;
interpreter.variables.insert(var_name, result.to_string());
} else {
// Regular variable assignment
let expanded_value = interpreter.expand_variables(&var_value);
interpreter.variables.insert(var_name, expanded_value);
}
return Ok(Some(0));
}
}
match expanded_name.as_str() { match expanded_name.as_str() {
"echo" => { "echo" => {
println!("{}", expanded_args.join(" ")); let output = expanded_args.join(" ");
println!("{}", output);
Ok(Some(0)) Ok(Some(0))
} }
"cd" => { "cd" => {
@ -82,39 +100,60 @@ impl Processes {
} }
Ok(Some(0)) Ok(Some(0))
} }
"write" => {
if expanded_args.len() != 2 {
return Err("Usage: write <filename> <content>".to_string());
}
let filename = &expanded_args[0];
let content = &expanded_args[1];
let mut file = File::create(filename)
.map_err(|e| format!("Failed to create file {}: {}", filename, e))?;
file.write_all(content.as_bytes())
.map_err(|e| format!("Failed to write to file {}: {}", filename, e))?;
Ok(Some(0))
}
"read" => {
if expanded_args.len() != 1 {
return Err("Usage: read <filename>".to_string());
}
let filename = &expanded_args[0];
let mut content = String::new();
File::open(filename)
.map_err(|e| format!("Failed to open file {}: {}", filename, e))?
.read_to_string(&mut content)
.map_err(|e| format!("Failed to read file {}: {}", filename, e))?;
println!("{}", content);
Ok(Some(0))
}
"append" => {
if expanded_args.len() != 2 {
return Err("Usage: append <filename> <content>".to_string());
}
let filename = &expanded_args[0];
let content = &expanded_args[1];
let mut file = OpenOptions::new()
.append(true)
.open(filename)
.map_err(|e| format!("Failed to open file {}: {}", filename, e))?;
file.write_all(content.as_bytes())
.map_err(|e| format!("Failed to append to file {}: {}", filename, e))?;
Ok(Some(0))
}
"delete" => {
if expanded_args.len() != 1 {
return Err("Usage: delete <filename>".to_string());
}
let filename = &expanded_args[0];
std::fs::remove_file(filename)
.map_err(|e| format!("Failed to delete file {}: {}", filename, e))?;
Ok(Some(0))
}
_ => { _ => {
if let Some(func) = interpreter.functions.get(&expanded_name) { if let Some(func) = interpreter.functions.get(&expanded_name) {
return interpreter.interpret_node(Box::new(func.clone())); return interpreter.interpret_node(Box::new(func.clone()));
} }
// Check if the command is a .bellos script // If it's not a built-in command or variable assignment, try to execute as external command
if expanded_name.ends_with(".bellos") {
let path = Path::new(&expanded_name);
if path.exists() {
// Read the script file
let mut file = File::open(path)
.map_err(|e| format!("Failed to open script file: {}", e))?;
let mut content = String::new();
file.read_to_string(&mut content)
.map_err(|e| format!("Failed to read script file: {}", e))?;
// Parse and execute the script content
let mut lexer = Lexer::new(content);
let tokens = lexer.tokenize();
let mut parser = Parser::new(tokens);
let ast = parser
.parse()
.map_err(|e| format!("Failed to parse script: {}", e))?;
for node in ast {
interpreter.interpret_node(Box::new(node))?;
}
return Ok(Some(0));
}
}
// If it's not a .bellos script, try to execute it as a system command
match Command::new(&expanded_name).args(&expanded_args).spawn() { match Command::new(&expanded_name).args(&expanded_args).spawn() {
Ok(mut child) => { Ok(mut child) => {
let status = child.wait().map_err(|e| e.to_string())?; let status = child.wait().map_err(|e| e.to_string())?;

View File

@ -79,6 +79,9 @@ impl Interpreter {
self.functions.insert(name, *body); self.functions.insert(name, *body);
Ok(None) Ok(None)
} }
ASTNode::Command { name: _, args: _ } => {
Err("Commands should be handled by Processes".to_string())
}
_ => Err("Node type not handled by Interpreter".to_string()), _ => Err("Node type not handled by Interpreter".to_string()),
} }
} }
@ -123,15 +126,27 @@ impl Interpreter {
while let Some(c) = chars.next() { while let Some(c) = chars.next() {
if c == '$' { if c == '$' {
if chars.peek() == Some(&'(') { if chars.peek() == Some(&'(') {
chars.next(); // consume '(' let mut depth = 0;
let expr: String = chars.by_ref().take_while(|&c| c != ')').collect(); let mut expr = String::new();
if expr.starts_with('(') && expr.ends_with(')') { for c in chars.by_ref() {
// Arithmetic expression expr.push(c);
let arithmetic_expr = &expr[1..expr.len() - 1]; if c == '(' {
match self.evaluate_arithmetic(arithmetic_expr) { depth += 1;
} else if c == ')' {
depth -= 1;
if depth == 0 {
break;
}
}
}
if expr.starts_with("((") && expr.ends_with("))") {
match self.evaluate_arithmetic(&expr) {
Ok(value) => result.push_str(&value.to_string()), Ok(value) => result.push_str(&value.to_string()),
Err(e) => result.push_str(&format!("Error: {}", e)), Err(e) => result.push_str(&format!("Error: {}", e)),
} }
} else {
result.push('$');
result.push_str(&expr);
} }
} else { } else {
let var_name: String = chars let var_name: String = chars
@ -142,6 +157,9 @@ impl Interpreter {
result.push_str(value); result.push_str(value);
} else if let Ok(value) = env::var(&var_name) { } else if let Ok(value) = env::var(&var_name) {
result.push_str(&value); result.push_str(&value);
} else {
result.push('$');
result.push_str(&var_name);
} }
} }
} else { } else {
@ -151,34 +169,81 @@ impl Interpreter {
result result
} }
fn evaluate_arithmetic(&self, expr: &str) -> Result<i32, String> { pub fn evaluate_arithmetic(&self, expr: &str) -> Result<i32, String> {
let tokens: Vec<&str> = expr.split_whitespace().collect(); let expr = expr.trim();
if tokens.len() != 3 { let inner_expr = if expr.starts_with("$((") && expr.ends_with("))") {
return Err("Invalid arithmetic expression".to_string()); &expr[3..expr.len() - 2]
} else if expr.starts_with("((") && expr.ends_with("))") {
&expr[2..expr.len() - 2]
} else {
expr
};
// Handle parentheses
if inner_expr.contains('(') {
let mut depth = 0;
let mut start = 0;
for (i, c) in inner_expr.chars().enumerate() {
match c {
'(' => {
if depth == 0 {
start = i + 1;
}
depth += 1;
}
')' => {
depth -= 1;
if depth == 0 {
let sub_result = self.evaluate_arithmetic(&inner_expr[start..i])?;
let new_expr = format!(
"{} {} {}",
&inner_expr[..start - 1],
sub_result,
&inner_expr[i + 1..]
);
return self.evaluate_arithmetic(&new_expr);
}
}
_ => {}
}
}
} }
let a = self.get_var_value(tokens[0])?; // Split the expression into tokens
let b = self.get_var_value(tokens[2])?; let tokens: Vec<&str> = inner_expr.split_whitespace().collect();
match tokens[1] { // Handle single number or variable
"+" => Ok(a + b), if tokens.len() == 1 {
"-" => Ok(a - b), return self.get_var_value(tokens[0]);
"*" => Ok(a * b), }
"/" => {
if b != 0 { // Handle binary operations
Ok(a / b) if tokens.len() == 3 {
} else { let a = self.get_var_value(tokens[0])?;
Err("Division by zero".to_string()) let b = self.get_var_value(tokens[2])?;
match tokens[1] {
"+" => Ok(a + b),
"-" => Ok(a - b),
"*" => Ok(a * b),
"/" => {
if b != 0 {
Ok(a / b)
} else {
Err("Division by zero".to_string())
}
} }
} "%" => {
"%" => { if b != 0 {
if b != 0 { Ok(a % b)
Ok(a % b) } else {
} else { Err("Modulo by zero".to_string())
Err("Modulo by zero".to_string()) }
} }
_ => Err(format!("Unsupported operation: {}", tokens[1])),
} }
_ => Err(format!("Unsupported operation: {}", tokens[1])), } else {
Err("Invalid arithmetic expression".to_string())
} }
} }
@ -187,13 +252,10 @@ impl Interpreter {
value value
.parse() .parse()
.map_err(|_| format!("Invalid integer: {}", value)) .map_err(|_| format!("Invalid integer: {}", value))
} else if let Ok(value) = env::var(var) { } else if let Ok(value) = var.parse() {
value Ok(value)
.parse()
.map_err(|_| format!("Invalid integer: {}", value))
} else { } else {
var.parse() Err(format!("Undefined variable or invalid integer: {}", var))
.map_err(|_| format!("Invalid integer or undefined variable: {}", var))
} }
} }
} }