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

A41 Feature: Add functions #30

Merged
merged 7 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion src/cli/cli_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl CLI {
cc.load(code.clone());
if let Ok(tokens) = cc.tokenize() {
let mut meta = ParserMetadata::new(tokens, path, Some(code));
if let Ok(()) = block.parse(&mut meta) {
if let Ok(()) = block.parse_debug(&mut meta) {
let mut meta = TranslateMetadata::new();
return block.translate(&mut meta);
}
Expand Down
17 changes: 11 additions & 6 deletions src/modules/block.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use heraclitus_compiler::prelude::*;
use crate::{utils::{metadata::ParserMetadata, error::get_error_logger, TranslateMetadata}};
use crate::translate::module::TranslateModule;
use super::statement::st::Statement;
use super::statement::stmt::Statement;

#[derive(Debug)]
pub struct Block {
Expand Down Expand Up @@ -35,7 +35,7 @@ impl SyntaxModule<ParserMetadata> for Block {
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
meta.var_mem.push_scope();
meta.mem.push_scope();
while let Some(token) = meta.get_current_token() {
// Handle the end of line or command
if ["\n", ";"].contains(&token.word.as_str()) {
Expand All @@ -57,15 +57,20 @@ impl SyntaxModule<ParserMetadata> for Block {
}
self.statements.push(statemant);
}
meta.var_mem.pop_scope();
meta.mem.pop_scope();
Ok(())
}
}

impl TranslateModule for Block {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
self.statements.iter()
.map(|module| module.translate(meta))
.collect::<Vec<_>>().join(";\n")
if self.is_empty() {
":".to_string()
}
else {
self.statements.iter()
.map(|module| module.translate(meta))
.collect::<Vec<_>>().join(";\n")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::modules::expression::expr::Expr;
use crate::translate::module::TranslateModule;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::modules::block::Block;
use crate::modules::statement::st::Statement;
use crate::modules::statement::stmt::Statement;

#[derive(Debug)]
pub struct IfChain {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::translate::module::TranslateModule;
use crate::utils::error::get_warn_logger;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::modules::block::Block;
use crate::modules::statement::st::{Statement, StatementType};
use crate::modules::statement::stmt::{Statement, StatementType};

#[derive(Debug)]
pub struct IfCondition {
Expand All @@ -14,14 +14,6 @@ pub struct IfCondition {
}

impl IfCondition {
fn translate_block(&self, meta: &mut TranslateMetadata, block: &Block) -> String {
if block.is_empty() {
":\n".to_string()
} else {
block.translate(meta)
}
}

fn prevent_not_using_if_chain(&self, meta: &mut ParserMetadata, statement: &Statement, tok: Option<Token>) {
let is_not_if_chain = matches!(statement.value.as_ref().unwrap(), StatementType::IfCondition(_) | StatementType::IfChain(_));
if is_not_if_chain {
Expand Down Expand Up @@ -90,10 +82,10 @@ 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.translate_block(meta, &self.true_block));
result.push(self.true_block.translate(meta));
if let Some(false_block) = &self.false_block {
result.push("else".to_string());
result.push(self.translate_block(meta, false_block));
result.push(false_block.translate(meta));
}
result.push("fi".to_string());
result.join("\n")
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion src/modules/expression/binop/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ impl SyntaxModule<ParserMetadata> for Add {
syntax(meta, &mut *self.right)?;
// If left and right are not of type Number
let error = "Add operation can only add numbers or text";
self.kind = expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num, Type::Text], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
self.kind = expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num, Type::Text], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ impl SyntaxModule<ParserMetadata> for Div {
token(meta, "/")?;
syntax(meta, &mut *self.right)?;
let error = "Divide operation can only divide numbers";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/ge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Ge {
token(meta, ">=")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/gt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Gt {
token(meta, ">")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/le.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Le {
token(meta, "<=")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/lt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Lt {
token(meta, "<")?;
syntax(meta, &mut *self.right)?;
let error = "Cannot compare two values of different types";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
10 changes: 3 additions & 7 deletions src/modules/expression/binop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,14 @@ pub mod le;
pub mod eq;
pub mod neq;

pub fn expression_arms_of_type<U, V>(meta: &mut ParserMetadata, left: &U, right: &V, kinds: &[Type], tok_pos: Option<Token>, message: &str) -> Type
where
U: Typed,
V: Typed,
{
if kinds.iter().all(|kind | ![left.get_type(), right.get_type()].iter().all(|item| item == kind)) {
pub fn expression_arms_of_type(meta: &mut ParserMetadata, left: &Type, right: &Type, kinds: &[Type], tok_pos: Option<Token>, message: &str) -> Type {
if kinds.iter().all(|kind | ![left, right].iter().all(|item| **item == *kind)) {
get_error_logger(meta, ErrorDetails::from_token_option(tok_pos))
.attach_message(message)
.show()
.exit()
}
left.get_type()
left.clone()
}

pub fn expression_arms_of_same_type(meta: &mut ParserMetadata, left: &Expr, right: &Expr, tok_pos: Option<Token>, message: &str) {
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/modulo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Modulo {
token(meta, "%")?;
syntax(meta, &mut *self.right)?;
let error = "Modulo operation can only be applied to numbers";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Mul {
token(meta, "*")?;
syntax(meta, &mut *self.right)?;
let error = "Multiply operation can only multiply numbers";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/expression/binop/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ impl SyntaxModule<ParserMetadata> for Sub {
token(meta, "-")?;
syntax(meta, &mut *self.right)?;
let error = "Substract operation can only substract numbers";
expression_arms_of_type(meta, &*self.left, &*self.right, &[Type::Num], tok, error);
let l_type = self.left.get_type();
let r_type = self.right.get_type();
expression_arms_of_type(meta, &l_type, &r_type, &[Type::Num], tok, error);
Ok(())
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/modules/expression/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ use super::unop::{
use super::parenthesis::Parenthesis;
use crate::modules::variable::get::VariableGet;
use crate::modules::command::expr::CommandExpr;
use crate::modules::conditions::ternary::Ternary;
use crate::modules::condition::ternary::Ternary;
use crate::modules::function::invocation::FunctionInvocation;
use crate::handle_types;

#[derive(Debug)]
Expand All @@ -54,7 +55,8 @@ pub enum ExprType {
Eq(Eq),
Neq(Neq),
Not(Not),
Ternary(Ternary)
Ternary(Ternary),
FunctionInvocation(FunctionInvocation)
}

#[derive(Debug)]
Expand Down Expand Up @@ -82,6 +84,9 @@ impl Expr {
Add, Sub, Mul, Div, Modulo,
// Literals
Parenthesis, CommandExpr, Bool, Number, Text,
// Function invocation
FunctionInvocation,
// Variable access
VariableGet
]);

Expand Down
76 changes: 76 additions & 0 deletions src/modules/function/declaration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use heraclitus_compiler::prelude::*;
use crate::modules::Type;
use crate::modules::variable::variable_name_extensions;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
use crate::modules::block::Block;

use super::{handle_existing_function, handle_add_function, skip_function_body};

#[derive(Debug)]
pub struct FunctionDeclaration {
pub name: String,
pub args: Vec<(String, Type)>,
pub returns: Type,
pub body: Block
}

impl SyntaxModule<ParserMetadata> for FunctionDeclaration {
syntax_name!("Function Declaration");

fn new() -> Self {
FunctionDeclaration {
name: String::new(),
args: vec![],
returns: Type::Generic,
body: Block::new()
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
token(meta, "fun")?;
// Get the function name
let tok = meta.get_current_token();
self.name = variable(meta, variable_name_extensions())?;
handle_existing_function(meta, tok.clone());
// Get the arguments
token(meta, "(")?;
while let Some(tok) = meta.get_current_token() {
if tok.word == ")" {
break;
}
let name = variable(meta, variable_name_extensions())?;
self.args.push((name, Type::Generic));
match token(meta, ")") {
Ok(_) => break,
Err(_) => token(meta, ",")?
};
}
// Parse the body
token(meta, "{")?;
let index_begin = meta.get_index();
skip_function_body(meta);
let index_end = meta.get_index();
token(meta, "}")?;
// Add the function to the memory
let body = meta.expr[index_begin..index_end].iter().cloned().collect::<Vec<Token>>();
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
handle_add_function(meta, &self.name, &self.args, self.returns.clone(), tok, body);
Ok(())
}
}

impl TranslateModule for FunctionDeclaration {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
// Increase indentation level
meta.increase_indent();
// Parse the function body
let mut result = vec![];
result.push(format!("function {} {{", self.name));
result.push(meta.gen_indent() + &self.body.translate(meta));
result.push("}".to_string());
// Decrease the indentation
meta.decrease_indent();
// Return the translation
result.join("\n")
}
}
66 changes: 66 additions & 0 deletions src/modules/function/invocation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use heraclitus_compiler::prelude::*;
use crate::modules::Type;
use crate::modules::variable::variable_name_extensions;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
use crate::modules::expression::expr::Expr;
use crate::modules::Typed;

use super::{handle_function_reference, handle_function_parameters};

#[derive(Debug)]
pub struct FunctionInvocation {
name: String,
args: Vec<Expr>,
kind: Type
}

impl Typed for FunctionInvocation {
fn get_type(&self) -> Type {
self.kind.clone()
}
}

impl SyntaxModule<ParserMetadata> for FunctionInvocation {
syntax_name!("Function Invocation");

fn new() -> Self {
FunctionInvocation {
name: String::new(),
args: vec![],
kind: Type::Null
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
// Get the function name
let tok = meta.get_current_token();
self.name = variable(meta, variable_name_extensions())?;
// Get the arguments
token(meta, "(")?;
handle_function_reference(meta, tok.clone(), &self.name);
Fixed Show fixed Hide fixed
while let Some(tok) = meta.get_current_token() {
if tok.word == ")" {
break;
}
let mut expr = Expr::new();
syntax(meta, &mut expr)?;
self.args.push(expr);
match token(meta, ")") {
Ok(_) => break,
Err(_) => token(meta, ",")?
};
}
let types = self.args.iter().map(|e| e.get_type()).collect::<Vec<Type>>();
self.kind = handle_function_parameters(meta, &self.name, &types);
Ok(())
}
}

impl TranslateModule for FunctionInvocation {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let name = self.name.clone();
let args = self.args.iter().map(|arg| arg.translate(meta)).collect::<Vec<String>>().join(" ");
format!("{name} {args}")
}
}
Loading