latest pushes
This commit is contained in:
parent
159fd823a7
commit
a4dfa81ed4
@ -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.
@ -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);
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
@ -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())?;
|
||||||
|
@ -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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user