latest pushes

This commit is contained in:
Ronaldson Bellande 2024-10-15 22:47:29 -04:00
parent 8f087db1b8
commit 14e5a2043d
8 changed files with 246 additions and 280 deletions

View File

@ -21,7 +21,7 @@
# Usage of Bellande Rust Executable Builder # Usage of Bellande Rust Executable Builder
- https://github.com/Architecture-Mechanism/bellande_rust_executable - https://github.com/Architecture-Mechanism/bellande_rust_executable
- ```bellande_rust_executable -d dependencies.txt -s src -m bellos.rs -o executable/bellos``` - ```bellande_rust_executable -d dependencies.bellande -s src -m bellos.rs -o executable/bellos```
# Usage of Bellande Rust Importer # Usage of Bellande Rust Importer
- https://github.com/Architecture-Mechanism/bellande_importer - https://github.com/Architecture-Mechanism/bellande_importer
@ -37,7 +37,6 @@
``` ```
## Built-in Commands ## Built-in Commands
### Basic Commands ### Basic Commands
- **echo [args...]**: Print arguments to standard output. - **echo [args...]**: Print arguments to standard output.
- **cd [directory]**: Change the current working directory. - **cd [directory]**: Change the current working directory.

0
bellos_scripts/basic_math.bellos Normal file → Executable file
View File

View File

@ -1,54 +1,52 @@
#!/usr/bin/env bellos #!/usr/bin/env bellos
# File: control_structures.bellos # File: control_structures.bellos
# Demonstrating if statements and loops # Demonstrating if-else statements
echo "Demonstrating if-else statements:"
# If-else statement
echo "If-else statement:"
x=10 x=10
if [ $x -gt 5 ]; then If [ $x -gt 5 ] Then
echo "x is greater than 5" echo "x is greater than 5"
else Else
echo "x is not greater than 5" echo "x is not greater than 5"
fi Fi
# Nested if-else # Demonstrating nested if-else
echo "\nNested if-else:" echo "Demonstrating nested if-else:"
y=20 y=20
if [ $x -gt 5 ]; then If [ $x -gt 5 ] Then
if [ $y -gt 15 ]; then If [ $y -gt 15 ] Then
echo "x is greater than 5 and y is greater than 15" echo "x is greater than 5 and y is greater than 15"
else Else
echo "x is greater than 5 but y is not greater than 15" echo "x is greater than 5 but y is not greater than 15"
fi Fi
else Else
echo "x is not greater than 5" echo "x is not greater than 5"
fi Fi
# While loop # Demonstrating while loop
echo "\nWhile loop:" echo "Demonstrating while loop:"
counter=0 counter=0
while [ $counter -lt 5 ]; do While [ $counter -lt 5 ] Do
echo "Counter: $counter" echo "Counter: $counter"
counter=$((counter + 1)) counter=$((counter + 1))
done Done
# For loop # Demonstrating for loop
echo "\nFor loop:" echo "Demonstrating for loop:"
for i in 1 2 3 4 5; do For i In 1 2 3 4 5 Do
echo "Iteration: $i" echo "Iteration: $i"
done Done
# For loop with range # Demonstrating for loop with command substitution
echo "\nFor loop with range:" echo "Demonstrating for loop with command substitution:"
for i in $(seq 1 5); do For i In $(seq 1 5) Do
echo "Number: $i" echo "Number: $i"
done Done
# Case statement # Demonstrating case statement
echo "\nCase statement:" echo "Demonstrating case statement:"
fruit="apple" fruit="apple"
case $fruit in Case $fruit In
"apple") "apple")
echo "It's an apple" echo "It's an apple"
;; ;;
@ -61,4 +59,14 @@ case $fruit in
*) *)
echo "Unknown fruit" echo "Unknown fruit"
;; ;;
esac Esac
# Demonstrating function
echo "Demonstrating function:"
Function greet (
echo "Hello, $1!"
)
greet "World"
greet "Bellos"
echo "Control structures demonstration completed."

0
bellos_scripts/file_operations.bellos Normal file → Executable file
View File

65
bellos_scripts/string_manipulation.bellos Normal file → Executable file
View File

