Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A12 Feature: Create If statements #20

Merged
merged 4 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions install.amber
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let tag = '1.0.0'
let place = '/opt/amber'
let url = 'https://github.com/Ph0enixKM/Amber/releases/download/{tag}/amber.zip'

$test -d "{place}"$
10 changes: 6 additions & 4 deletions out.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
a=12;
b=2;
a=$(echo $a '+' 12 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//');
echo ($(echo $a '+' $b | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'))
age=22;
if [ $(echo $age '>=' 18 | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//') != 0 ]; then
echo "You can drive"
else
echo "You cannot drive"
fi
3 changes: 2 additions & 1 deletion src/cli/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ impl CLI {
let mut meta = TranslateMetadata::new();
return format!("{}", block.translate(&mut meta));
}
return format!("[parsing err]")
}
format!("[err]")
format!("[lexing err]")
}

fn execute(&self, code: String) {
Expand Down
82 changes: 82 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,86 @@ mod tests {
";
assert_eq!(cli.test_eval(code).trim(), "");
}

#[test]
fn compare_eq_texts() {
let cli = CLI::new();
let code = "
let x = 'Hello World'
let y = 'Hello World'
$echo {x == y}$
";
assert_eq!(cli.test_eval(code).trim(), "1");
}

#[test]
fn compare_eq_numbers() {
let cli = CLI::new();
let code = "
let x = 42
let y = 42
$echo {x == y}$
";
assert_eq!(cli.test_eval(code).trim(), "1");
}

#[test]
fn compare_neq_numbers() {
let cli = CLI::new();
let code = "
let x = 42
let y = 24
$echo {x != y}$
";
assert_eq!(cli.test_eval(code).trim(), "1");
}

#[test]
fn if_statements() {
let cli = CLI::new();
let code = "
let x = 42
let y = 24
if x == y {
$echo {x}$
} else {
$echo {y}$
}
";
assert_eq!(cli.test_eval(code).trim(), "24");
}

#[test]
fn if_statements_else() {
let cli = CLI::new();
let code = "
let x = 42
let y = 24
if x == y {
$echo {x}$
}
else {
$echo {y}$
}
";
assert_eq!(cli.test_eval(code).trim(), "24");
}

#[test]
fn if_statement_chain() {
let cli = CLI::new();
let code = "
let x = 42
let y = 24
if {
x == y {
$echo {x}$
}
else {
$echo {y}$
}
}
";
assert_eq!(cli.test_eval(code).trim(), "24");
}
}
12 changes: 7 additions & 5 deletions src/modules/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ impl SyntaxModule<ParserMetadata> for Block {
continue;
}
// Handle comments
else if let Some(token) = meta.get_current_token() {
if token.word.starts_with("#") {
meta.increment_index();
continue
}
if token.word.starts_with("#") {
meta.increment_index();
continue
}
// Handle block end
else if token.word == "}" {
break;
}
}
None => break
Expand Down
81 changes: 81 additions & 0 deletions src/modules/conditions/ifchain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use heraclitus_compiler::prelude::*;
use crate::modules::expression::expr::Expr;
use crate::translate::module::TranslateModule;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::modules::block::Block;

#[derive(Debug)]
pub struct IfChain {
cond_blocks: Vec<(Expr, Block)>,
false_block: Option<Box<Block>>
}

impl SyntaxModule<ParserMetadata> for IfChain {
syntax_name!("If Condition");

fn new() -> Self {
IfChain {
cond_blocks: vec![],
false_block: None
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
let mut is_else = false;
token(meta, "if")?;
// Parse true block
token(meta, "{")?;
loop {
let mut cond = Expr::new();
let mut block = Block::new();
cond.cannot_fail();
// Handle else keyword
if let Ok(_) = token(meta, "else") {
is_else = true;
break;
}
// Handle end of the if chain
if let Err(_) = syntax(meta, &mut cond) {
println!("{:?}", meta.get_current_token());
break
}
token(meta, "{")?;
syntax(meta, &mut block)?;
token(meta, "}")?;
self.cond_blocks.push((cond, block));
}
// Parse false block
if is_else {
token(meta, "{")?;
let mut false_block = Box::new(Block::new());
syntax(meta, &mut *false_block)?;
self.false_block = Some(false_block);
token(meta, "}")?;
}
token(meta, "}")?;
Ok(())
}
}

impl TranslateModule for IfChain {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let mut result = vec![];
let mut is_first = true;
for (cond, block) in self.cond_blocks.iter() {
if is_first {
result.push(format!("if [ {} != 0 ]; then", cond.translate(meta)));
result.push(block.translate(meta));
is_first = false;
} else {
result.push(format!("elif [ {} != 0 ]; then", cond.translate(meta)));
result.push(block.translate(meta));
}
}
if let Some(false_block) = &self.false_block {
result.push(format!("else"));
result.push(false_block.translate(meta));
}
result.push(format!("fi"));
result.join("\n")
}
}
57 changes: 57 additions & 0 deletions src/modules/conditions/ifcond.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use heraclitus_compiler::prelude::*;
use crate::modules::expression::expr::Expr;
use crate::translate::module::TranslateModule;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::modules::block::Block;

#[derive(Debug)]
pub struct IfCondition {
expr: Box<Expr>,
true_block: Box<Block>,
false_block: Option<Box<Block>>
}

impl SyntaxModule<ParserMetadata> for IfCondition {
syntax_name!("If Condition");

fn new() -> Self {
IfCondition {
expr: Box::new(Expr::new()),
true_block: Box::new(Block::new()),
false_block: None
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
token(meta, "if")?;
// Parse expression
syntax(meta, &mut *self.expr)?;
// Parse true block
token(meta, "{")?;
syntax(meta, &mut *self.true_block)?;
token(meta, "}")?;
// Parse false block
if let Ok(_) = token(meta, "else") {
token(meta, "{")?;
let mut false_block = Box::new(Block::new());
syntax(meta, &mut *false_block)?;
self.false_block = Some(false_block);
token(meta, "}")?;
}
Ok(())
}
}

impl TranslateModule for IfCondition {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let mut result = vec![];
result.push(format!("if [ {} != 0 ]; then", self.expr.translate(meta)));
result.push(self.true_block.translate(meta));
if let Some(false_block) = &self.false_block {
result.push(format!("else"));
result.push(false_block.translate(meta));
}
result.push(format!("fi"));
result.join("\n")
}
}
2 changes: 2 additions & 0 deletions src/modules/conditions/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod ifcond;
pub mod ifchain;
7 changes: 6 additions & 1 deletion src/modules/expression/binop/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ impl TranslateModule for Eq {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let left = self.left.translate(meta);
let right = self.right.translate(meta);
translate_computation(meta, ArithOp::Eq, Some(left), Some(right))
// Handle text comparison
if self.left.get_type() == Type::Text && self.right.get_type() == Type::Text {
format!("$([ \"_{left}\" != \"_{right}\" ]; echo $?)")
} else {
translate_computation(meta, ArithOp::Eq, Some(left), Some(right))
}
}
}
4 changes: 2 additions & 2 deletions src/modules/expression/binop/ge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::translate::compute::{ArithOp, translate_computation};
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_same_type};
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_type};
use crate::modules::{Type, Typed};