@ -1,37 +1,54 @@
#!/usr/bin/env bellos #!/usr/bin/env bellos
# File: string_manipulation.bellos # File: string_manipulation.bellos
# Demonstrating basic string manipulation in Bellos
# Demonstrating string manipulation # String assignment
echo "String assignment:"
# String concatenation
first_name=John first_name=John
last_name=Doe last_name=Doe
echo "first_name: $first_name"
echo "last_name: $last_name"
echo
# String concatenation
echo "String concatenation:"
full_name="$first_name $last_name" full_name="$first_name $last_name"
echo Full name: $full_name echo full_name: $full_name
echo
# String length # Using strings in commands
string="Hello, World!" echo "Using strings in commands:"
echo The string '$string' has ${#string} characters. greeting=Hello
echo "$greeting, $full_name!"
echo
# Substring extraction # Quoting strings
echo The first 5 characters are: ${string:0:5} echo "Quoting strings:"
# 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 With double quotes: "$sentence"
new_sentence=${sentence/fox/cat} echo With single quotes: '$sentence'
echo Modified sentence: $new_sentence echo
# Converting to uppercase and lowercase # Assigning command output to a variable
echo Uppercase: ${string^^} echo "Assigning command output to a variable:"
echo Lowercase: ${string,,} current_date=10-17-2025
echo "The current date is: $current_date"
echo
# Trimming whitespace # Escaping special characters
padded_string=" trim me " echo "Escaping special characters:"
echo Original string: '$padded_string' path=/home/user/documents
trimmed_string="${padded_string#"${padded_string%%[![:space:]]*}"}" # Trim leading whitespace echo "Path with slashes: $path"
trimmed_string="${trimmed_string%"${trimmed_string##*[![:space:]]}"}" # Trim trailing whitespace echo "Dollar sign: $100"
echo Trimmed string: '$trimmed_string' echo
# Using variables in paths
echo "Using variables in paths:"
username=johndoe
user_home=/home/$username
echo "User's home directory: $user_home"
echo
# Completion message # Completion message
echo String manipulation operations completed. echo "String manipulation operations completed."

Binary file not shown.

View File

@ -18,8 +18,6 @@ use crate::utilities::utilities::{ASTNode, Token};
pub struct Parser { pub struct Parser {
tokens: Vec<Token>, tokens: Vec<Token>,
position: usize, position: usize,
recursion_depth: usize,
max_recursion_depth: usize,
} }
impl Parser { impl Parser {
@ -27,199 +25,48 @@ impl Parser {
Parser { Parser {
tokens, tokens,
position: 0, position: 0,
recursion_depth: 0,
max_recursion_depth: 1000,
} }
} }
fn increment_recursion(&mut self) -> Result<(), String> {
self.recursion_depth += 1;
if self.recursion_depth > self.max_recursion_depth {
Err("Maximum recursion depth exceeded".to_string())
} else {
Ok(())
}
}
fn decrement_recursion(&mut self) {
self.recursion_depth -= 1;
}
pub fn parse(&mut self) -> Result<Vec<ASTNode>, String> { pub fn parse(&mut self) -> Result<Vec<ASTNode>, String> {
let mut nodes = Vec::new(); let mut nodes = Vec::new();
while self.position < self.tokens.len() { while self.position < self.tokens.len() {
self.skip_newlines();
if self.position >= self.tokens.len() {
break;
}
nodes.push(self.parse_statement()?); nodes.push(self.parse_statement()?);
self.consume_if(Token::Semicolon);
self.consume_if(Token::NewLine);
} }
Ok(nodes) Ok(nodes)
} }
fn parse_statement(&mut self) -> Result<ASTNode, String> { fn parse_statement(&mut self) -> Result<ASTNode, String> {
self.increment_recursion()?;
let result = if self.position >= self.tokens.len() {
Err("Unexpected end of input".to_string())
} else {
match &self.tokens[self.position] {
Token::Word(_) => self.parse_command_or_assignment(),
Token::LeftParen => self.parse_block(),
Token::If => self.parse_if(),
Token::While => self.parse_while(),
Token::For => self.parse_for(),
Token::Function => self.parse_function(),
_ => Err(format!(
"Unexpected token: {:?}",
self.tokens[self.position]
)),
}
};
self.decrement_recursion();
result
}
fn parse_command_or_assignment(&mut self) -> Result<ASTNode, String> {
let name = match &self.tokens[self.position] {
Token::Word(w) => w.clone(),
_ => {
return Err(format!(
"Expected word, found {:?}",
self.tokens[self.position]
))
}
};
self.position += 1;
if self.position < self.tokens.len() && self.tokens[self.position] == Token::Assignment {
self.position += 1;
let value = self.parse_expression()?;
Ok(ASTNode::Assignment { name, value })
} else {
let mut args = Vec::new();
while self.position < self.tokens.len()
&& !matches!(
self.tokens[self.position],
Token::Pipe
| Token::Redirect(_)
| Token::Semicolon
| Token::NewLine
| Token::Ampersand
| Token::Assignment
)
{
match &self.tokens[self.position] {
Token::Word(w) => args.push(w.clone()),
Token::String(s) => args.push(s.clone()),
_ => break,
}
self.position += 1;
}
let command = ASTNode::Command { name, args };
self.parse_pipeline_or_redirect(command)
}
}
fn parse_expression(&mut self) -> Result<String, String> {
let mut expression = String::new();
let mut paren_count = 0;
while self.position < self.tokens.len() {
match &self.tokens[self.position] {
Token::Word(w) => expression.push_str(w),
Token::String(s) => {
expression.push('"');
expression.push_str(s);
expression.push('"');
}
Token::LeftParen => {
expression.push('(');
paren_count += 1;
}
Token::RightParen if paren_count > 0 => {
expression.push(')');
paren_count -= 1;
}
Token::Semicolon | Token::NewLine if paren_count == 0 => break,
Token::Assignment => expression.push('='),
_ if paren_count == 0 => break,
_ => expression.push_str(&format!("{:?}", self.tokens[self.position])),
}
self.position += 1;
}
if paren_count != 0 {
return Err("Mismatched parentheses in expression".to_string());
}
Ok(expression)
}
fn parse_pipeline_or_redirect(&mut self, left: ASTNode) -> Result<ASTNode, String> {
if self.position >= self.tokens.len() { if self.position >= self.tokens.len() {
return Ok(left); return Err("Unexpected end of input".to_string());
} }
match &self.tokens[self.position] { match &self.tokens[self.position] {
Token::Pipe => { Token::Word(w) if w.eq_ignore_ascii_case("if") => self.parse_if(),
self.position += 1; Token::Word(w) if w.eq_ignore_ascii_case("while") => self.parse_while(),
let right = self.parse_command_or_assignment()?; Token::Word(w) if w.eq_ignore_ascii_case("for") => self.parse_for(),
let pipeline = ASTNode::Pipeline(vec![left, right]); Token::Word(w) if w.eq_ignore_ascii_case("case") => self.parse_case(),
self.parse_pipeline_or_redirect(pipeline) Token::Word(w) if w.eq_ignore_ascii_case("function") => self.parse_function(),
_ => self.parse_command_or_assignment(),
} }
Token::Redirect(direction) => {
self.position += 1;
let target = if self.position < self.tokens.len() {
match &self.tokens[self.position] {
Token::Word(w) => w.clone(),
Token::String(s) => s.clone(),
_ => {
return Err(format!(
"Expected word after redirect, found {:?}",
self.tokens[self.position]
))
}
}
} else {
return Err("Unexpected end of input after redirect".to_string());
};
self.position += 1;
let redirect = ASTNode::Redirect {
node: Box::new(left),
direction: direction.clone(),
target,
};
self.parse_pipeline_or_redirect(redirect)
}
Token::Ampersand => {
self.position += 1;
Ok(ASTNode::Background(Box::new(left)))
}
_ => Ok(left),
}
}
fn parse_block(&mut self) -> Result<ASTNode, String> {
self.position += 1; // Consume left paren
let mut statements = Vec::new();
while self.position < self.tokens.len() && self.tokens[self.position] != Token::RightParen {
statements.push(self.parse_statement()?);
self.consume_if(Token::Semicolon);
self.consume_if(Token::NewLine);
}
self.expect_token(Token::RightParen)?;
Ok(ASTNode::Block(statements))
} }
fn parse_if(&mut self) -> Result<ASTNode, String> { fn parse_if(&mut self) -> Result<ASTNode, String> {
self.position += 1; // Consume 'if' self.position += 1; // Consume 'if'
let condition = Box::new(self.parse_command()?); let condition = Box::new(self.parse_command()?);
self.expect_token(Token::Then)?; self.skip_newlines_and_expect("then")?;
let then_block = Box::new(self.parse_block()?); let then_block = Box::new(self.parse_block("else", "fi")?);
let else_block = if self.consume_if(Token::Else) { let else_block = if self.current_token_is("else") {
Some(Box::new(self.parse_block()?)) self.position += 1;
self.skip_newlines();
Some(Box::new(self.parse_block("fi", "fi")?))
} else { } else {
None None
}; };
self.expect_token(Token::Fi)?; self.skip_newlines_and_expect("fi")?;
Ok(ASTNode::If { Ok(ASTNode::If {
condition, condition,
then_block, then_block,
@ -230,65 +77,70 @@ impl Parser {
fn parse_while(&mut self) -> Result<ASTNode, String> { fn parse_while(&mut self) -> Result<ASTNode, String> {
self.position += 1; // Consume 'while' self.position += 1; // Consume 'while'
let condition = Box::new(self.parse_command()?); let condition = Box::new(self.parse_command()?);
self.expect_token(Token::Do)?; self.skip_newlines_and_expect("do")?;
let block = Box::new(self.parse_block()?); let block = Box::new(self.parse_block("done", "done")?);
self.expect_token(Token::Done)?; self.skip_newlines_and_expect("done")?;
Ok(ASTNode::While { condition, block }) Ok(ASTNode::While { condition, block })
} }
fn parse_for(&mut self) -> Result<ASTNode, String> { fn parse_for(&mut self) -> Result<ASTNode, String> {
self.position += 1; // Consume 'for' self.position += 1; // Consume 'for'
let var = match &self.tokens[self.position] { let var = self.expect_word()?;
Token::Word(w) => w.clone(), self.skip_newlines_and_expect("in")?;
_ => return Err("Expected variable name after 'for'".to_string()), let list = self.parse_list()?;
}; self.skip_newlines_and_expect("do")?;
self.position += 1; let block = Box::new(self.parse_block("done", "done")?);
self.expect_token(Token::In)?; self.skip_newlines_and_expect("done")?;
let mut list = Vec::new();
while self.position < self.tokens.len() && self.tokens[self.position] != Token::Do {
match &self.tokens[self.position] {
Token::Word(w) => list.push(w.clone()),
Token::String(s) => list.push(s.clone()),
_ => break,
}
self.position += 1;
}
self.expect_token(Token::Do)?;
let block = Box::new(self.parse_block()?);
self.expect_token(Token::Done)?;
Ok(ASTNode::For { var, list, block }) Ok(ASTNode::For { var, list, block })
} }
fn parse_case(&mut self) -> Result<ASTNode, String> {
self.position += 1; // Consume 'case'
let var = self.parse_expression()?;
self.skip_newlines_and_expect("in")?;
let mut cases = Vec::new();
while !self.current_token_is("esac") {
self.skip_newlines();
let pattern = self.parse_expression()?;
self.expect_token(&Token::RightParen)?;
let block = self.parse_block(";;", "esac")?;
cases.push((pattern, block));
self.skip_newlines();
if self.current_token_is(";;") {
self.position += 1;
}
}
self.skip_newlines_and_expect("esac")?;
Ok(ASTNode::Case { var, cases })
}
fn parse_function(&mut self) -> Result<ASTNode, String> { fn parse_function(&mut self) -> Result<ASTNode, String> {
self.position += 1; // Consume 'function' self.position += 1; // Consume 'function'
let name = match &self.tokens[self.position] { let name = self.expect_word()?;
Token::Word(w) => w.clone(), self.skip_newlines();
_ => { self.expect_token(&Token::LeftParen)?;
return Err(format!( self.skip_newlines();
"Expected function name, found {:?}", let body = Box::new(self.parse_block(")", ")")?);
self.tokens[self.position] self.expect_token(&Token::RightParen)?;
))
}
};
self.position += 1;
let body = Box::new(self.parse_block()?);
Ok(ASTNode::Function { name, body }) Ok(ASTNode::Function { name, body })
} }
fn parse_block(&mut self, end_token1: &str, end_token2: &str) -> Result<ASTNode, String> {
let mut statements = Vec::new();
while !self.current_token_is(end_token1) && !self.current_token_is(end_token2) {
self.skip_newlines();
if self.current_token_is(end_token1) || self.current_token_is(end_token2) {
break;
}
statements.push(self.parse_statement()?);
}
Ok(ASTNode::Block(statements))
}
fn parse_command(&mut self) -> Result<ASTNode, String> { fn parse_command(&mut self) -> Result<ASTNode, String> {
let mut args = Vec::new(); let mut args = Vec::new();
while self.position < self.tokens.len() while self.position < self.tokens.len() && !self.is_command_end() {
&& !matches!( args.push(self.expect_word()?);
self.tokens[self.position],
Token::Then | Token::Do | Token::Done | Token::Fi | Token::Else
)
{
match &self.tokens[self.position] {
Token::Word(w) => args.push(w.clone()),
Token::String(s) => args.push(s.clone()),
_ => break,
}
self.position += 1;
} }
if args.is_empty() { if args.is_empty() {
Err("Expected command".to_string()) Err("Expected command".to_string())
@ -300,25 +152,109 @@ impl Parser {
} }
} }
fn expect_token(&mut self, expected: Token) -> Result<(), String> { fn parse_list(&mut self) -> Result<Vec<String>, String> {
if self.position < self.tokens.len() && self.tokens[self.position] == expected { let mut list = Vec::new();
while !self.current_token_is("do") {
list.push(self.expect_word()?);
self.skip_newlines();
}
Ok(list)
}
fn parse_expression(&mut self) -> Result<String, String> {
self.expect_word()
}
fn expect_word(&mut self) -> Result<String, String> {
if self.position >= self.tokens.len() {
return Err("Unexpected end of input".to_string());
}
match &self.tokens[self.position] {
Token::Word(w) | Token::String(w) => {
self.position += 1;
Ok(w.clone())
}
_ => Err(format!(
"Expected word, found {:?}",
self.tokens[self.position]
)),
}
}
fn expect_token(&mut self, expected: &Token) -> Result<(), String> {
if self.position >= self.tokens.len() {
return Err(format!("Expected {:?}, found end of input", expected));
}
if self.tokens[self.position] == *expected {
self.position += 1; self.position += 1;
Ok(()) Ok(())
} else { } else {
Err(format!( Err(format!(
"Expected {:?}, found {:?}", "Expected {:?}, found {:?}",
expected, expected, self.tokens[self.position]
self.tokens.get(self.position).unwrap_or(&Token::NewLine)
)) ))
} }
} }
fn consume_if(&mut self, token: Token) -> bool { fn current_token_is(&self, token: &str) -> bool {
if self.position < self.tokens.len() && self.tokens[self.position] == token { if self.position >= self.tokens.len() {
return false;
}
match &self.tokens[self.position] {
Token::Word(w) => w.eq_ignore_ascii_case(token),
_ => false,
}
}
fn skip_newlines(&mut self) {
while self.position < self.tokens.len() && self.tokens[self.position] == Token::NewLine {
self.position += 1; self.position += 1;
true }
}
fn skip_newlines_and_expect(&mut self, expected: &str) -> Result<(), String> {
self.skip_newlines();
if self.position >= self.tokens.len() {
return Err(format!("Expected {}, found end of input", expected));
}
if self.current_token_is(expected) {
self.position += 1;
Ok(())
} else { } else {
false Err(format!(
"Expected {}, found {:?}",
expected, self.tokens[self.position]
))
}
}
fn is_command_end(&self) -> bool {
self.position >= self.tokens.len()
|| matches!(
self.tokens[self.position],
Token::Semicolon | Token::NewLine
)
|| self.current_token_is("then")
|| self.current_token_is("do")
|| self.current_token_is("done")
|| self.current_token_is("fi")
|| self.current_token_is("else")
|| self.current_token_is("elif")
|| self.current_token_is("esac")
}
fn parse_command_or_assignment(&mut self) -> Result<ASTNode, String> {
let name = self.expect_word()?;
if self.position < self.tokens.len() && self.tokens[self.position] == Token::Assignment {
self.position += 1;
let value = self.parse_expression()?;
Ok(ASTNode::Assignment { name, value })
} else {
let mut args = Vec::new();
while self.position < self.tokens.len() && !self.is_command_end() {
args.push(self.expect_word()?);
}
Ok(ASTNode::Command { name, args })
} }
} }
} }

View File

@ -34,6 +34,8 @@ pub enum Token {
Done, Done,
For, For,
In, In,
Case,
Esac,
Function, Function,
} }
@ -90,6 +92,10 @@ pub enum ASTNode {
body: Box<ASTNode>, body: Box<ASTNode>,
}, },
Background(Box<ASTNode>), Background(Box<ASTNode>),
Case {
var: String,
cases: Vec<(String, ASTNode)>,
},
} }
impl ASTNode { impl ASTNode {