#[derive(Debug)]
Expand Down Expand Up @@ -33,7 +33,7 @@ impl SyntaxModule<ParserMetadata> for Ge {
token(meta, ">=")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_same_type(meta, &self.left, &self.right, tok, error);
expression_arms_of_type(meta, &self.left, &self.right, Type::Num, tok, error);
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/modules/expression/binop/gt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::translate::compute::{ArithOp, translate_computation};
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_same_type};
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_type};
use crate::modules::{Type, Typed};

#[derive(Debug)]
Expand Down Expand Up @@ -33,7 +33,7 @@ impl SyntaxModule<ParserMetadata> for Gt {
token(meta, ">")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_same_type(meta, &self.left, &self.right, tok, error);
expression_arms_of_type(meta, &self.left, &self.right, Type::Num, tok, error);
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/modules/expression/binop/le.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::translate::compute::{ArithOp, translate_computation};
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_same_type};
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_type};
use crate::modules::{Type, Typed};

#[derive(Debug)]
Expand Down Expand Up @@ -33,7 +33,7 @@ impl SyntaxModule<ParserMetadata> for Le {
token(meta, "<=")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_same_type(meta, &self.left, &self.right, tok, error);
expression_arms_of_type(meta, &self.left, &self.right, Type::Num, tok, error);
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/modules/expression/binop/lt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::translate::compute::{translate_computation, ArithOp};
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_same_type};
use super::{super::expr::Expr, parse_left_expr, expression_arms_of_type};
use crate::modules::{Type, Typed};

#[derive(Debug)]
Expand Down Expand Up @@ -33,7 +33,7 @@ impl SyntaxModule<ParserMetadata> for Lt {
token(meta, "<")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_same_type(meta, &self.left, &self.right, tok, error);
expression_arms_of_type(meta, &self.left, &self.right, Type::Num, tok, error);
Ok(())
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/modules/expression/binop/neq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ impl TranslateModule for Neq {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let left = self.left.translate(meta);
let right = self.right.translate(meta);
translate_computation(meta, ArithOp::Neq, Some(left), Some(right))
if self.left.get_type() == Type::Text && self.right.get_type() == Type::Text {
format!("$([ \"_{left}\" == \"_{right}\" ]; echo $?)")
} else {
translate_computation(meta, ArithOp::Neq, Some(left), Some(right))
}
}
}
Loading