├── CNAME ├── docs ├── logo.png ├── tutorial.gif ├── example.md ├── syntax.md ├── index.md └── bc2b.md ├── example ├── files.list ├── lib │ ├── Object.bc │ ├── Integer.bc │ ├── List.bc │ ├── Utils.bc │ └── String.bc └── input │ └── Tutorial.bc ├── .gitmodules ├── src ├── exception │ └── BException.cpp ├── scope │ ├── BElse.cpp │ ├── BFor.cpp │ ├── BElif.cpp │ ├── BWhile.cpp │ ├── BIf.cpp │ ├── BGlobal.cpp │ ├── BClass.cpp │ ├── BFunction.cpp │ └── BScope.cpp ├── type │ ├── BExpressionType.cpp │ ├── BElementType.cpp │ └── IBType.cpp ├── chain │ ├── BThisChainAccess.cpp │ ├── BSuperChainAccess.cpp │ ├── BVariableChainAccess.cpp │ ├── IBChainable.cpp │ ├── BTypeFactory.cpp │ ├── BFunctionChainCall.cpp │ └── BChain.cpp ├── expression │ ├── BArrayUse.cpp │ ├── BFunctionCall.cpp │ ├── BVariableAccess.cpp │ ├── BThisAccess.cpp │ ├── BTokenUse.cpp │ └── BArithOperation.cpp ├── bashclass │ ├── maindev.cpp │ └── mainpro.cpp ├── report │ └── BReport.cpp ├── components │ ├── BVariable.cpp │ └── BReturn.cpp └── code │ └── BGenerateCode.cpp ├── include └── bashclass │ ├── BConstructorChainCall.h │ ├── BSuperConstructorChainCall.h │ ├── BException.h │ ├── IBExpression.h │ ├── BElse.h │ ├── BArrayUse.h │ ├── BWhile.h │ ├── BSuperChainAccess.h │ ├── BThisAccess.h │ ├── BThisChainAccess.h │ ├── BFunctionCall.h │ ├── BVariableAccess.h │ ├── BTokenUse.h │ ├── BElif.h │ ├── BVariableChainAccess.h │ ├── BExpressionType.h │ ├── BTypeFactory.h │ ├── BGenerateCode.h │ ├── BReturn.h │ ├── BElementType.h │ ├── IBChainable.h │ ├── BReport.h │ ├── BIf.h │ ├── BFunctionChainCall.h │ ├── BFor.h │ ├── BGlobal.h │ ├── BChain.h │ ├── BClass.h │ ├── BVariable.h │ ├── BashClass.h │ ├── BFunction.h │ ├── BArithOperation.h │ ├── BBashHelper.h │ ├── IBType.h │ └── BScope.h ├── mkdocs.yml ├── README.md ├── resources └── src │ ├── lexical_errors.json │ ├── syntax_errors.json │ ├── lexical_config.json │ └── grammar.json ├── .travis.yml ├── CMakeLists.txt ├── Dockerfile ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── LICENSE /CNAME: -------------------------------------------------------------------------------- 1 | bashclass.com 2 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirbawab/BashClass/HEAD/docs/logo.png -------------------------------------------------------------------------------- /docs/tutorial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amirbawab/BashClass/HEAD/docs/tutorial.gif -------------------------------------------------------------------------------- /example/files.list: -------------------------------------------------------------------------------- 1 | input/Tutorial.bc 2 | lib/Integer.bc 3 | lib/List.bc 4 | lib/Object.bc 5 | lib/String.bc 6 | lib/Utils.bc 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "EasyCC-CPP"] 2 | path = thirdparty/EasyCC-CPP 3 | url = https://github.com/amirbawab/EasyCC-CPP 4 | branch = master 5 | -------------------------------------------------------------------------------- /src/exception/BException.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BException::BException(std::string message) : std::runtime_error(message + " -- Please report this error") {} -------------------------------------------------------------------------------- /src/scope/BElse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | std::stringstream BElse::getLabel() { 4 | std::stringstream stream = m_parentScope->getLabel(); 5 | stream << "_else_"; 6 | return stream; 7 | } -------------------------------------------------------------------------------- /include/bashclass/BConstructorChainCall.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BCONSTRUCTORCHAINCALL_H 2 | #define BASHCLASS_BCONSTRUCTORCHAINCALL_H 3 | 4 | #include 5 | 6 | class BConstructorChainCall : public BFunctionChainCall {}; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /example/lib/Object.bc: -------------------------------------------------------------------------------- 1 | /** 2 | * BashClass Library 3 | * Author: Amir Bawab 4 | */ 5 | class Object { 6 | constructor Object() {} 7 | function String type() { 8 | return new String(>$echo ${_object_[${_this_},"__type__"]}$<); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /include/bashclass/BSuperConstructorChainCall.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BSUPERCONSTRUCTORCHAINCALL_H 2 | #define BASHCLASS_BSUPERCONSTRUCTORCHAINCALL_H 3 | 4 | #include 5 | 6 | class BSuperConstructorChainCall : public BFunctionChainCall {}; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/bashclass/BException.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BEXCEPTION_H 2 | #define BASHCLASS_BEXCEPTION_H 3 | 4 | #include 5 | #include 6 | 7 | class BException : public std::runtime_error { 8 | public: 9 | BException(std::string message); 10 | }; 11 | 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/type/BExpressionType.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void BExpressionType::cast(std::shared_ptr type) { 5 | IBType::cast(type); 6 | m_typeName = type->getTypeName(); 7 | m_typeValue = type->getTypeValue(); 8 | } -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: 'BashClass' 2 | repo_url: 'https://github.com/amirbawab/BashClass' 3 | theme: 'readthedocs' 4 | site_description: 'BashClass documentation' 5 | pages: 6 | - 'Home': 'index.md' 7 | - 'BashClass to Bash': 'bc2b.md' 8 | - 'Syntax': 'syntax.md' 9 | - 'Example': 'example.md' 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![Build Status](https://travis-ci.org/amirbawab/BashClass.svg?branch=master)](https://travis-ci.org/amirbawab/BashClass) 2 | 3 | ## Documentation 4 | [Read the docs](https://amirbawab.github.io/BashClass/) 5 | 6 | ## Demo 7 | tutorial.gif 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/lib/Integer.bc: -------------------------------------------------------------------------------- 1 | /** 2 | * BashClass Library 3 | * Author: Amir Bawab 4 | */ 5 | class Integer extends Object { 6 | var int data; 7 | constructor Integer(var int data=0) { 8 | super_constructor(); 9 | this.data = data; 10 | } 11 | 12 | function void setInteger(var int data) { 13 | this.data = data; 14 | } 15 | 16 | function int getInteger(){ 17 | return data; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/chain/BThisChainAccess.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool BThisChainAccess::isFound() { 6 | return m_reference != nullptr; 7 | } 8 | 9 | std::shared_ptr BThisChainAccess::getType() { 10 | if(!m_reference) { 11 | return BTypeFactory::createUndefinedExpressionType(); 12 | } 13 | return BTypeFactory::createClassExpressionType(m_reference); 14 | } 15 | -------------------------------------------------------------------------------- /src/chain/BSuperChainAccess.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool BSuperChainAccess::isFound() { 5 | return m_srcReference && m_srcReference->getExtends(); 6 | } 7 | 8 | std::shared_ptr BSuperChainAccess::getType() { 9 | if(!isFound()) { 10 | return BTypeFactory::createUndefinedExpressionType(); 11 | } 12 | return BTypeFactory::createClassExpressionType(m_srcReference->getExtends()); 13 | } 14 | -------------------------------------------------------------------------------- /src/expression/BArrayUse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BArrayUse::BArrayUse() { 4 | m_type = std::make_shared(); 5 | } 6 | 7 | void BArrayUse::setTypeLexicalToken(std::shared_ptr lexicalToken) { 8 | 9 | // Set the type lexical token 10 | m_type->setLexicalToken(lexicalToken); 11 | 12 | // Link type 13 | m_type->linkType(); 14 | } 15 | 16 | void BArrayUse::castType(std::shared_ptr type) { 17 | m_type->cast(type); 18 | } -------------------------------------------------------------------------------- /include/bashclass/IBExpression.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_IBEXPRESSION_H 2 | #define BASHCLASS_IBEXPRESSION_H 3 | 4 | #include 5 | 6 | class IBExpression { 7 | public: 8 | 9 | /** 10 | * Get the type of the expression element 11 | * @return type value 12 | */ 13 | virtual std::shared_ptr getType()=0; 14 | 15 | /** 16 | * Cast type 17 | * @param type 18 | */ 19 | virtual void castType(std::shared_ptr type)=0; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/expression/BFunctionCall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::shared_ptr BFunctionCall::last() { 5 | if(!m_chain) { 6 | throw BException("Cannot get the last function chain call element before setting the chain"); 7 | } 8 | return std::static_pointer_cast(m_chain->last()); 9 | } 10 | 11 | std::shared_ptr BFunctionCall::getType() { 12 | return last()->getType(); 13 | } 14 | 15 | void BFunctionCall::castType(std::shared_ptr type) { 16 | last()->getType()->cast(type); 17 | } -------------------------------------------------------------------------------- /src/expression/BVariableAccess.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::shared_ptr BVariableAccess::last() { 5 | if(!m_chain) { 6 | throw BException("Cannot get the last variable chain access element before setting the chain"); 7 | } 8 | return std::static_pointer_cast(m_chain->last()); 9 | } 10 | 11 | 12 | std::shared_ptr BVariableAccess::getType() { 13 | return last()->getType(); 14 | } 15 | 16 | void BVariableAccess::castType(std::shared_ptr type) { 17 | last()->getType()->cast(type); 18 | } -------------------------------------------------------------------------------- /src/bashclass/maindev.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | 8 | // Create easycc developer mode 9 | std::shared_ptr easyccdev = std::make_shared(); 10 | 11 | // Create an easycc developer mode instance 12 | int code = easyccdev->init(argc, argv); 13 | if(code != ecc::EasyCC::OK_CODE) { 14 | return code; 15 | } 16 | 17 | // Create a bashclass 18 | BashClass bashClass(easyccdev); 19 | 20 | // Compile files 21 | return bashClass.compile(easyccdev->getInputFilesNames(), easyccdev->getOutputFileName()); 22 | } -------------------------------------------------------------------------------- /src/chain/BVariableChainAccess.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool BVariableChainAccess::isFound() { 7 | return m_variable != nullptr; 8 | } 9 | 10 | std::shared_ptr BVariableChainAccess::getType() { 11 | if(!m_variable || !m_variable->getType()->hasKnownType() || m_type->getDimension() < 0) { 12 | return BTypeFactory::createUndefinedExpressionType(); 13 | } 14 | return m_type; 15 | } 16 | 17 | void BVariableChainAccess::setVariable(std::shared_ptr variable) { 18 | m_variable = variable; 19 | m_type = variable->getType()->cloneToExpressionType(); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /include/bashclass/BElse.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BELSE_H 2 | #define BASHCLASS_BELSE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BElse : public BScope { 9 | private: 10 | // Parent if statement 11 | std::shared_ptr m_parentIf; 12 | public: 13 | /** 14 | * Get else label 15 | */ 16 | std::stringstream getLabel(); 17 | 18 | /** 19 | * Set parent if 20 | * @param parentIf 21 | */ 22 | void setParentIf(std::shared_ptr parentIf) {m_parentIf = parentIf;} 23 | 24 | /** 25 | * Get parent if 26 | * @return parent if 27 | */ 28 | std::shared_ptr getParentIf() {return m_parentIf;} 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /resources/src/lexical_errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_message": "${filename}: Error found: Token of value '${value}' found at line ${line} and column ${column}", 3 | "error_messages": { 4 | "error_comment_block" : "${filename}: Input reached end of file before closing block comment", 5 | "error_string" : "${filename}: Incomplete string found at line ${line}", 6 | "error_character" : "${filename}: Incomplete character found at line ${line}", 7 | "error_bash_block" : "${filename}: Input reached end of file before closing bash block", 8 | "error_bash_sub" : "${filename}: Input reached end of file before closing bash subshell", 9 | "error_invalid_character" : "${filename}: Invalid character '${value}' found at line ${line} and column ${column}" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/report/BReport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void BReport::printError() { 6 | std::cerr << m_errorStream.str(); 7 | m_errorStream.str(std::string()); 8 | m_errorStream.clear(); 9 | m_hasError = true; 10 | } 11 | 12 | std::stringstream& BReport::error() { 13 | m_errorStream << boost::filesystem::path(m_fileName).filename().c_str() << ": "; 14 | return m_errorStream; 15 | } 16 | 17 | BReport::~BReport() { 18 | 19 | // Get the size of the error stream 20 | m_errorStream.seekg(0, std::ios::end); 21 | long size = m_errorStream.tellg(); 22 | m_errorStream.seekg(0, std::ios::beg); 23 | 24 | // Don't terminate before flushing all error messages 25 | if(size != 0) { 26 | printError(); 27 | } 28 | } -------------------------------------------------------------------------------- /resources/src/syntax_errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_message": "${filename}: Error found: ${lexical.value} at line ${lexical.line} and column ${lexical.column}", 3 | "error_messages": [ 4 | { 5 | "non_terminal": ":any", 6 | "terminal": "$", 7 | "message": "${filename}: Unexpected end of file reached in input file" 8 | }, 9 | { 10 | "non_terminal" : "$", 11 | "terminal" : ":any", 12 | "message" : "${filename}: Expected end of file in input file" 13 | }, 14 | { 15 | "non_terminal" : "CLASS_NAME", 16 | "terminal" : ":any", 17 | "message" : "${filename}: Expected class name instead of '${lexical.value}' at line ${lexical.line} and column ${lexical.column}" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/scope/BFor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::stringstream BFor::getLabel() { 6 | std::stringstream stream = m_parentScope->getLabel(); 7 | stream << "_for_"; 8 | return stream; 9 | } 10 | 11 | void BFor::setCondition(std::shared_ptr expression) { 12 | // Set condition anw 13 | m_cond = expression; 14 | 15 | // Condition type must be boolean 16 | if(!expression->getType()->isBoolean()) { 17 | BReport::getInstance().error() 18 | << "A for statement condition should evaluate to a boolean" << std::endl; 19 | BReport::getInstance().printError(); 20 | } 21 | } 22 | 23 | std::shared_ptr BFor::findClosestFor() { 24 | return std::static_pointer_cast(shared_from_this()); 25 | } 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | compiler: 2 | - c++ 3 | 4 | sudo: required 5 | 6 | addons: 7 | apt: 8 | sources: 9 | - ubuntu-toolchain-r-test 10 | packages: 11 | - g++-5 12 | 13 | before_script: 14 | - sudo unlink /usr/bin/g++ 15 | - sudo ln -s /usr/bin/g++-5 /usr/bin/g++ 16 | - g++ --version 17 | - WORKSPACE=$PWD 18 | - sudo apt remove cmake 19 | - curl "https://cmake.org/files/v3.9/cmake-3.9.0-rc3.tar.gz" > /tmp/cmake.tar.gz 20 | - cd /tmp; tar -xf cmake.tar.gz; cd cmake-3.9.0-rc3/ 21 | - ./configure; make | tail -n50 22 | - sudo make install | tail -n50 23 | - curl -L "https://downloads.sourceforge.net/project/boost/boost/1.63.0/boost_1_63_0.tar.gz" > /tmp/boost.tar.gz 24 | - cd /tmp; tar -xf boost.tar.gz 25 | - cd boost_1_63_0/; ./bootstrap.sh --prefix=/usr/local | tail -n50 26 | - sudo ./b2 install 27 | - cd $WORKSPACE; cmake . 28 | 29 | script: make 30 | -------------------------------------------------------------------------------- /example/lib/List.bc: -------------------------------------------------------------------------------- 1 | /** 2 | * BashClass Library 3 | * Author: Amir Bawab 4 | */ 5 | class List extends Object { 6 | var Object[] data = new Object[]; 7 | var int size = 0; 8 | constructor List(){ 9 | super_constructor(); 10 | } 11 | 12 | function void add(var Object object) { 13 | data[size] = object; 14 | size = size + 1; 15 | } 16 | 17 | function void pop() { 18 | if(size == 0) { 19 | exception("Cannot remove element from an empty list"); 20 | } 21 | size = size - 1; 22 | data[size] = null; 23 | } 24 | 25 | function int size() { 26 | return size; 27 | } 28 | 29 | function Object get(var int index) { 30 | if(index < 0 || index >= size) { 31 | exception("Cannot access element out of bound"); 32 | } 33 | return data[index]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /include/bashclass/BArrayUse.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BARRAYUSE_H 2 | #define BASHCLASS_BARRAYUSE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BArrayUse : public IBExpression { 9 | private: 10 | 11 | // Hold the type of this array 12 | std::shared_ptr m_type; 13 | 14 | public: 15 | 16 | /** 17 | * Initialize members 18 | */ 19 | BArrayUse(); 20 | 21 | /** 22 | * Get type 23 | * @return type 24 | */ 25 | std::shared_ptr getType() {return m_type;} 26 | 27 | /** 28 | * Set type lexical token 29 | */ 30 | void setTypeLexicalToken(std::shared_ptr lexicalToken); 31 | 32 | /** 33 | * Cast type 34 | * @param type 35 | */ 36 | void castType(std::shared_ptr type); 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/components/BVariable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | BVariable::BVariable() { 5 | m_isParam = false; 6 | m_type = std::make_shared(); 7 | } 8 | 9 | std::stringstream BVariable::getLabel() { 10 | std::stringstream stream = m_parentScope->getLabel(); 11 | stream << (m_isParam ? "_p_" : "_v_") << m_name->getValue(); 12 | return stream; 13 | } 14 | 15 | bool BVariable::isClassMember() { 16 | if(!m_parentScope) { 17 | throw BException("Cannot check if a variable is a class member if it does not have a parent scope"); 18 | } 19 | return std::dynamic_pointer_cast(m_parentScope) != nullptr; 20 | } 21 | 22 | std::string BVariable::getDefaultValue() { 23 | if(!m_type) { 24 | throw BException("Cannot get initial value without setting the variable type"); 25 | } 26 | 27 | return "0"; 28 | } -------------------------------------------------------------------------------- /include/bashclass/BWhile.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BWHILE_H 2 | #define BASHCLASS_BWHILE_H 3 | 4 | #include 5 | #include 6 | 7 | class BWhile : public BScope { 8 | private: 9 | 10 | // Condition/Expression for this while statement 11 | std::shared_ptr m_expression; 12 | public: 13 | /** 14 | * Get while label 15 | */ 16 | std::stringstream getLabel(); 17 | 18 | /** 19 | * Get expression/condition 20 | * @return expression 21 | */ 22 | std::shared_ptr getExpression(){return m_expression;} 23 | 24 | /** 25 | * Set expression/condition 26 | * @param expression 27 | */ 28 | void setExpression(std::shared_ptr expression); 29 | 30 | /** 31 | * The closest while to this scope is this scope itself 32 | * @return this scope 33 | */ 34 | std::shared_ptr findClosestWhile(); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/bashclass/BSuperChainAccess.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BSUPERCHAINACCESS_H 2 | #define BASHCLASS_BSUPERCHAINACCESS_H 3 | 4 | #include 5 | 6 | class BSuperChainAccess : public IBChainable { 7 | private: 8 | // The source class from where the super is call 9 | std::shared_ptr m_srcReference; 10 | public: 11 | 12 | /** 13 | * Get reference class 14 | * @return reference 15 | */ 16 | std::shared_ptr getSrcReference() {return m_srcReference;} 17 | 18 | /** 19 | * Set reference class 20 | * @param reference 21 | */ 22 | void setSrcReference(std::shared_ptr reference) {m_srcReference = reference;} 23 | 24 | /** 25 | * Check if reference is found 26 | * @return true if found 27 | */ 28 | bool isFound(); 29 | 30 | /** 31 | * Get this reference type 32 | * @return type 33 | */ 34 | std::shared_ptr getType(); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/bashclass/BThisAccess.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BTHISACCESS_H 2 | #define BASHCLASS_BTHISACCESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BThisAccess : public IBExpression { 9 | private: 10 | 11 | // Hold chain which will contain only a this 12 | std::shared_ptr m_chain; 13 | public: 14 | 15 | /** 16 | * Set this chain access 17 | * @param chain 18 | */ 19 | void setChain(std::shared_ptr chain); 20 | 21 | /** 22 | * Get this chain access 23 | * @return thisChainAccess 24 | */ 25 | std::shared_ptr getThisChainAccess(); 26 | 27 | /** 28 | * Get type 29 | * @return type 30 | */ 31 | std::shared_ptr getType(); 32 | 33 | /** 34 | * Cannot cast this 35 | * @param type 36 | */ 37 | void castType(std::shared_ptr type); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/expression/BThisAccess.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void BThisAccess::setChain(std::shared_ptr chain) { 6 | if(chain->size() != 1) { 7 | throw BException("A 'this' access must contain exactly one 'this' element"); 8 | } 9 | m_chain = chain; 10 | } 11 | 12 | std::shared_ptr BThisAccess::getThisChainAccess() { 13 | if(m_chain->empty()) { 14 | throw BException("Requesting 'this' reference from an empty 'this' access chain"); 15 | } 16 | return std::static_pointer_cast(m_chain->last()); 17 | } 18 | 19 | std::shared_ptr BThisAccess::getType() { 20 | return getThisChainAccess()->getType(); 21 | } 22 | 23 | void BThisAccess::castType(std::shared_ptr type) { 24 | BReport::getInstance().error() 25 | << "Cannot cast a 'this' reference" << std::endl; 26 | BReport::getInstance().printError(); 27 | } -------------------------------------------------------------------------------- /src/code/BGenerateCode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void BGenerateCode::writePreCode(){ 7 | m_bashFile << "#!/bin/bash" << std::endl 8 | << "#" << std::endl 9 | << "# Bash version 4.4+ required!" << std::endl 10 | << "# This code is auto generated by bashc, do not make manual changes" << std::endl 11 | << "# -----------------------------------------------------------------" << std::endl; 12 | } 13 | 14 | void BGenerateCode::writePostCode() { 15 | m_bashFile << "# -----------------------------------------------------------------" << std::endl; 16 | } 17 | 18 | void BGenerateCode::write(std::stringstream &code) { 19 | m_bashFile << code.str(); 20 | } 21 | 22 | void BGenerateCode::openFile(std::string name) { 23 | m_bashFile.open(name); 24 | chmod(name.c_str(), S_IRWXU); 25 | } 26 | 27 | void BGenerateCode::closeFile() { 28 | m_bashFile.close(); 29 | } 30 | -------------------------------------------------------------------------------- /include/bashclass/BThisChainAccess.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BTHISCHAINACCESS_H 2 | #define BASHCLASS_BTHISCHAINACCESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BThisChainAccess : public IBChainable { 10 | private: 11 | 12 | // The class that this reference points to 13 | std::shared_ptr m_reference; 14 | public: 15 | 16 | /** 17 | * Get reference class 18 | * @return reference 19 | */ 20 | std::shared_ptr getReference() {return m_reference;} 21 | 22 | /** 23 | * Set reference class 24 | * @param reference 25 | */ 26 | void setReference(std::shared_ptr reference) {m_reference = reference;} 27 | 28 | /** 29 | * Check if reference is found 30 | * @return true if found 31 | */ 32 | bool isFound(); 33 | 34 | /** 35 | * Get this reference type 36 | * @return type 37 | */ 38 | std::shared_ptr getType(); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/bashclass/BFunctionCall.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BFUNCTIONCALL_H 2 | #define BASHCLASS_BFUNCTIONCALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BFunctionCall : public IBExpression { 9 | private: 10 | 11 | // Hold chain for the function call 12 | std::shared_ptr m_chain; 13 | public: 14 | 15 | /** 16 | * Get the last element in the chain 17 | * @return function chain call 18 | */ 19 | std::shared_ptr last(); 20 | 21 | /** 22 | * Get chain 23 | * @return chain 24 | */ 25 | std::shared_ptr getChain() { return m_chain;} 26 | 27 | /** 28 | * Set chain 29 | * @param chain 30 | */ 31 | void setChain(std::shared_ptr chain) {m_chain = chain;} 32 | 33 | /** 34 | * Get type 35 | * @return type 36 | */ 37 | std::shared_ptr getType(); 38 | 39 | /** 40 | * Cast type 41 | * @param type 42 | */ 43 | void castType(std::shared_ptr type); 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/scope/BElif.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | std::stringstream BElif::getLabel() { 8 | std::stringstream stream = m_parentScope->getLabel(); 9 | stream << "_elif_"; 10 | return stream; 11 | } 12 | 13 | void BElif::setExpression(std::shared_ptr expression) { 14 | 15 | // Store the condition/expression 16 | m_expression = expression; 17 | 18 | // Verify the type of the expression is boolean 19 | std::shared_ptr expressionType = expression->getType(); 20 | if(expressionType->isUndefined()) { 21 | BReport::getInstance().error() 22 | << "Elif statement condition cannot be of undefined type" << std::endl; 23 | BReport::getInstance().printError(); 24 | } else if(!expressionType->isBoolean()) { 25 | BReport::getInstance().error() 26 | << "An elif condition must evaluate to a boolean instead of " << expressionType << std::endl; 27 | BReport::getInstance().printError(); 28 | } 29 | } -------------------------------------------------------------------------------- /include/bashclass/BVariableAccess.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BVARIABLEACCESS_H 2 | #define BASHCLASS_BVARIABLEACCESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BVariableAccess : public IBExpression { 9 | private: 10 | 11 | // Hold chain for the variable access 12 | std::shared_ptr m_chain; 13 | public: 14 | 15 | /** 16 | * Get the last element in the chain which is of type variable chain access 17 | * @return variable chain access 18 | */ 19 | std::shared_ptr last(); 20 | 21 | /** 22 | * Get chain 23 | * @return chain 24 | */ 25 | std::shared_ptr getChain() {return m_chain;} 26 | 27 | /** 28 | * Set chain 29 | * @param chain 30 | */ 31 | void setChain(std::shared_ptr chain) { m_chain = chain;} 32 | 33 | /** 34 | * Get type 35 | * @return type 36 | */ 37 | std::shared_ptr getType(); 38 | 39 | /** 40 | * Cast type 41 | * @param type 42 | */ 43 | void castType(std::shared_ptr type); 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/bashclass/BTokenUse.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BTOKENUSE_H 2 | #define BASHCLASS_BTOKENUSE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BTokenUse : public IBExpression { 10 | private: 11 | 12 | // Lexical token corresponding to this instance 13 | std::shared_ptr m_lexicalToken; 14 | 15 | // Hold the type of the token 16 | std::shared_ptr m_type; 17 | public: 18 | 19 | /** 20 | * Get lexical token 21 | * @return lexical token 22 | */ 23 | std::shared_ptr getLexicalToken() const {return m_lexicalToken;} 24 | 25 | /** 26 | * Set lexical token 27 | * @param lexicalToken 28 | */ 29 | void setLexicalToken(std::shared_ptr lexicalToken); 30 | 31 | /** 32 | * Get token type 33 | * @return type 34 | */ 35 | std::shared_ptr getType() { return m_type;} 36 | 37 | /** 38 | * Cast type 39 | * @param type 40 | */ 41 | void castType(std::shared_ptr type); 42 | }; 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/bashclass/BElif.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BELIF_H 2 | #define BASHCLASS_BELIF_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BElif : public BScope { 9 | private: 10 | // Condition/Expression for this elif statement 11 | std::shared_ptr m_expression; 12 | 13 | // Parent if statement 14 | std::shared_ptr m_parentIf; 15 | public: 16 | /** 17 | * Get if label 18 | */ 19 | std::stringstream getLabel(); 20 | 21 | /** 22 | * Get expression/condition 23 | * @return expression 24 | */ 25 | std::shared_ptr getExpression() {return m_expression;} 26 | 27 | /** 28 | * Set expression/condition 29 | * @param expression 30 | */ 31 | void setExpression(std::shared_ptr expression); 32 | 33 | /** 34 | * Set parent if 35 | * @param parentIf 36 | */ 37 | void setParentIf(std::shared_ptr parentIf) {m_parentIf = parentIf;} 38 | 39 | /** 40 | * Get parent if 41 | * @return parent if 42 | */ 43 | std::shared_ptr getParentIf() {return m_parentIf;} 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/bashclass/BVariableChainAccess.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BVARIABLECHAINACCESS_H 2 | #define BASHCLASS_BVARIABLECHAINACCESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BVariableChainAccess : public IBChainable { 10 | private: 11 | 12 | // The variable this variable call refers to. 13 | // If this variable is not set, then the actual variable 14 | // was not found 15 | std::shared_ptr m_variable; 16 | 17 | // Hold the type of this variable access 18 | std::shared_ptr m_type; 19 | public: 20 | 21 | /** 22 | * Get variable 23 | * @return variable 24 | */ 25 | std::shared_ptr getVariable() { return m_variable;} 26 | 27 | /** 28 | * Set variable 29 | * @param variable 30 | */ 31 | void setVariable(std::shared_ptr variable); 32 | 33 | /** 34 | * Check if reference is found 35 | * @return true if found 36 | */ 37 | bool isFound(); 38 | 39 | /** 40 | * Get variable type 41 | * @return type 42 | */ 43 | std::shared_ptr getType(); 44 | }; 45 | 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /example/lib/Utils.bc: -------------------------------------------------------------------------------- 1 | /** 2 | * BashClass Library 3 | * Author: Amir Bawab 4 | */ 5 | function void printi(var int data) { 6 | ># echo -n -e "$1" 7 | } 8 | 9 | function void printiln(var int data) { 10 | printi(data); 11 | ># echo "" 12 | } 13 | 14 | function void printc(var char data) { 15 | ># echo -n -e "$1" 16 | } 17 | 18 | function void printcln(var char data) { 19 | printc(data); 20 | ># echo "" 21 | } 22 | 23 | function void prints(var String str) { 24 | var int i=0; 25 | while(i < str.length()) { 26 | printc(str.charAt(i)); 27 | i=i+1; 28 | } 29 | } 30 | 31 | function void printsln(var String str) { 32 | prints(str); 33 | ># echo "" 34 | } 35 | 36 | function void printcs(var char[] cstr) { 37 | prints(new String(cstr)); 38 | } 39 | 40 | function void printcsln(var char[] cstr) { 41 | printcs(cstr); 42 | ># echo "" 43 | } 44 | 45 | function void exception(var char[] message) { 46 | printcsln(message); 47 | ># exit 1 48 | } 49 | 50 | function String readStr() { 51 | ># declare _l_read_ 52 | return new String(>$read _l_read_; echo ${_l_read_}$<); 53 | } 54 | 55 | function String str(var char[] message) { 56 | return new String(message); 57 | } 58 | -------------------------------------------------------------------------------- /src/scope/BWhile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::stringstream BWhile::getLabel() { 7 | std::stringstream stream = m_parentScope->getLabel(); 8 | stream << "_while_"; 9 | return stream; 10 | } 11 | 12 | void BWhile::setExpression(std::shared_ptr expression) { 13 | 14 | // Store the condition/expression 15 | m_expression = expression; 16 | 17 | // Verify the type of the condition is boolean 18 | std::shared_ptr expressionType = expression->getType(); 19 | if(expressionType->isUndefined()) { 20 | BReport::getInstance().error() 21 | << "While statement condition cannot be of undefined type" << std::endl; 22 | BReport::getInstance().printError(); 23 | } else if(!expressionType->isBoolean()) { 24 | BReport::getInstance().error() 25 | << "A while condition must evaluate to a boolean instead of " << expressionType << std::endl; 26 | BReport::getInstance().printError(); 27 | } 28 | } 29 | 30 | std::shared_ptr BWhile::findClosestWhile() { 31 | return std::static_pointer_cast(shared_from_this()); 32 | } 33 | -------------------------------------------------------------------------------- /docs/example.md: -------------------------------------------------------------------------------- 1 | # Example project 2 | 3 | ## Demo 4 | tutorial.gif 5 | 6 | ## Project structure 7 | ``` 8 | example 9 | ├── files.list 10 | ├── input 11 | │   └── Tutorial.bc 12 | └── lib 13 |    ├── Integer.bc 14 |     ├── List.bc 15 |     ├── Object.bc 16 |     ├── String.bc 17 |     └── Utils.bc 18 | ``` 19 | * The `main` function is located in `Tutorial.bc` file. 20 | * Files in `libs/` contain data structures and helper functions. 21 | 22 | ## Prerequisite 23 | * Build BashClass. For more details check the [home page](../). 24 | 25 | ## Compile files 26 | ```bash 27 | cd example 28 | ../bin/bashc @files.list -o tutorial.sh 29 | ``` 30 | 31 | ## Run generated bash script 32 | ``` 33 | ./tutorial.sh "James" 34 | 35 | Hi, James 36 | Let's do some examples ... 37 | Want to do 'List' example? (y/n) 38 | > y 39 | Add items to a list. Type exit to stop. 40 | > Apple 41 | > Orange 42 | > exit 43 | Total number of items added to the list: 2 44 | Want to do 'Casting' example? (y/n) 45 | > y 46 | Adding the following two items to a list: 123, "Orange" 47 | Printing items: 48 | Item at index 0 is an Integer 49 | 123 50 | Item at index 1 is a String 51 | Orange 52 | Congratulations James! You've completed all the examples! 53 | Thank you for trying BashClass :) 54 | ``` 55 | -------------------------------------------------------------------------------- /include/bashclass/BExpressionType.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BEXPRESSIONTYPE_H 2 | #define BASHCLASS_BEXPRESSIONTYPE_H 3 | 4 | #include 5 | #include 6 | 7 | class BExpressionType : public IBType { 8 | private: 9 | 10 | // Hold type name 11 | std::string m_typeName; 12 | 13 | // Hold type value 14 | std::string m_typeValue; 15 | public: 16 | 17 | /** 18 | * Get type name 19 | * @return type name 20 | */ 21 | std::string getTypeName() {return m_typeName;} 22 | 23 | /** 24 | * Set type name 25 | * @param typeName 26 | */ 27 | void setTypeName(std::string typeName) { m_typeName = typeName;} 28 | 29 | /** 30 | * Get type value 31 | * @return type value 32 | */ 33 | std::string getTypeValue() { return m_typeValue; } 34 | 35 | /** 36 | * Set type value 37 | * @param typeValue 38 | */ 39 | void setTypeValue(std::string typeValue) { m_typeValue = typeValue;} 40 | 41 | /** 42 | * Set type scope 43 | * @param cls 44 | */ 45 | void setTypeScope(std::shared_ptr cls) { m_typeScope = cls;} 46 | 47 | /** 48 | * Cast type 49 | * @param type 50 | */ 51 | void cast(std::shared_ptr type); 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/bashclass/BTypeFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BTYPEFACTORY_H 2 | #define BASHCLASS_BTYPEFACTORY_H 3 | 4 | #include 5 | #include 6 | 7 | class BTypeFactory { 8 | public: 9 | 10 | /** 11 | * Create expression type 12 | * @param cls 13 | * @return expression type 14 | */ 15 | static std::shared_ptr createClassExpressionType(std::shared_ptr cls); 16 | 17 | /** 18 | * Create int expression type 19 | * @return expression type 20 | */ 21 | static std::shared_ptr createIntExpressionType(); 22 | 23 | /** 24 | * Create char expression type 25 | * @return expression type 26 | */ 27 | static std::shared_ptr createCharExpressionType(); 28 | 29 | /** 30 | * Create boolean expression type 31 | * @return expression type 32 | */ 33 | static std::shared_ptr createBooleanExpressionType(); 34 | 35 | /** 36 | * Create null expression type 37 | * @return expression type 38 | */ 39 | static std::shared_ptr createNullExpressionType(); 40 | 41 | /** 42 | * Create undefined expression type 43 | * @return expression type 44 | */ 45 | static std::shared_ptr createUndefinedExpressionType(); 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/bashclass/BGenerateCode.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BGENERATECODE_H 2 | #define BASHCLASS_BGENERATECODE_H 3 | 4 | #include 5 | #include 6 | 7 | class BGenerateCode { 8 | private: 9 | 10 | // Mark destructor as private 11 | BGenerateCode(){} 12 | 13 | // Output bash file 14 | std::ofstream m_bashFile; 15 | public: 16 | 17 | /** 18 | * Get singleton instance 19 | * @return singleton instance 20 | */ 21 | static BGenerateCode& get() { 22 | static BGenerateCode instance; 23 | return instance; 24 | } 25 | 26 | // Delete constructor and operator 27 | BGenerateCode(BGenerateCode const&) = delete; 28 | void operator=(BGenerateCode const&) = delete; 29 | 30 | /** 31 | * Create/Open the file to be written 32 | * @param name 33 | */ 34 | void openFile(std::string name); 35 | 36 | /** 37 | * Close file 38 | */ 39 | void closeFile(); 40 | 41 | /** 42 | * Code generated before parsing the input 43 | */ 44 | void writePreCode(); 45 | 46 | /** 47 | * Code generated after parsing the input 48 | */ 49 | void writePostCode(); 50 | 51 | /** 52 | * Write code 53 | * @param code 54 | */ 55 | void write(std::stringstream &code); 56 | }; 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/bashclass/BReturn.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BRETURN_H 2 | #define BASHCLASS_BRETURN_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BReturn { 9 | private: 10 | 11 | // Expression assigned to this return statement 12 | std::shared_ptr m_expression; 13 | 14 | // Set the parent scope of this return statement 15 | std::shared_ptr m_parentScope; 16 | public: 17 | 18 | /** 19 | * Set return statement expression 20 | * @param return statement expression 21 | */ 22 | void setExpression(std::shared_ptr expression) {m_expression = expression;} 23 | 24 | /** 25 | * Get return statement expression 26 | * @return return statement expression 27 | */ 28 | std::shared_ptr getExpression(){return m_expression;} 29 | 30 | /** 31 | * Verify return 32 | */ 33 | void verifyReturn(); 34 | 35 | /** 36 | * Set parent scope 37 | * @param parentScope 38 | */ 39 | void setParentScope(std::shared_ptr parentScope) {m_parentScope = parentScope;} 40 | 41 | /** 42 | * Get parent scope 43 | * @return parent scope 44 | */ 45 | std::shared_ptr getParentScope() {return m_parentScope;} 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(bashclass) 3 | set(CMAKE_VERBOSE_MAKEFILE ON) 4 | set(BASH_PROJECT_DEV_EXEC "bashcdev") 5 | set(BASH_PROJECT_PRO_EXEC "bashc") 6 | 7 | # Add easycc CMakeLists.txt to build it automatically 8 | add_subdirectory(thirdparty/EasyCC-CPP) 9 | 10 | # Compile with -std=c++11 flag 11 | add_compile_options(-std=c++11) 12 | 13 | # Configure directory of output file 14 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 15 | 16 | # Include bashc header files (e.g. same as -I flag) 17 | include_directories(include) 18 | include_directories(thirdparty/EasyCC-CPP/include) 19 | include_directories(thirdparty/EasyCC-CPP/thirdparty/rapidjson/include) 20 | 21 | # Store cpp files in a variable 22 | file(GLOB_RECURSE BASH_PROJECT_SOURCE_FILES src/*/*.cpp) 23 | list(REMOVE_ITEM BASH_PROJECT_SOURCE_FILES 24 | "${PROJECT_SOURCE_DIR}/src/bashclass/maindev.cpp" 25 | "${PROJECT_SOURCE_DIR}/src/bashclass/mainpro.cpp") 26 | 27 | # Add the executables 28 | add_executable(${BASH_PROJECT_DEV_EXEC} ${BASH_PROJECT_SOURCE_FILES} src/bashclass/maindev.cpp) 29 | add_executable(${BASH_PROJECT_PRO_EXEC} ${BASH_PROJECT_SOURCE_FILES} src/bashclass/mainpro.cpp) 30 | 31 | # Link library to the executable 32 | target_link_libraries(${BASH_PROJECT_DEV_EXEC} easyccdev) 33 | target_link_libraries(${BASH_PROJECT_PRO_EXEC} easyccpro) 34 | -------------------------------------------------------------------------------- /resources/src/lexical_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "newline": "LF", 3 | 4 | "ignore": { 5 | "prefix": "comment_", 6 | "suffix": "", 7 | "include": [], 8 | "exclude": [] 9 | }, 10 | 11 | "error": { 12 | "prefix": "error_", 13 | "suffix": "", 14 | "include": [], 15 | "exclude": [] 16 | }, 17 | 18 | "reserved": { 19 | "identifier": { 20 | "if" : "if", 21 | "elif" : "elif", 22 | "else" : "else", 23 | "while" : "while", 24 | "for" : "for", 25 | "function" : "function", 26 | "class" : "class", 27 | "extends": "extends", 28 | "var" : "var", 29 | "return" : "return", 30 | "int" : "int_type", 31 | "void" : "void_type", 32 | "char" : "char_type", 33 | "boolean" : "boolean_type", 34 | "true" : "truefalse", 35 | "false" : "truefalse", 36 | "this" : "this_ref", 37 | "new": "new", 38 | "break": "break", 39 | "continue": "continue", 40 | "constructor": "constructor", 41 | "super": "super", 42 | "super_constructor": "super_constructor", 43 | "null": "null", 44 | "undefined": "null" 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /include/bashclass/BElementType.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BELEMENTTYPE_H 2 | #define BASHCLASS_BELEMENTTYPE_H 3 | 4 | #include 5 | #include 6 | 7 | class BElementType : public IBType { 8 | private: 9 | 10 | // Hold lexical token 11 | std::shared_ptr m_lexicalToken; 12 | public: 13 | 14 | /** 15 | * Get lexical ltoken 16 | * @return lexical token 17 | */ 18 | std::shared_ptr getLexicalToken() {return m_lexicalToken;} 19 | 20 | /** 21 | * Set lexical token 22 | * @param lexicalToken 23 | */ 24 | void setLexicalToken(std::shared_ptr lexicalToken) { m_lexicalToken = lexicalToken; } 25 | 26 | /** 27 | * Get type name 28 | * @return type name 29 | */ 30 | std::string getTypeName(); 31 | 32 | /** 33 | * Get type value 34 | * @return type value 35 | */ 36 | std::string getTypeValue(); 37 | 38 | /** 39 | * Link type 40 | */ 41 | void linkType(); 42 | 43 | /** 44 | * Create a clone of this element type into expression type 45 | * @return expression type 46 | */ 47 | std::shared_ptr cloneToExpressionType(); 48 | 49 | /** 50 | * Cast type 51 | * @param type 52 | */ 53 | void cast(std::shared_ptr type); 54 | }; 55 | #endif 56 | -------------------------------------------------------------------------------- /include/bashclass/IBChainable.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_IBCHAINABLE_H 2 | #define BASHCLASS_IBCHAINABLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class IBChainable { 10 | protected: 11 | 12 | // Hold the integer indices 13 | std::vector> m_indices; 14 | 15 | // Lexical token for the chainable item 16 | std::shared_ptr m_lexicalToken; 17 | public: 18 | 19 | /** 20 | * Check if the element is known 21 | * @return true if the element is recognized 22 | */ 23 | virtual bool isFound()=0; 24 | 25 | /** 26 | * Get the type of the chainable element 27 | * @return type 28 | */ 29 | virtual std::shared_ptr getType()=0; 30 | 31 | /** 32 | * Add index 33 | * @param expression 34 | */ 35 | void addIndex(std::shared_ptr expression); 36 | 37 | /** 38 | * Get lexical token 39 | * @return lexicalToken 40 | */ 41 | std::shared_ptr getLexicalToken() {return m_lexicalToken;} 42 | 43 | /** 44 | * Set lexical token 45 | * @param lexicalToken 46 | */ 47 | void setLexicalToken(std::shared_ptr lexicalToken) { m_lexicalToken = lexicalToken;} 48 | 49 | /** 50 | * Get indices 51 | * @return indices 52 | */ 53 | std::vector> getIndices() const { return m_indices;} 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/expression/BTokenUse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void BTokenUse::setLexicalToken(std::shared_ptr lexicalToken) { 6 | 7 | // Set lexical token 8 | m_lexicalToken = lexicalToken; 9 | 10 | // Configure expression type based no the lexical token data 11 | if(m_lexicalToken->getName() == IBType::DATA_TYPE_NAME_INT 12 | || m_lexicalToken->getName() == IBType::DATA_TYPE_NAME_BASH_SUB_INT) { 13 | m_type = BTypeFactory::createIntExpressionType(); 14 | 15 | } else if(m_lexicalToken->getName() == IBType::DATA_TYPE_NAME_STRING 16 | || m_lexicalToken->getName() == IBType::DATA_TYPE_NAME_BASH_SUB) { 17 | 18 | // A string is a char[] 19 | m_type = BTypeFactory::createCharExpressionType(); 20 | m_type->setDimension(1); 21 | 22 | } else if(m_lexicalToken->getName() == IBType::DATA_TYPE_NAME_CHAR) { 23 | m_type = BTypeFactory::createCharExpressionType(); 24 | 25 | } else if(m_lexicalToken->getName() == IBType::DATA_TYPE_NAME_BOOLEAN) { 26 | m_type = BTypeFactory::createBooleanExpressionType(); 27 | 28 | } else if(m_lexicalToken->getName() == IBType::NULL_VALUE) { 29 | m_type = BTypeFactory::createNullExpressionType(); 30 | 31 | } else { 32 | throw BException("Token type value cannot be undefined"); 33 | } 34 | } 35 | 36 | void BTokenUse::castType(std::shared_ptr type) { 37 | m_type->cast(type); 38 | } 39 | -------------------------------------------------------------------------------- /src/scope/BIf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::stringstream BIf::getLabel() { 9 | std::stringstream stream = m_parentScope->getLabel(); 10 | stream << "_if_"; 11 | return stream; 12 | } 13 | 14 | void BIf::setExpression(std::shared_ptr expression) { 15 | 16 | // Store the condition/expression 17 | m_expression = expression; 18 | 19 | // Verify the type of the expression is boolean 20 | std::shared_ptr expressionType = expression->getType(); 21 | if(expressionType->isUndefined()) { 22 | BReport::getInstance().error() 23 | << "If statement condition cannot be of undefined type" << std::endl; 24 | BReport::getInstance().printError(); 25 | } else if(!expressionType->isBoolean()) { 26 | BReport::getInstance().error() 27 | << "An if condition must evaluate to a boolean instead of " << expressionType << std::endl; 28 | BReport::getInstance().printError(); 29 | } 30 | } 31 | 32 | void BIf::addElif(std::shared_ptr elifScope) { 33 | m_elifScopes.push_back(elifScope); 34 | elifScope->setParentIf(std::static_pointer_cast(shared_from_this())); 35 | } 36 | 37 | void BIf::setElse(std::shared_ptr elseScope) { 38 | m_elseScope = elseScope; 39 | // TODO Test casting 40 | elseScope->setParentIf(std::static_pointer_cast(shared_from_this())); 41 | } -------------------------------------------------------------------------------- /include/bashclass/BReport.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BREPORT_H 2 | #define BASHCLASS_BREPORT_H 3 | 4 | #include 5 | 6 | class BReport { 7 | private: 8 | 9 | // Hold messages 10 | std::stringstream m_errorStream; 11 | 12 | // Any error changes the value of this flag to true 13 | bool m_hasError; 14 | 15 | // Make constructor private 16 | BReport() : m_hasError(false){} 17 | 18 | // Hold temporary file name 19 | // This file name correspond to the one currently 20 | // being processed by the semantic analyzer 21 | std::string m_fileName; 22 | public: 23 | 24 | // Delete constructor and operator 25 | BReport(BReport const&) = delete; 26 | void operator=(BReport const&) = delete; 27 | 28 | /** 29 | * Flush buffer 30 | */ 31 | ~BReport(); 32 | 33 | /** 34 | * Get singleton instance 35 | * @return singleton instance 36 | */ 37 | static BReport& getInstance() { 38 | static BReport instance; 39 | return instance; 40 | } 41 | 42 | /** 43 | * Set file name currently being processed 44 | * @param fileName 45 | */ 46 | void setFileName(std::string fileName) { m_fileName = fileName; } 47 | 48 | /** 49 | * Print error message 50 | */ 51 | void printError(); 52 | 53 | /** 54 | * Store the error message 55 | * @return 56 | */ 57 | std::stringstream& error(); 58 | 59 | /** 60 | * Check if an error was reported 61 | * @return true if an error was reported 62 | */ 63 | bool hasError() {return m_hasError;} 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /include/bashclass/BIf.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BIF_H 2 | #define BASHCLASS_BIF_H 3 | 4 | #include 5 | #include 6 | 7 | class BElif; 8 | class BElse; 9 | class BIf : public BScope { 10 | private: 11 | // Condition/Expression for this if statement 12 | std::shared_ptr m_expression; 13 | 14 | // Elif scopes in order 15 | std::vector> m_elifScopes; 16 | 17 | // Else scope for this if statement 18 | std::shared_ptr m_elseScope; 19 | public: 20 | /** 21 | * Get if label 22 | */ 23 | std::stringstream getLabel(); 24 | 25 | /** 26 | * Get expression/condition 27 | * @return expression 28 | */ 29 | std::shared_ptr getExpression() {return m_expression;} 30 | 31 | /** 32 | * Set expression/condition 33 | * @param expression 34 | */ 35 | void setExpression(std::shared_ptr expression); 36 | 37 | /** 38 | * Add elif scope 39 | * @param elifScope 40 | */ 41 | void addElif(std::shared_ptr elifScope); 42 | 43 | /** 44 | * Get elif scopes in the order of insertion 45 | * @return elif scopes 46 | */ 47 | const std::vector>& getElifScopes() const { return m_elifScopes; } 48 | 49 | /** 50 | * Set the else scope 51 | * @param elseScope 52 | */ 53 | void setElse(std::shared_ptr elseScope); 54 | 55 | /** 56 | * Get the else scope 57 | * @return else scope 58 | */ 59 | std::shared_ptr getElse() {return m_elseScope;} 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/bashclass/BFunctionChainCall.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BFUNCTIONCHAINCALL_H 2 | #define BASHCLASS_BFUNCTIONCHAINCALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class BFunctionChainCall : public IBChainable { 11 | private: 12 | 13 | // The function this function chain call refers to. 14 | // If this variable is not set, then the actual function 15 | // was not found 16 | std::shared_ptr m_function; 17 | 18 | // Arguments passed to this function chain call 19 | std::vector> m_arguments; 20 | 21 | // Hold the type of this function access 22 | std::shared_ptr m_type; 23 | public: 24 | 25 | /** 26 | * Get function 27 | * @return function 28 | */ 29 | std::shared_ptr getFunction() {return m_function;} 30 | 31 | /** 32 | * Set function 33 | * @param function 34 | */ 35 | void setFunction(std::shared_ptr function); 36 | 37 | /** 38 | * Add argument 39 | * @param argument 40 | */ 41 | void addArgument(std::shared_ptr argument); 42 | 43 | /** 44 | * Get arguments 45 | * @return arguments 46 | */ 47 | std::vector> getArguments() const { return m_arguments;}; 48 | 49 | /** 50 | * Argument number should match the number of parameters 51 | */ 52 | void verifyArguments(); 53 | 54 | /** 55 | * Check if reference found 56 | * @return true if found 57 | */ 58 | bool isFound(); 59 | 60 | /** 61 | * Get type 62 | * @return type 63 | */ 64 | std::shared_ptr getType(); 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /include/bashclass/BFor.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BFOR_H 2 | #define BASHCLASS_BFOR_H 3 | 4 | #include 5 | 6 | class BFor : public BScope { 7 | private: 8 | 9 | // Hold expression to execute initially 10 | std::shared_ptr m_preCond; 11 | 12 | // Hold condition of the for loop 13 | std::shared_ptr m_cond; 14 | 15 | // Hold expression to execute at the end of each iteration 16 | std::shared_ptr m_postCond; 17 | 18 | public: 19 | 20 | /** 21 | * Get for label 22 | * @return label 23 | */ 24 | std::stringstream getLabel(); 25 | 26 | /** 27 | * Get pre condition 28 | * @return pre condition 29 | */ 30 | std::shared_ptr getPreCondition() { return m_preCond;} 31 | 32 | /** 33 | * Set condition 34 | * @param expression 35 | */ 36 | void setPreCondition(std::shared_ptr expression) { m_preCond = expression;} 37 | 38 | /** 39 | * Get condition 40 | * @return condition 41 | */ 42 | std::shared_ptr getCondition() { return m_cond;} 43 | 44 | /** 45 | * Set condition 46 | * @param expression 47 | */ 48 | void setCondition(std::shared_ptr expression); 49 | 50 | /** 51 | * Get post condition 52 | * @return post condition 53 | */ 54 | std::shared_ptr getPostCondition() { return m_postCond;} 55 | 56 | /** 57 | * Set post condition 58 | * @param expression 59 | */ 60 | void setPostCondition( std::shared_ptr expression) { m_postCond = expression;} 61 | 62 | /** 63 | * The closest for to this scope is this scope itself 64 | * @return this scope 65 | */ 66 | std::shared_ptr findClosestFor(); 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/type/BElementType.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::string BElementType::getTypeValue() { 7 | if(!m_lexicalToken) { 8 | throw BException("Cannot get type value of lexical token that was not set"); 9 | } 10 | return m_lexicalToken->getValue(); 11 | } 12 | 13 | std::string BElementType::getTypeName() { 14 | if(!m_lexicalToken) { 15 | throw BException("Cannot get type name of lexical token that was not set"); 16 | } 17 | return m_lexicalToken->getName(); 18 | } 19 | 20 | void BElementType::linkType() { 21 | 22 | // Link type iff the type is an identifier 23 | if(isIdentifier()) { 24 | // Find class scope of that type 25 | auto cls = BGlobal::getInstance()->findAllClasses(m_lexicalToken->getValue().c_str()); 26 | if(cls.empty()) { 27 | BReport::getInstance().error() 28 | << "Undefined type " << m_lexicalToken->getValue() 29 | << " at line " << m_lexicalToken->getLine() 30 | << " and column " << m_lexicalToken->getColumn() 31 | << std::endl; 32 | BReport::getInstance().printError(); 33 | } else { 34 | m_typeScope = cls.front(); 35 | } 36 | } 37 | } 38 | 39 | std::shared_ptr BElementType::cloneToExpressionType() { 40 | auto newType = std::make_shared(); 41 | newType->setDimension(getDimension()); 42 | newType->setTypeName(getTypeName()); 43 | newType->setTypeValue(getTypeValue()); 44 | newType->setTypeScope(getTypeScope()); 45 | return newType; 46 | } 47 | 48 | void BElementType::cast(std::shared_ptr type) { 49 | IBType::cast(type); 50 | m_lexicalToken = type->getLexicalToken(); 51 | } -------------------------------------------------------------------------------- /include/bashclass/BGlobal.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BGLOBAL_H 2 | #define BASHCLASS_BGLOBAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BGlobal : public BScope { 9 | private: 10 | 11 | // Disable constructor 12 | BGlobal(){} 13 | public: 14 | 15 | // Set main function name 16 | static const std::string MAIN_FUNCTION; 17 | 18 | /** 19 | * Get single instance of this class 20 | * @return pointer to a singleton instance 21 | */ 22 | static std::shared_ptr getInstance() { 23 | static std::shared_ptr instance(new BGlobal()); 24 | return instance; 25 | } 26 | 27 | // Delete constructor and operator 28 | BGlobal(BGlobal const&) = delete; 29 | void operator=(BGlobal const&) = delete; 30 | 31 | /** 32 | * Get global label 33 | */ 34 | std::stringstream getLabel(); 35 | 36 | /** 37 | * Link extended classes and types of classes 38 | */ 39 | void link(); 40 | 41 | /** 42 | * There is no ancestor function scope for a global scope 43 | * @return nullptr 44 | */ 45 | std::shared_ptr findClosestFunction() {return nullptr;} 46 | 47 | /** 48 | * There is no ancestor class scope for a global scope 49 | * @return nullptr 50 | */ 51 | std::shared_ptr findClosestClass() {return nullptr;} 52 | 53 | /** 54 | * There is no ancestor while loop scope for a global scope 55 | * @return nullptr 56 | */ 57 | std::shared_ptr findClosestWhile() {return nullptr;} 58 | 59 | /** 60 | * There is no ancestor for loop scope for a global scope 61 | * @return nullptr 62 | */ 63 | std::shared_ptr findClosestFor() {return nullptr;} 64 | 65 | /** 66 | * Verify that the main function exists in the global scope 67 | */ 68 | void verifyMain(); 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/chain/IBChainable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void IBChainable::addIndex(std::shared_ptr expression) { 5 | 6 | // Add expression 7 | m_indices.push_back(expression); 8 | 9 | // Update type dimension 10 | if(!getType()->isUndefined()) { 11 | getType()->setDimension(getType()->getDimension()-1); 12 | } 13 | 14 | if(!isFound()) { 15 | BReport::getInstance().error() 16 | << "Index expression " << m_indices.size() << " cannot be accessed for element " 17 | << m_lexicalToken->getValue() 18 | << " at line " << m_lexicalToken->getLine() 19 | << " and column " << m_lexicalToken->getColumn() 20 | << " because the element is not found" 21 | << std::endl; 22 | BReport::getInstance().printError(); 23 | 24 | } else if(getType()->isUndefined()) { 25 | BReport::getInstance().error() 26 | << "Index expression " << m_indices.size() << " cannot be verified for element " 27 | << m_lexicalToken->getValue() 28 | << " at line " << m_lexicalToken->getLine() 29 | << " and column " << m_lexicalToken->getColumn() 30 | << " because the element is of an undefined type" 31 | << std::endl; 32 | BReport::getInstance().printError(); 33 | } 34 | 35 | // Check if the expression is of type integer 36 | if(!expression->getType()->isInt()) { 37 | BReport::getInstance().error() 38 | << "Index expression " << m_indices.size() 39 | << " must evaluate to an integer for element " << m_lexicalToken->getValue() 40 | << " at line " << m_lexicalToken->getLine() 41 | << " and column " << m_lexicalToken->getColumn() 42 | << std::endl; 43 | BReport::getInstance().printError(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | ENV HOME /root 3 | 4 | # Intall required packages 5 | RUN apt-get update 6 | RUN apt-get install -y git curl wget 7 | RUN apt-get install -y g++ make 8 | 9 | # Install cmake 10 | RUN curl "https://cmake.org/files/v3.9/cmake-3.9.0-rc3.tar.gz" > /tmp/cmake.tar.gz 11 | RUN cd /tmp; tar -xf cmake.tar.gz 12 | WORKDIR "/tmp/cmake-3.9.0-rc3" 13 | RUN ./configure; make; make install 14 | 15 | # Install boost 16 | RUN curl -L "https://downloads.sourceforge.net/project/boost/boost/1.63.0/boost_1_63_0.tar.gz" > /tmp/boost.tar.gz 17 | RUN cd /tmp; tar -xf boost.tar.gz 18 | WORKDIR "/tmp/boost_1_63_0/" 19 | RUN ./bootstrap.sh --prefix=/usr/local; ./b2 install 20 | 21 | # Install BASH4.4 22 | RUN curl -L "http://ftp.gnu.org/gnu/bash/bash-4.4.tar.gz" > /tmp/bash-4.4.tar.gz 23 | RUN cd /tmp; tar -xf bash-4.4.tar.gz 24 | WORKDIR /tmp/bash-4.4 25 | RUN ./configure; make; make install 26 | RUN mv /bin/bash /bin/bash.old 27 | RUN ln -s /usr/local/bin/bash /bin/bash 28 | 29 | # Install BashClass 30 | RUN cd $HOME; git clone https://github.com/amirbawab/BashClass 31 | WORKDIR $HOME/BashClass 32 | RUN git submodule update --init --recursive 33 | RUN cmake . -DSYNTAX_ERRORS="${PWD}/resources/src/syntax_errors.json"\ 34 | -DSYNTAX_GRAMMAR="${PWD}/resources/src/grammar.json" \ 35 | -DLEXICAL_ERRORS="${PWD}/resources/src/lexical_errors.json"\ 36 | -DLEXICAL_CONFIG="${PWD}/resources/src/lexical_config.json"\ 37 | -DLEXICAL_STATE_MACHINE="${PWD}/resources/src/lexical_graph.json" 38 | RUN make bashcdev 39 | RUN make generate_files 40 | RUN cmake . -DSYNTAX_ERRORS="${PWD}/resources/src/syntax_errors.json" \ 41 | -DSYNTAX_GRAMMAR="${PWD}/resources/src/grammar.json" \ 42 | -DLEXICAL_ERRORS="${PWD}/resources/src/lexical_errors.json"\ 43 | -DLEXICAL_CONFIG="${PWD}/resources/src/lexical_config.json"\ 44 | -DLEXICAL_STATE_MACHINE="${PWD}/resources/src/lexical_graph.json" 45 | RUN make bashc 46 | 47 | CMD /bin/bash 48 | -------------------------------------------------------------------------------- /example/lib/String.bc: -------------------------------------------------------------------------------- 1 | /** 2 | * BashClass Library 3 | * Author: Amir Bawab 4 | */ 5 | class String extends Object { 6 | var char[] data; 7 | constructor String(var char[] data) { 8 | super_constructor(); 9 | this.data = data; 10 | } 11 | 12 | function int length() { 13 | ># declare -n _l_array_="_array_${_object_[${_this_},_c_String_v_data]}" 14 | return >% echo ${#_l_array_[@]}%<; 15 | } 16 | 17 | function char charAt(var int index) { 18 | if(index < 0 || index >= length()) { 19 | exception("Cannot access index out of bound"); 20 | } 21 | return data[index]; 22 | } 23 | 24 | function String substr(var int fromIndex, var int len) { 25 | if(fromIndex < 0) { 26 | exception("Substring cannot start from a negative index"); 27 | } 28 | 29 | if(len < 0) { 30 | exception("Substring length cannot be negative"); 31 | } 32 | 33 | if(fromIndex + len > length()) { 34 | exception("Substring index out of bound"); 35 | } 36 | 37 | var char[] subArray = new char[]; 38 | var int i; 39 | var int si=0; 40 | for(i=fromIndex; i < fromIndex + len; i=i+1) { 41 | subArray[si] = data[i]; 42 | si = si + 1; 43 | } 44 | return new String(subArray); 45 | } 46 | 47 | function String append(var String str) { 48 | var char[] newArray = new char[]; 49 | var int i; 50 | var int ni=0; 51 | for(i=0; i < length(); i=i+1) { 52 | newArray[ni] = charAt(i); 53 | ni = ni+1; 54 | } 55 | for(i=0; i < str.length(); i=i+1) { 56 | newArray[ni] = str.charAt(i); 57 | ni = ni+1; 58 | } 59 | return new String(newArray); 60 | } 61 | 62 | function boolean equals(var String str) { 63 | if(length() != str.length()) { 64 | return false; 65 | } 66 | 67 | var int i=0; 68 | while(i < length()) { 69 | if(charAt(i) != str.charAt(i)) { 70 | return false; 71 | } 72 | i=i+1; 73 | } 74 | return true; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/chain/BTypeFactory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // TODO Make the the returned pointers static, so each time the same instance is returned (except for custom ones) 5 | 6 | std::shared_ptr BTypeFactory::createClassExpressionType(std::shared_ptr cls) { 7 | std::shared_ptr expressionType = std::make_shared(); 8 | expressionType->setTypeName(cls->getName()->getName()); 9 | expressionType->setTypeValue(cls->getName()->getValue()); 10 | expressionType->setTypeScope(cls); 11 | return expressionType; 12 | } 13 | 14 | std::shared_ptr BTypeFactory::createIntExpressionType() { 15 | std::shared_ptr expressionType = std::make_shared(); 16 | expressionType->setTypeName(IBType::TYPE_NAME_INT); 17 | expressionType->setTypeValue(IBType::TYPE_VALUE_INT); 18 | return expressionType; 19 | } 20 | 21 | std::shared_ptr BTypeFactory::createCharExpressionType() { 22 | std::shared_ptr expressionType = std::make_shared(); 23 | expressionType->setTypeName(IBType::TYPE_NAME_CHAR); 24 | expressionType->setTypeValue(IBType::TYPE_VALUE_CHAR); 25 | return expressionType; 26 | } 27 | 28 | std::shared_ptr BTypeFactory::createNullExpressionType() { 29 | std::shared_ptr expressionType = std::make_shared(); 30 | expressionType->setTypeName(IBType::NULL_VALUE); 31 | expressionType->setTypeValue(IBType::NULL_VALUE); 32 | return expressionType; 33 | } 34 | 35 | std::shared_ptr BTypeFactory::createBooleanExpressionType() { 36 | std::shared_ptr expressionType = std::make_shared(); 37 | expressionType->setTypeName(IBType::TYPE_NAME_BOOLEAN); 38 | expressionType->setTypeValue(IBType::TYPE_VALUE_BOOLEAN); 39 | return expressionType; 40 | } 41 | 42 | std::shared_ptr BTypeFactory::createUndefinedExpressionType() { 43 | std::shared_ptr expressionType = std::make_shared(); 44 | expressionType->setTypeName(IBType::UNDEFINED); 45 | expressionType->setTypeValue(IBType::UNDEFINED); 46 | return expressionType; 47 | } 48 | -------------------------------------------------------------------------------- /docs/syntax.md: -------------------------------------------------------------------------------- 1 | ## Variable 2 | ``` 3 | var int id; 4 | ``` 5 | * Variable must have a type. 6 | * Variable can be initialized when declared. 7 | 8 | ## Function 9 | ``` 10 | function void myFunction(var int arg1=0) { 11 | // body 12 | } 13 | ``` 14 | * Function must have a type. 15 | * Parameters can have default values. 16 | * Each program must have a `main` function of type `int` with: 17 | * No parameters, or 18 | * `var int argc, var char[][] argv` 19 | 20 | ## For loop 21 | ``` 22 | var int i; 23 | for(i=0; i < 10; i=i+1) { 24 | // body 25 | } 26 | ``` 27 | * The counter must be declared before the for loop statement. 28 | 29 | ## While loop 30 | ``` 31 | while(true) { 32 | // body 33 | } 34 | ``` 35 | 36 | ## If, Elif and Else 37 | ``` 38 | if(condition1) { 39 | // body1 40 | } elif( condition2) { 41 | // body2 42 | } else { 43 | // body3 44 | } 45 | ``` 46 | 47 | ## Class 48 | ``` 49 | class MyClass { 50 | constructor MyClass() { 51 | // body 52 | } 53 | // functions and variables 54 | } 55 | ``` 56 | * One constructor function is required for each class and must share the class name. 57 | * A class can have [functions](#funtion) and [variables](#variable). 58 | * All class members for instances are accessible. 59 | 60 | ## Inheritance 61 | ``` 62 | class Child extends Parent { 63 | constructor Child() { 64 | super_constructor(); 65 | // body 66 | } 67 | } 68 | ``` 69 | * Parent constructor must be called from child constructor 70 | 71 | ## Arrays 72 | ``` 73 | var MyClass[] data = new MyClass[]; 74 | ``` 75 | * Multi-dimensional arrays are created similarly 76 | 77 | ## Casting 78 | ``` 79 | var int fakeInt = ('a'):int; 80 | ``` 81 | * Variable `fakeInt` will not convert `a` to its corresponding ascii number, instead it will just trick the compiler to think it holds an `int`. 82 | * Casting to wrong types might lead to an undefined behavior (example above). 83 | 84 | ## Bash code 85 | ### Inline bash script 86 | ``` 87 | ># echo Hello world 88 | ``` 89 | 90 | ### Block of bash script 91 | ``` 92 | >@ 93 | echo Hello 94 | echo World 95 | @< 96 | ``` 97 | 98 | ### Subshell char[] 99 | ``` 100 | var char[] helloWorld = >$echo hello world$<; 101 | ``` 102 | * Equivalent to: `helloWorld="$(echo hello world)"` 103 | 104 | ### Subshell int 105 | ``` 106 | var int one = >%echo 1%<; 107 | ``` 108 | * Equivalent to: `one="$(echo 1)"` 109 | -------------------------------------------------------------------------------- /include/bashclass/BChain.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BCHAIN_H 2 | #define BASHCLASS_BCHAIN_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class BChain { 12 | private: 13 | 14 | // Vector containing 'this' references, variables and functions calls 15 | // in their order of insertion. 16 | // e.g. a.b().c.d() => [a,b(),c,d()] 17 | std::vector> m_callables; 18 | public: 19 | 20 | /** 21 | * Get chain size 22 | * @return size 23 | */ 24 | size_t size() { 25 | return m_callables.size(); 26 | } 27 | 28 | /** 29 | * Get callable element at the provided index 30 | * @param index 31 | * @return callable item 32 | */ 33 | std::shared_ptr operator[](int index); 34 | 35 | /** 36 | * Check if chain is empty 37 | * @return true if empty 38 | */ 39 | bool empty() { 40 | return m_callables.empty(); 41 | } 42 | 43 | /** 44 | * Get the last element or throw an exception 45 | * @return last 46 | */ 47 | std::shared_ptr last(); 48 | 49 | /** 50 | * Add variable to the chain 51 | * @param scope 52 | * @param token 53 | */ 54 | void addVariable(std::shared_ptr scope, std::shared_ptr token); 55 | 56 | /** 57 | * Add function to the chain 58 | * @param scope 59 | * @param token 60 | */ 61 | void addFunction(std::shared_ptr scope, std::shared_ptr token); 62 | 63 | /** 64 | * Add constructor to the chain 65 | * @param scope 66 | * @param token 67 | */ 68 | void addConstructor(std::shared_ptr scope, std::shared_ptr token); 69 | 70 | /** 71 | * Add super constructor to the chain 72 | * @param scope 73 | * @param token 74 | */ 75 | void addSuperConstructor(std::shared_ptr scope, std::shared_ptr token); 76 | 77 | /** 78 | * Add this reference to the chain 79 | * @param scope 80 | * @param thisReference 81 | */ 82 | void addThis(std::shared_ptr scope, std::shared_ptr thisReference); 83 | 84 | /** 85 | * Add super reference to the chain 86 | * @param scope 87 | * @param superReference 88 | */ 89 | void addSuper(std::shared_ptr scope, std::shared_ptr superReference); 90 | }; 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/components/BReturn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void BReturn::verifyReturn() { 6 | 7 | if(!m_parentScope) { 8 | throw BException("Cannot verify a return statement without a parent scope"); 9 | } 10 | 11 | // Get ancestor function 12 | auto function = m_parentScope->findClosestFunction(); 13 | if(!function) { 14 | throw BException("Cannot verify a return statement without a function"); 15 | } 16 | 17 | // If function is of type void, then a return statement is not expected 18 | if(function->requiresReturn()) { 19 | 20 | // A function that requires a return statement 21 | // must only have return statements with expressions 22 | if(!m_expression) { 23 | BReport::getInstance().error() 24 | << "Function " << function->getName()->getValue() << " expects a return statement with expression" 25 | << std::endl; 26 | BReport::getInstance().printError(); 27 | } else { 28 | 29 | std::shared_ptr functionType = function->getType(); 30 | std::shared_ptr expressionType = m_expression->getType(); 31 | 32 | if(!function->getType()->hasKnownType()) { 33 | BReport::getInstance().error() 34 | << "Cannot return expression in function " << function->getName()->getValue() 35 | << " of undefined type" << std::endl; 36 | BReport::getInstance().printError(); 37 | } else if(expressionType->isUndefined()) { 38 | BReport::getInstance().error() 39 | << "Function " << function->getName()->getValue() 40 | << " has return statement but of undefined type" << std::endl; 41 | BReport::getInstance().printError(); 42 | } else if(!functionType->isCompatible(expressionType)) { 43 | BReport::getInstance().error() 44 | << "Function " << function->getName()->getValue() << " is of type " << functionType->toString() 45 | << " but return expression is of type " << expressionType->toString() << std::endl; 46 | BReport::getInstance().printError(); 47 | } 48 | } 49 | } else if (m_expression) { 50 | BReport::getInstance().error() 51 | << "Function " << function->getName()->getValue() 52 | << " does not expect to return an expression" << std::endl; 53 | BReport::getInstance().printError(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/bashclass/mainpro.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // Output file 8 | std::string outputFile; 9 | 10 | // Input files 11 | std::vector inputFiles; 12 | 13 | /** 14 | * Print help message 15 | */ 16 | void printUsage() { 17 | std::cout 18 | << "bashc - Compiler converting BashClass syntax into bash 4.4+" << std::endl 19 | << "Usage: bashc [OPTION]... [FILE]..." << std::endl 20 | << "\t-o, --output\t\t\tOutput file" << std::endl 21 | << "\t-h, --help\t\t\tDisplay this help message" << std::endl; 22 | } 23 | 24 | /** 25 | * Initialize parameter 26 | * @param argc 27 | * @param argv 28 | */ 29 | void initParams(int argc, char *argv[]) { 30 | 31 | struct option longOptions[] = { 32 | {"output", required_argument, 0, 'o'}, 33 | {"help", no_argument, 0, 'h'}, 34 | {0, 0, 0, 0} 35 | }; 36 | 37 | int optionIndex = 0; 38 | int c; 39 | while ((c = getopt_long(argc, argv, "ho:", longOptions, &optionIndex)) != -1) { 40 | switch (c) { 41 | case 'o': 42 | outputFile = optarg; 43 | break; 44 | case 'h': 45 | default: 46 | // Print by default 47 | break; 48 | } 49 | } 50 | } 51 | 52 | int main(int argc, char *argv[]) { 53 | 54 | // Initialize parameters 55 | initParams(argc, argv); 56 | 57 | // Fetch files names 58 | for(int i = optind; i < argc; ++i) { 59 | std::string fileName = argv[i]; 60 | if(!fileName.empty()) { 61 | 62 | // Check if it's a file containing a list of files names 63 | if(fileName.front() == '@') { 64 | 65 | // Open file starting from the second character 66 | std::ifstream input(fileName.substr(1)); 67 | 68 | // Add all lines in that file 69 | for( std::string line; getline( input, line ); ) { 70 | inputFiles.push_back(line); 71 | } 72 | 73 | // Close file 74 | input.close(); 75 | } else { 76 | inputFiles.push_back(fileName); 77 | } 78 | } 79 | } 80 | 81 | // Check missing requirements 82 | if(outputFile.empty() || inputFiles.empty()) { 83 | printUsage(); 84 | return ecc::EasyCC::ERR_CODE_PARAMS; 85 | } 86 | 87 | // Create easycc production mode 88 | std::shared_ptr easyccpro = std::make_shared(); 89 | 90 | // Create a bashclass 91 | BashClass bashClass(easyccpro); 92 | 93 | // Compile files 94 | return bashClass.compile(inputFiles, outputFile); 95 | } 96 | -------------------------------------------------------------------------------- /include/bashclass/BClass.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BCLASS_H 2 | #define BASHCLASS_BCLASS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BClass : public BScope { 9 | private: 10 | 11 | // Class name 12 | std::shared_ptr m_name; 13 | 14 | // Parent class lexical token 15 | std::shared_ptr m_extendsName; 16 | 17 | // Parent class 18 | std::shared_ptr m_extends; 19 | public: 20 | /** 21 | * Get name lexical token 22 | * @return token pointer 23 | */ 24 | std::shared_ptr getName() const { return m_name;} 25 | 26 | /** 27 | * Set name lexical token 28 | * @param name 29 | */ 30 | void setName(std::shared_ptr name) {m_name = name;} 31 | 32 | /** 33 | * Get class label 34 | */ 35 | std::stringstream getLabel(); 36 | 37 | /** 38 | * The closest class to this scope is this scope itself 39 | * @return this scope 40 | */ 41 | std::shared_ptr findClosestClass(); 42 | 43 | /** 44 | * Find all constructors 45 | * @return return the constructors 46 | * that matches the class name 47 | */ 48 | std::vector> findAllConstructors(); 49 | 50 | /** 51 | * Set extends from class 52 | * @param class lexical token 53 | */ 54 | void setExtendsName(std::shared_ptr lexicalToken) {m_extendsName = lexicalToken;} 55 | 56 | /** 57 | * Get extends from class 58 | * @return extends class 59 | */ 60 | std::shared_ptr getExtends(){ return m_extends;} 61 | 62 | /** 63 | * Check if class derives from the provided class 64 | * @param cls 65 | * @return true if class derives from the provided class 66 | */ 67 | bool inheritsFrom(std::shared_ptr cls); 68 | 69 | /** 70 | * Find closest variable in current, ancestor or extended scopes 71 | * @param name Name of the variable 72 | * @return closest variable pointer | nullptr if not found 73 | */ 74 | std::shared_ptr findClosestVariable(std::string name); 75 | 76 | /** 77 | * Find all functions extended 78 | * @param name Name of the function | nullptr 79 | * @return if name is a nullptr, then return all the functions 80 | * in their order of insertion and from closest to farthest scope, otherwise return the functions 81 | * that matches the passed name 82 | */ 83 | std::vector> findAllFunctionsExtended(const char* name = nullptr); 84 | 85 | /** 86 | * Check if constructor is created 87 | */ 88 | void verifyConstructor(); 89 | 90 | /** 91 | * Link extended function 92 | */ 93 | void linkExtends(); 94 | }; 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /example/input/Tutorial.bc: -------------------------------------------------------------------------------- 1 | /** 2 | * BashClass Tutorial Example 3 | * Author: Amir Bawab 4 | */ 5 | 6 | function int main(var int argc, var char[][] argv) { 7 | 8 | // Name is required 9 | if(argc < 2) { 10 | exception("Please enter your name as an argument: (e.g. bashc \"John\")"); 11 | } 12 | 13 | // Welcome message 14 | var String name = new String(argv[1]); 15 | printsln(new String("Hi, ").append(name)); 16 | 17 | // Start examples 18 | printcsln("Let's do some examples ..."); 19 | 20 | // List example 21 | if(confirm("Want to do 'List' example?")) { 22 | printcsln("Add items to a list. Type exit to stop."); 23 | var List list = new List(); 24 | var boolean exit = false; 25 | while(!exit) { 26 | var String word = readStr(); 27 | if(word.equals(str("exit"))) { 28 | exit = true; 29 | } else { 30 | list.add(word); 31 | } 32 | } 33 | printcs("Total number of items added to the list: "); 34 | printiln(list.size()); 35 | } else { 36 | printcsln("Skipping 'List' example"); 37 | } 38 | 39 | // Casting example 40 | if(confirm("Want to do 'Casting' example?")) { 41 | printcsln("Adding the following two items to a list: 123, \"Orange\""); 42 | var List list = new List(); 43 | list.add(new Integer(123)); 44 | list.add(new String("Orange")); 45 | 46 | printcsln("Printing items: "); 47 | var int i; 48 | var String typeString = str("String"); 49 | var String typeInteger = str("Integer"); 50 | for(i=0; i < list.size(); i=i+1) { 51 | var String type = list.get(i).type(); 52 | printcs("Item at index "); 53 | printi(i); 54 | if(type.equals(typeString)) { 55 | printcsln(" is a String"); 56 | var String cast = (list.get(i)):String; 57 | printsln(cast); 58 | } elif(type.equals(typeInteger)) { 59 | printcsln(" is an Integer"); 60 | var Integer cast = (list.get(i)):Integer; 61 | printiln(cast.getInteger()); 62 | } else { 63 | exception("Unknown type!"); 64 | } 65 | } 66 | } else { 67 | printcsln("Skipping 'Casting' example"); 68 | } 69 | 70 | printsln(str("Congratulations ").append(name).append(str("! You've completed all the examples!"))); 71 | printcsln("Thank you for trying BashClass :)"); 72 | 73 | return 0; 74 | } 75 | 76 | function boolean confirm(var char[] message) { 77 | var String yes = str("y"); 78 | var String YES = str("Y"); 79 | printsln(str(message).append(str(" (y/n)"))); 80 | var String val = readStr(); 81 | if(val.equals(yes) || val.equals(YES)) { 82 | return true; 83 | } 84 | return false; 85 | } 86 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # [![Build Status](https://travis-ci.org/amirbawab/BashClass.svg?branch=master)](https://travis-ci.org/amirbawab/BashClass) 2 | 3 | **Version**: 1.2.0 4 | 5 | ## Github 6 | Link: [Release 1.2.0](https://github.com/amirbawab/BashClass/releases/tag/v1.2.0) 7 | 8 | ## About 9 | BashClass is a programming language supporting Object Oriented Programming, and compiles to BASH 4.4. Class members written in BashClass are converted to an associative array with unique indices in the generated BASH script. 10 | 11 | BashClass uses [EasyCC-C++](http://amirbawab.github.io/EasyCC-CPP) library which provides the lexical and syntax analysis. The lexical and syntax analysis configuration files, located under the resources directory, serve as input to [EasyCC-C++](http://amirbawab.github.io/EasyCC-CPP) to parse the user files and validate it against a grammar determining the language syntax. 12 | 13 | 14 | ## Build project 15 | ### Docker 16 | * Clone repository 17 | * Build image: `sudo docker build -t bashclass:latest .` 18 | * Run container: `docker run --name bashclass-tutorial -it bashclass:latest` 19 | 20 | ### Host 21 | * Clone repository 22 | * Clone submodules: `git submodule update --init --recursive` 23 | * Run cmake: 24 | ```bash 25 | cmake . \ 26 | -DSYNTAX_ERRORS="${PWD}/resources/src/syntax_errors.json"\ 27 | -DSYNTAX_GRAMMAR="${PWD}/resources/src/grammar.json"\ 28 | -DLEXICAL_ERRORS="${PWD}/resources/src/lexical_errors.json"\ 29 | -DLEXICAL_CONFIG="${PWD}/resources/src/lexical_config.json"\ 30 | -DLEXICAL_STATE_MACHINE="${PWD}/resources/src/lexical_graph.json" 31 | ``` 32 | * Run make (developer mode): 33 | ```bash 34 | make bashcdev 35 | ``` 36 | * Run make (production mode): 37 | ```bash 38 | make generate_files # Embed JSON configurations into C++ files 39 | # Run the `cmake` command again to include the generated files 40 | # cmake . ... 41 | make bashc 42 | ``` 43 | 44 | ## Usage 45 | ### Developer mode 46 | ```bash 47 | ./bin/bashcdev \ 48 | -s resources/src/lexical_graph.json \ 49 | -c resources/src/lexical_config.json \ 50 | -e resources/src/lexical_errors.json \ 51 | -g resources/src/grammar.json \ 52 | -E resources/src/syntax_errors.json \ 53 | -o /tmp/test.sh \ 54 | -v \ 55 | path/to/file1 path/to/file2 ... 56 | ``` 57 | ### Production mode 58 | ```bash 59 | ./bin/bashc -o gen_bash.sh \ 60 | path/to/file1 path/to/file2 ... 61 | ``` 62 | In production mode the list of files to compile can be stored in a file (e.g. `files.list`) and then passed to the application prefixed by an `@` symbol. (e.g. `./bin/bashc @files.list -o /tmp/test.sh`) 63 | 64 | ## Limitations 65 | * The application was tested only on Arch and Ubuntu 66 | * Not much input files has been written to test the application 67 | * Project was created for fun and is not guaranteed to work everywhere, unless users prove the opposite ;) 68 | 69 | ## Contribution 70 | * Feel free to contribute 71 | -------------------------------------------------------------------------------- /include/bashclass/BVariable.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BVARIABLE_H 2 | #define BASHCLASS_BVARIABLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class BVariable { 12 | private: 13 | 14 | // Name of this variable 15 | std::shared_ptr m_name; 16 | 17 | // Type of this variable 18 | std::shared_ptr m_type; 19 | 20 | // Parent scope of this variable 21 | std::shared_ptr m_parentScope; 22 | 23 | // Initialize expression set when declaring the variable 24 | std::shared_ptr m_expression; 25 | 26 | // A parameter variable has this flag set to true 27 | bool m_isParam; 28 | 29 | public: 30 | 31 | /** 32 | * Initialize member variables 33 | */ 34 | BVariable(); 35 | 36 | /** 37 | * Get variable name token 38 | * @return name 39 | */ 40 | std::shared_ptr getName() const {return m_name;} 41 | 42 | /** 43 | * Set variable name token 44 | * @param name 45 | */ 46 | void setName(std::shared_ptr name) {m_name = name;} 47 | 48 | /** 49 | * Get variable type 50 | * @return type 51 | */ 52 | std::shared_ptr getType() const {return m_type;} 53 | 54 | /** 55 | * Get parent scope 56 | * @return pointer to parent scope 57 | */ 58 | std::shared_ptr getParentScope() {return m_parentScope;}; 59 | 60 | /** 61 | * Set parent scope 62 | * @param parent scope pointer 63 | */ 64 | void setParentScope(std::shared_ptr scope) {m_parentScope = scope;} 65 | 66 | /** 67 | * Check if variable is a function parameter 68 | * @return true if it is a parameter 69 | */ 70 | bool isParam() const {return m_isParam;} 71 | 72 | /** 73 | * Set parameter flag for a variable 74 | * @param isParam True if the variable is a function parameter 75 | */ 76 | void setIsParam(bool isParam) {m_isParam = isParam;} 77 | 78 | /** 79 | * Get variable label 80 | */ 81 | std::stringstream getLabel(); 82 | 83 | /** 84 | * Check if variable is a class member 85 | */ 86 | bool isClassMember(); 87 | 88 | /** 89 | * Set expression 90 | * @param expression 91 | */ 92 | void setExpression(std::shared_ptr expression) { m_expression = expression;} 93 | 94 | /** 95 | * Get expression 96 | * @return expression 97 | */ 98 | std::shared_ptr getExpression() {return m_expression;} 99 | 100 | /** 101 | * Get the default value 102 | * @return default value 103 | */ 104 | std::string getDefaultValue(); 105 | }; 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/eclipse,c++ 3 | 4 | ### Eclipse ### 5 | 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | .recommenders 17 | 18 | # Eclipse Core 19 | .project 20 | 21 | # External tool builders 22 | .externalToolBuilders/ 23 | 24 | # Locally stored "Eclipse launch configurations" 25 | *.launch 26 | 27 | # PyDev specific (Python IDE for Eclipse) 28 | *.pydevproject 29 | 30 | # CDT-specific (C/C++ Development Tooling) 31 | .cproject 32 | 33 | # JDT-specific (Eclipse Java Development Tools) 34 | .classpath 35 | 36 | # Java annotation processor (APT) 37 | .factorypath 38 | 39 | # PDT-specific (PHP Development Tools) 40 | .buildpath 41 | 42 | # sbteclipse plugin 43 | .target 44 | 45 | # Tern plugin 46 | .tern-project 47 | 48 | # TeXlipse plugin 49 | .texlipse 50 | 51 | # STS (Spring Tool Suite) 52 | .springBeans 53 | 54 | # Code Recommenders 55 | .recommenders/ 56 | 57 | 58 | ### C++ ### 59 | # Prerequisites 60 | *.d 61 | 62 | # Compiled Object files 63 | *.slo 64 | *.lo 65 | *.o 66 | *.obj 67 | 68 | # Precompiled Headers 69 | *.gch 70 | *.pch 71 | 72 | # Compiled Dynamic libraries 73 | *.so 74 | *.dylib 75 | *.dll 76 | 77 | # Fortran module files 78 | *.mod 79 | *.smod 80 | 81 | # Compiled Static libraries 82 | *.lai 83 | *.la 84 | *.a 85 | *.lib 86 | 87 | # Executables 88 | *.exe 89 | *.out 90 | *.app 91 | 92 | # End of https://www.gitignore.io/api/eclipse,c++ 93 | 94 | /Debug/ 95 | /Release/ 96 | 97 | 98 | ### JetBrains ### 99 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 100 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 101 | 102 | # User-specific stuff: 103 | .idea/workspace.xml 104 | .idea/tasks.xml 105 | 106 | # Sensitive or high-churn files: 107 | .idea/dataSources/ 108 | .idea/dataSources.ids 109 | .idea/dataSources.xml 110 | .idea/dataSources.local.xml 111 | .idea/sqlDataSources.xml 112 | .idea/dynamic.xml 113 | .idea/uiDesigner.xml 114 | 115 | # Gradle: 116 | .idea/gradle.xml 117 | .idea/libraries 118 | 119 | # Mongo Explorer plugin: 120 | .idea/mongoSettings.xml 121 | 122 | ## File-based project format: 123 | *.iws 124 | 125 | ## Plugin-specific files: 126 | 127 | # IntelliJ 128 | /out/ 129 | 130 | # mpeltonen/sbt-idea plugin 131 | .idea_modules/ 132 | 133 | # JIRA plugin 134 | atlassian-ide-plugin.xml 135 | 136 | # Crashlytics plugin (for Android Studio and IntelliJ) 137 | com_crashlytics_export_strings.xml 138 | crashlytics.properties 139 | crashlytics-build.properties 140 | fabric.properties 141 | .idea/sonarlint/ 142 | 143 | ### JetBrains Patch ### 144 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 145 | 146 | # *.iml 147 | # modules.xml 148 | # .idea/misc.xml 149 | # *.ipr 150 | 151 | # End of https://www.gitignore.io/api/jetbrains 152 | 153 | .idea/ 154 | cmake-build-debug/ 155 | site/ 156 | -------------------------------------------------------------------------------- /src/type/IBType.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /********************* 5 | * TOKEN TYPE NAME 6 | *********************/ 7 | const std::string IBType::TYPE_NAME_INT = "int_type"; 8 | const std::string IBType::TYPE_NAME_CHAR = "char_type"; 9 | const std::string IBType::TYPE_NAME_BOOLEAN = "boolean_type"; 10 | const std::string IBType::TYPE_NAME_VOID = "void_type"; 11 | const std::string IBType::TYPE_NAME_IDENTIFIER = "identifier"; 12 | 13 | /********************* 14 | * TOKEN TYPE VALUE 15 | *********************/ 16 | const std::string IBType::TYPE_VALUE_INT = "int"; 17 | const std::string IBType::TYPE_VALUE_CHAR = "char"; 18 | const std::string IBType::TYPE_VALUE_BOOLEAN = "boolean"; 19 | const std::string IBType::TYPE_VALUE_VOID = "void"; 20 | 21 | /********************* 22 | * TOKEN TYPE DATA 23 | *********************/ 24 | const std::string IBType::DATA_TYPE_NAME_INT = "integer"; 25 | const std::string IBType::DATA_TYPE_NAME_CHAR = "character"; 26 | const std::string IBType::DATA_TYPE_NAME_BOOLEAN = "truefalse"; 27 | const std::string IBType::DATA_TYPE_NAME_STRING = "string_literal"; 28 | const std::string IBType::DATA_TYPE_NAME_BASH_SUB = "bash_sub"; 29 | const std::string IBType::DATA_TYPE_NAME_BASH_SUB_INT = "bash_sub_int"; 30 | const std::string IBType::DATA_TYPE_NAME_BASH_INLINE = "bash_inline"; 31 | const std::string IBType::DATA_TYPE_NAME_BASH_BLOCK = "bash_block"; 32 | 33 | /********************* 34 | * SPECIAL TOKEN TYPE 35 | *********************/ 36 | const std::string IBType::UNDEFINED = "undefined"; 37 | const std::string IBType::NULL_VALUE = "null"; 38 | 39 | bool IBType::isBuiltInType() { 40 | return isInt() || isVoid() || isBoolean() || isChar(); 41 | } 42 | 43 | bool IBType::hasKnownType() { 44 | return isBuiltInType() || (isIdentifier() && m_typeScope); 45 | } 46 | 47 | bool IBType::isCompatible(std::shared_ptr type) { 48 | 49 | if(type->isUndefined() || type->isVoid()) { 50 | return false; 51 | } 52 | 53 | if(isArray() && type->isNull()) { 54 | return true; 55 | } 56 | 57 | if(isIdentifier() && type->isNull()) { 58 | return true; 59 | } 60 | 61 | if(isIdentifier() && getTypeScope() 62 | && type->isIdentifier() && type->getTypeScope() 63 | && type->getTypeScope()->inheritsFrom(getTypeScope())) { 64 | return true; 65 | } 66 | 67 | if(getTypeValue() != type->getTypeValue()) { 68 | return false; 69 | } 70 | 71 | return getDimension() == type->getDimension(); 72 | } 73 | 74 | std::string IBType::toString() { 75 | std::string result = getTypeValue(); 76 | int tmpDim = m_dimension; 77 | while (tmpDim-- > 0) { 78 | result += "[]"; 79 | } 80 | return result; 81 | } 82 | 83 | void IBType::cast(std::shared_ptr type) { 84 | m_dimension = type->getDimension(); 85 | m_typeScope = type->getTypeScope(); 86 | } 87 | 88 | bool IBType::isSame(std::shared_ptr type) { 89 | return getTypeValue() == type->getTypeValue() 90 | && getTypeName() == type->getTypeName() 91 | && getTypeScope() == type->getTypeScope() 92 | && getDimension() == type->getDimension(); 93 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at amirbawab@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /include/bashclass/BashClass.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BASHCLASS_H 2 | #define BASHCLASS_BASHCLASS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | typedef std::vector> LexicalTokens; 18 | typedef std::function SemanticActionHandler; 19 | 20 | class BashClass { 21 | public: 22 | 23 | // Different phases 24 | static const int PHASE_CREATE = 1; 25 | static const int PHASE_EVAL = 2; 26 | static const int PHASE_GENERATE = 3; 27 | 28 | // Error code 29 | static const int ERR_CODE_SEMANTIC = 4; 30 | 31 | /** 32 | * Initialize members 33 | * @param easyCC 34 | */ 35 | BashClass(std::shared_ptr easyCC) : m_easyCC(easyCC){} 36 | 37 | /** 38 | * Set easycc 39 | * @param easycc 40 | */ 41 | void setEasyCC(std::shared_ptr easycc) {m_easyCC = easycc;} 42 | 43 | /** 44 | * Compile files 45 | * @param inputFiles 46 | * @param outputFile 47 | */ 48 | int compile(std::vector inputFiles, std::string outputFile); 49 | 50 | private: 51 | 52 | // Handles the lexical and syntax analysis 53 | std::shared_ptr m_easyCC; 54 | 55 | // Key updated by a semantic action handler 56 | unsigned int m_referenceKey; 57 | 58 | // Hold nesting scopes 59 | std::vector> m_scopeStack; 60 | 61 | // Hold calls in order to build chains 62 | // e.g. a.b(c.d(e.f())) => [a, b], [b, c], [e, f] 63 | // e.g. a.b = 123; => [a, b], [123] 64 | std::vector> m_chainBuilderStack; 65 | 66 | // Hold variable currently being defined 67 | std::shared_ptr m_focusVariable; 68 | 69 | // Hold function currently being defined 70 | std::shared_ptr m_focusFunction; 71 | 72 | // Hold class currently being defined 73 | std::shared_ptr m_focusClass; 74 | 75 | // Hold if scope being defined 76 | std::shared_ptr m_focusIf; 77 | 78 | // Hold cast type 79 | std::shared_ptr m_focusCastType; 80 | 81 | // Hold chains and expressions operands 82 | std::vector> m_expressionOperandStack; 83 | 84 | // Hold expression operators 85 | std::vector> m_expressionOperatorStack; 86 | 87 | // Store output file name 88 | std::string m_outputFile; 89 | 90 | /** 91 | * Initialize semantic action handlers 92 | */ 93 | void initHandlers(); 94 | 95 | /** 96 | * Couple of checks required at each beginning of a phase 97 | */ 98 | void onPhaseStartCheck(); 99 | 100 | /** 101 | * Open output file 102 | */ 103 | void openOutput(); 104 | 105 | /** 106 | * Close output file 107 | */ 108 | void closeOutput(); 109 | }; 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /include/bashclass/BFunction.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BFUNCTION_H 2 | #define BASHCLASS_BFUNCTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BFunction : public BScope { 10 | private: 11 | 12 | // Function name 13 | std::shared_ptr m_name; 14 | 15 | // Function type 16 | std::shared_ptr m_type; 17 | 18 | // Mark function as a constructor 19 | bool m_isConstructor; 20 | 21 | public: 22 | 23 | /** 24 | * Initial variables 25 | */ 26 | BFunction(); 27 | 28 | /** 29 | * Get function name token 30 | * @return name 31 | */ 32 | std::shared_ptr getName() const{return m_name;} 33 | 34 | /** 35 | * Set function name token 36 | * @param name 37 | */ 38 | void setName(std::shared_ptr name) { m_name = name;} 39 | 40 | /** 41 | * Get function type 42 | * @return type 43 | */ 44 | std::shared_ptr getType() const {return m_type; } 45 | 46 | /** 47 | * Check if this function is a class member 48 | */ 49 | bool isClassMember(); 50 | 51 | /** 52 | * Get function label 53 | */ 54 | std::stringstream getLabel(); 55 | 56 | /** 57 | * Check if function requires a return expression 58 | * @return true if function requires a return expression 59 | */ 60 | bool requiresReturn(); 61 | 62 | /** 63 | * A void function should not a return statement 64 | */ 65 | void verifyReturns(); 66 | 67 | /** 68 | * If a parameter has a default value, then its following ones 69 | * should also have a default value 70 | */ 71 | void verifyParameters(); 72 | 73 | /** 74 | * Check if function overrides another one 75 | */ 76 | void verifyOverride(); 77 | 78 | /** 79 | * Check if super constructor is required 80 | */ 81 | void verifyNoSuperConstructor(); 82 | 83 | /** 84 | * The closest function to this scope is the scope itself 85 | * @return this scope 86 | */ 87 | std::shared_ptr findClosestFunction(); 88 | 89 | /** 90 | * Set if the function is a constructor 91 | * @param isConstructor 92 | */ 93 | void setIsConstructor(bool isConstructor) { m_isConstructor = isConstructor;} 94 | 95 | /** 96 | * Check if a function is a constructor 97 | * @return true if the function is a constructor 98 | */ 99 | bool isConstructor(); 100 | 101 | /** 102 | * Find all parameter variables 103 | * @param name Name of the parameter variable | nullptr 104 | * @return if name is a nullptr, then return all the parameter variables 105 | * in their order of insertion, otherwise return the parameter variables 106 | * that matches the passed name 107 | */ 108 | std::vector> findAllParameters(const char* name = nullptr); 109 | 110 | /** 111 | * Check if provided function has the same signature as this 112 | * @param function 113 | * @return true if both functions have the same signature 114 | */ 115 | bool hasSameSignature(std::shared_ptr function); 116 | }; 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /include/bashclass/BArithOperation.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BARITHOPERATION_H 2 | #define BASHCLASS_BARITHOPERATION_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BArithOperation : public IBExpression { 9 | private: 10 | 11 | // Left operand of the expression 12 | std::shared_ptr m_leftOperand; 13 | 14 | // Right operand of the expression 15 | std::shared_ptr m_rightOperand; 16 | 17 | // Operator of the expression 18 | std::shared_ptr m_operatorToken; 19 | 20 | // Type of this arithmetic operation 21 | std::shared_ptr m_type; 22 | 23 | /** 24 | * Evaluate arith operation with two operands 25 | * @return arith operation type 26 | */ 27 | std::shared_ptr _evaluateTwoOperands(); 28 | 29 | /** 30 | * Evaluate arith operation with right operand only 31 | * @return arith operation type 32 | */ 33 | std::shared_ptr _evaluateRightOperand(); 34 | 35 | public: 36 | 37 | // Operators names 38 | static const std::string OP_LOGICAL_OR; 39 | static const std::string OP_LOGICAL_AND; 40 | static const std::string OP_IS_EQUAL; 41 | static const std::string OP_IS_NOT_EQUAL; 42 | static const std::string OP_LESS_THAN; 43 | static const std::string OP_GREATER_THAN; 44 | static const std::string OP_LESS_OR_EQUAL; 45 | static const std::string OP_GREATER_OR_EQUAL; 46 | static const std::string OP_NOT; 47 | static const std::string OP_BIT_OR; 48 | static const std::string OP_BIT_XOR; 49 | static const std::string OP_BIT_AND; 50 | static const std::string OP_LEFT_SHIFT; 51 | static const std::string OP_RIGHT_SHIFT; 52 | static const std::string OP_MINUS; 53 | static const std::string OP_MULTIPLY; 54 | static const std::string OP_DIVIDE; 55 | static const std::string OP_MOD; 56 | static const std::string OP_EXPONENTIAL; 57 | static const std::string OP_ASSIGN; 58 | static const std::string OP_PLUS; 59 | 60 | /** 61 | * Set left operator 62 | * @param leftOperand 63 | */ 64 | void setLeftOperand(std::shared_ptr leftOperand) { m_leftOperand = leftOperand;} 65 | 66 | /** 67 | * Get left operator 68 | * @return leftOperator 69 | */ 70 | std::shared_ptr getLeftOperand() const {return m_leftOperand;} 71 | 72 | /** 73 | * Set right operand 74 | * @param rightOperand 75 | */ 76 | void setRightOperand(std::shared_ptr rightOperand) {m_rightOperand = rightOperand;} 77 | 78 | /** 79 | * Get right operand 80 | * @return rightOpeartor 81 | */ 82 | std::shared_ptr getRightOperand() const {return m_rightOperand;} 83 | 84 | /** 85 | * Set operator 86 | * @param operatorToken 87 | */ 88 | void setOperator(std::shared_ptr operatorToken) {m_operatorToken = operatorToken;} 89 | 90 | /** 91 | * Get operator 92 | * @return operator 93 | */ 94 | std::shared_ptr getOperator() {return m_operatorToken;} 95 | 96 | /** 97 | * Get type 98 | * @return type 99 | */ 100 | std::shared_ptr getType() { return m_type; } 101 | 102 | /** 103 | * Evaluate arithmetic operation 104 | */ 105 | void evaluate(); 106 | 107 | /** 108 | * Cast type 109 | * @param type 110 | */ 111 | void castType(std::shared_ptr type); 112 | }; 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/scope/BGlobal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | const std::string BGlobal::MAIN_FUNCTION = "main"; 10 | 11 | std::stringstream BGlobal::getLabel() { 12 | return std::stringstream(); 13 | } 14 | 15 | void BGlobal::link() { 16 | 17 | for(auto cls : findAllClasses()) { 18 | 19 | // Link extends 20 | cls->linkExtends(); 21 | 22 | // Link class variable members types 23 | for(auto variable : cls->findAllVariables()) { 24 | variable->getType()->linkType(); 25 | } 26 | 27 | // Link class function members types 28 | for(auto function : cls->findAllFunctions()) { 29 | function->getType()->linkType(); 30 | 31 | // Link class function parameters types 32 | for(auto param : function->findAllParameters()) { 33 | param->getType()->linkType(); 34 | } 35 | } 36 | } 37 | 38 | // Link global functions types 39 | for(auto function : findAllFunctions()) { 40 | function->getType()->linkType(); 41 | 42 | // LInk global functions parameters types 43 | for(auto param : function->findAllParameters()) { 44 | param->getType()->linkType(); 45 | } 46 | } 47 | } 48 | 49 | void BGlobal::verifyMain() { 50 | auto functions = findAllFunctions(BGlobal::MAIN_FUNCTION.c_str()); 51 | if(functions.empty()) { 52 | BReport::getInstance().error() 53 | << "A main function is required" << std::endl; 54 | BReport::getInstance().printError(); 55 | } else { 56 | auto mainFunction = functions.front(); 57 | if(!mainFunction->getType()) { 58 | throw BException("Cannot verify main function without a defined type"); 59 | } 60 | 61 | // Main function must return an integer 62 | if(!mainFunction->getType()->isInt()) { 63 | BReport::getInstance().error() 64 | << "Main function must return an integer" << std::endl; 65 | BReport::getInstance().printError(); 66 | } 67 | 68 | // Check params: int, char[][] 69 | auto params = mainFunction->findAllParameters(); 70 | if(params.size() != 0 && params.size() != 2) { 71 | BReport::getInstance().error() 72 | << "Main function parameters must either be empty or (int, char[][])" << std::endl; 73 | BReport::getInstance().printError(); 74 | } else if(params.size() == 2) { 75 | 76 | // int 77 | if(!params[0]->getType()->isInt() || params[0]->getType()->getDimension() != 0) { 78 | BReport::getInstance().error() 79 | << "First parameter in main function must be of type int" << std::endl; 80 | BReport::getInstance().printError(); 81 | } 82 | 83 | // char[][] 84 | if(!params[1]->getType()->isChar() || params[1]->getType()->getDimension() != 2) { 85 | BReport::getInstance().error() 86 | << "Second parameter in main function must be of type char[][]" << std::endl; 87 | BReport::getInstance().printError(); 88 | } 89 | 90 | // Params should not have default expression 91 | if(params[0]->getExpression() || params[1]->getExpression()) { 92 | BReport::getInstance().error() 93 | << "Main function parameters cannot have a default expression" << std::endl; 94 | BReport::getInstance().printError(); 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | 19 | ## Code of Conduct 20 | 21 | ### Our Pledge 22 | 23 | In the interest of fostering an open and welcoming environment, we as 24 | contributors and maintainers pledge to making participation in our project and 25 | our community a harassment-free experience for everyone, regardless of age, body 26 | size, disability, ethnicity, gender identity and expression, level of experience, 27 | nationality, personal appearance, race, religion, or sexual identity and 28 | orientation. 29 | 30 | ### Our Standards 31 | 32 | Examples of behavior that contributes to creating a positive environment 33 | include: 34 | 35 | * Using welcoming and inclusive language 36 | * Being respectful of differing viewpoints and experiences 37 | * Gracefully accepting constructive criticism 38 | * Focusing on what is best for the community 39 | * Showing empathy towards other community members 40 | 41 | Examples of unacceptable behavior by participants include: 42 | 43 | * The use of sexualized language or imagery and unwelcome sexual attention or 44 | advances 45 | * Trolling, insulting/derogatory comments, and personal or political attacks 46 | * Public or private harassment 47 | * Publishing others' private information, such as a physical or electronic 48 | address, without explicit permission 49 | * Other conduct which could reasonably be considered inappropriate in a 50 | professional setting 51 | 52 | ### Our Responsibilities 53 | 54 | Project maintainers are responsible for clarifying the standards of acceptable 55 | behavior and are expected to take appropriate and fair corrective action in 56 | response to any instances of unacceptable behavior. 57 | 58 | Project maintainers have the right and responsibility to remove, edit, or 59 | reject comments, commits, code, wiki edits, issues, and other contributions 60 | that are not aligned to this Code of Conduct, or to ban temporarily or 61 | permanently any contributor for other behaviors that they deem inappropriate, 62 | threatening, offensive, or harmful. 63 | 64 | ### Scope 65 | 66 | This Code of Conduct applies both within project spaces and in public spaces 67 | when an individual is representing the project or its community. Examples of 68 | representing a project or community include using an official project e-mail 69 | address, posting via an official social media account, or acting as an appointed 70 | representative at an online or offline event. Representation of a project may be 71 | further defined and clarified by project maintainers. 72 | 73 | ### Enforcement 74 | 75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 76 | reported by contacting the project team. All 77 | complaints will be reviewed and investigated and will result in a response that 78 | is deemed necessary and appropriate to the circumstances. The project team is 79 | obligated to maintain confidentiality with regard to the reporter of an incident. 80 | Further details of specific enforcement policies may be posted separately. 81 | 82 | Project maintainers who do not follow or enforce the Code of Conduct in good 83 | faith may face temporary or permanent repercussions as determined by other 84 | members of the project's leadership. 85 | 86 | ### Attribution 87 | 88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 89 | available at [http://contributor-covenant.org/version/1/4][version] 90 | 91 | [homepage]: http://contributor-covenant.org 92 | [version]: http://contributor-covenant.org/version/1/4/ 93 | -------------------------------------------------------------------------------- /include/bashclass/BBashHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BBASHHELPER_H 2 | #define BASHCLASS_BBASHHELPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | class BBashHelper { 18 | private: 19 | /** 20 | * Generate code to convert strings into char array in bash 21 | */ 22 | static void _bashStrToCharArray(std::stringstream &ss); 23 | 24 | /** 25 | * Generate code to create an array in bash 26 | */ 27 | static void _bashCreateArray(std::stringstream &ss); 28 | public: 29 | 30 | /** 31 | * Generate code for bash required functions 32 | */ 33 | static void writeBashFunctions(); 34 | 35 | /** 36 | * Generate header bash code 37 | */ 38 | static void header(); 39 | 40 | /** 41 | * Generate footer bash code 42 | */ 43 | static void footer(); 44 | 45 | /** 46 | * Generate counters wichi store the next index of the corresponding item 47 | */ 48 | static void declareCounters(); 49 | 50 | /** 51 | * Generate a variable in bash 52 | * @param variable 53 | * @param defaultValue 54 | */ 55 | static void createVar(std::shared_ptr variable); 56 | 57 | /** 58 | * Generate a function in bash 59 | * @param function 60 | */ 61 | static void createFunction(std::shared_ptr function); 62 | 63 | /** 64 | * Close a function in bash 65 | * @param function 66 | */ 67 | static void closeFunction(std::shared_ptr function); 68 | 69 | /** 70 | * Write pure bash 71 | * @param scope 72 | * @param lexicalToken 73 | */ 74 | static void bash(std::shared_ptr scope, std::shared_ptr lexicalToken); 75 | 76 | /** 77 | * Write expression 78 | * @param scope 79 | * @param expression 80 | */ 81 | static void writeExpression(std::shared_ptr scope, std::shared_ptr expression); 82 | 83 | /** 84 | * Generate code for a return statement 85 | * @param rtn 86 | */ 87 | static void writeReturn(std::shared_ptr rtn); 88 | 89 | /** 90 | * Generate code for an if statement 91 | * @param ifStatement 92 | */ 93 | static void createIf(std::shared_ptr ifStatement); 94 | 95 | /** 96 | * Generate code for an elif statement 97 | * @param elifStatement 98 | */ 99 | static void createElif(std::shared_ptr elifStatement); 100 | 101 | /** 102 | * Generate code for an else statement 103 | * @param elseStatement 104 | */ 105 | static void createElse(std::shared_ptr elseStatement); 106 | 107 | /** 108 | * Generate code for closing the if statement 109 | * @param ifStatement 110 | */ 111 | static void closeIf(std::shared_ptr ifStatement); 112 | 113 | /** 114 | * Generate code for closing the elif statement 115 | * @param elifStatement 116 | */ 117 | static void closeElif(std::shared_ptr elifStatement); 118 | 119 | /** 120 | * Generate code for closing the else statement 121 | * @param elseStatement 122 | */ 123 | static void closeElse(std::shared_ptr elseStatement); 124 | 125 | /** 126 | * Generate code for while statement 127 | * @param whileStatement 128 | */ 129 | static void createWhile(std::shared_ptr whileStatement); 130 | 131 | /** 132 | * Generate code for closing while statement 133 | * @param whileStatement 134 | */ 135 | static void closeWhile(std::shared_ptr whileStatement); 136 | 137 | /** 138 | * Generate code for for statement 139 | * @param forStatement 140 | */ 141 | static void createFor(std::shared_ptr forStatement); 142 | 143 | /** 144 | * Generate code for closing for statement 145 | * @param forStatement 146 | */ 147 | static void closeFor(std::shared_ptr forStatement); 148 | 149 | /** 150 | * Write break or continue 151 | * @param scope 152 | * @param lexicalToken 153 | */ 154 | static void writeBreakOrContinue(std::shared_ptr scope, std::shared_ptr lexicalToken); 155 | }; 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /src/chain/BFunctionChainCall.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void BFunctionChainCall::verifyArguments() { 10 | 11 | // Check if the number of arguments is less than the number of parameters 12 | if(m_function) { 13 | auto params = m_function->findAllParameters(); 14 | if(m_arguments.size() < params.size()) { 15 | 16 | // Check if the remaining params have a default value 17 | for(size_t paramIndex=m_arguments.size(); paramIndex < params.size(); paramIndex++) { 18 | if(!params[paramIndex]->getExpression()) { 19 | BReport::getInstance().error() 20 | << "Function call " << m_lexicalToken->getValue() 21 | << " is missing arguments" << std::endl; 22 | BReport::getInstance().printError(); 23 | return; 24 | } 25 | } 26 | } 27 | } 28 | 29 | // No need to check if for the number of arguments exceeding the number of parameters because 30 | // this is already handled by the addArgument() function 31 | } 32 | 33 | void BFunctionChainCall::addArgument(std::shared_ptr argument) { 34 | 35 | // Check the index of the parameter to be compared with 36 | size_t paramIndex = m_arguments.size(); 37 | 38 | // Add argument 39 | m_arguments.push_back(argument); 40 | 41 | // To verify the argument added, the function must exist 42 | if(m_function) { 43 | 44 | // Get function parameters 45 | auto parameters = m_function->findAllParameters(); 46 | 47 | // Arguments number must match function parameters 48 | if(paramIndex >= parameters.size()) { 49 | BReport::getInstance().error() 50 | << "Argument number " << paramIndex + 1 << " cannot be passed to the function " 51 | << m_function->getName()->getValue() << " because the function expects " 52 | << parameters.size() << " arguments" << std::endl; 53 | BReport::getInstance().printError(); 54 | } else { 55 | 56 | std::shared_ptr argumentType = argument->getType(); 57 | std::shared_ptr parameterType = parameters[paramIndex]->getType(); 58 | if(!parameters[paramIndex]->getType()->hasKnownType()) { 59 | BReport::getInstance().error() 60 | << "Cannot pass argument value to an undefined type for parameter " 61 | << parameters[paramIndex]->getName()->getValue() << " in function " 62 | << m_function->getName()->getValue() << std::endl; 63 | BReport::getInstance().printError(); 64 | } else if(argumentType->isUndefined()) { 65 | BReport::getInstance().error() 66 | << "Parameter " << parameters[paramIndex]->getName()->getValue() 67 | << " in function " << m_function->getName()->getValue() 68 | << " is given an undefined argument" << std::endl; 69 | BReport::getInstance().printError(); 70 | } else if(!parameterType->isCompatible(argumentType)) { 71 | BReport::getInstance().error() 72 | << "Function " << m_function->getName()->getValue() 73 | << " expects argument " << paramIndex + 1 << " to be of type " << parameterType->toString() 74 | << " but given " << argumentType->toString() << std::endl; 75 | BReport::getInstance().printError(); 76 | } 77 | } 78 | } else { 79 | BReport::getInstance().error() 80 | << "Arguments number " << m_arguments.size() 81 | << " for function call " << m_lexicalToken->getValue() 82 | << " cannot be verified because the function is undefined" << std::endl; 83 | BReport::getInstance().printError(); 84 | } 85 | } 86 | 87 | bool BFunctionChainCall::isFound() { 88 | return m_function != nullptr; 89 | } 90 | 91 | std::shared_ptr BFunctionChainCall::getType() { 92 | if(!m_function || !m_function->getType()->hasKnownType() || m_type->getDimension() < 0) { 93 | return BTypeFactory::createUndefinedExpressionType(); 94 | } 95 | return m_type; 96 | } 97 | 98 | void BFunctionChainCall::setFunction(std::shared_ptr function) { 99 | m_function = function; 100 | m_type = function->getType()->cloneToExpressionType(); 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/scope/BClass.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::stringstream BClass::getLabel() { 9 | std::stringstream stream = m_parentScope->getLabel(); 10 | stream << "_c_" << m_name->getValue(); 11 | return stream; 12 | } 13 | 14 | std::shared_ptr BClass::findClosestClass() { 15 | return std::static_pointer_cast(shared_from_this()); 16 | } 17 | 18 | std::vector> BClass::findAllConstructors() { 19 | std::vector> functions; 20 | for(auto scope : m_scopes) { 21 | std::shared_ptr functionScope = std::dynamic_pointer_cast(scope.second); 22 | if(functionScope && functionScope->isConstructor()) { 23 | if(!functionScope->getName()) { 24 | throw BException("Finding constructors requires constructor name to be defined"); 25 | } 26 | 27 | if(!m_name) { 28 | throw BException("Class name is required to search for constructors"); 29 | } 30 | 31 | if (functionScope->getName()->getValue() == m_name->getValue()) { 32 | functions.push_back(functionScope); 33 | } 34 | } 35 | } 36 | return functions; 37 | } 38 | 39 | void BClass::linkExtends() { 40 | 41 | // If extends exists 42 | if(m_extendsName) { 43 | 44 | // Search for that class 45 | auto classes = BGlobal::getInstance()->findAllClasses(m_extendsName->getValue().c_str()); 46 | 47 | // TODO To be tested 48 | auto thisClass = std::static_pointer_cast(shared_from_this()); 49 | 50 | // Check if class was found 51 | if (classes.empty()) { 52 | BReport::getInstance().error() 53 | << "Class " << m_extendsName->getValue() 54 | << " not found while establishing an inheritance relationship with " 55 | << m_name->getValue() << std::endl; 56 | BReport::getInstance().printError(); 57 | } else { 58 | 59 | // Check if a circular inheritance will be created 60 | if (classes.front()->inheritsFrom(std::static_pointer_cast(shared_from_this()))) { 61 | BReport::getInstance().error() 62 | << "A circular inheritance detected while establishing an inheritance relationship between classes " 63 | << m_name->getValue() << " and " << classes.front()->getName()->getValue() << std::endl; 64 | BReport::getInstance().printError(); 65 | } 66 | 67 | // Extend anw 68 | m_extends = classes.front(); 69 | } 70 | } 71 | } 72 | 73 | bool BClass::inheritsFrom(std::shared_ptr cls) { 74 | // TODO To be tested 75 | std::shared_ptr tmpParent = std::static_pointer_cast(shared_from_this()); 76 | while(tmpParent && tmpParent != cls) { 77 | tmpParent = tmpParent->getExtends(); 78 | } 79 | return tmpParent != nullptr; 80 | } 81 | 82 | std::shared_ptr BClass::findClosestVariable(std::string name) { 83 | 84 | // Check in current and extended classes 85 | auto tmpClass = std::static_pointer_cast(shared_from_this()); 86 | while(tmpClass) { 87 | auto variables = tmpClass->findAllVariables(name.c_str()); 88 | if(!variables.empty()) { 89 | return variables.front(); 90 | } 91 | tmpClass = tmpClass->getExtends(); 92 | } 93 | 94 | if(!m_parentScope) { 95 | throw BException("Cannot search for variables in an undefined parent scope for class " + m_name->getValue()); 96 | } 97 | return m_parentScope->findClosestVariable(name); 98 | } 99 | 100 | std::vector> BClass::findAllFunctionsExtended(const char *name) { 101 | std::vector> functions; 102 | std::shared_ptr tmpClass = std::static_pointer_cast(shared_from_this()); 103 | while (tmpClass) { 104 | auto foundFunctions = tmpClass->findAllFunctions(name); 105 | functions.insert(functions.end(), foundFunctions.begin(), foundFunctions.end()); 106 | tmpClass = tmpClass->getExtends(); 107 | } 108 | return functions; 109 | } 110 | 111 | void BClass::verifyConstructor() { 112 | auto constructors = findAllConstructors(); 113 | if(constructors.empty()) { 114 | BReport::getInstance().error() 115 | << "Class " << m_name->getValue() 116 | << " is missing a constructor" << std::endl; 117 | BReport::getInstance().printError(); 118 | } 119 | } -------------------------------------------------------------------------------- /src/scope/BFunction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | BFunction::BFunction() { 10 | m_isConstructor = false; 11 | m_type = std::make_shared(); 12 | } 13 | 14 | std::stringstream BFunction::getLabel() { 15 | std::stringstream stream = m_parentScope->getLabel(); 16 | stream << "_f_" << m_name->getValue(); 17 | return stream; 18 | } 19 | 20 | bool BFunction::isClassMember() { 21 | if(!m_parentScope) { 22 | throw BException("Cannot check if a function is a class member if it does not have a parent scope"); 23 | } 24 | return std::dynamic_pointer_cast(m_parentScope) != nullptr; 25 | } 26 | 27 | bool BFunction::requiresReturn() { 28 | return !m_type->isVoid() && !isConstructor(); 29 | } 30 | 31 | void BFunction::verifyReturns() { 32 | if(requiresReturn() && !hasReturn()) { 33 | BReport::getInstance().error() 34 | << "Missing return statement in function " << m_name->getValue() << std::endl; 35 | BReport::getInstance().printError(); 36 | } 37 | 38 | // No need to check for the case of return not required 39 | // since it is already handled when it is set into a scope 40 | } 41 | 42 | void BFunction::verifyParameters() { 43 | auto params = findAllParameters(); 44 | 45 | // If a parameter has an default expression, 46 | // then all the following ones must also have a default expression 47 | bool hasExpression = false; 48 | for(size_t i=0; i < params.size(); i++) { 49 | if(hasExpression && !params[i]->getExpression()) { 50 | BReport::getInstance().error() 51 | << "Parameter " << i+1 << " in function " << m_name->getValue() 52 | << " is missing a default expression" << std::endl; 53 | BReport::getInstance().printError(); 54 | } 55 | hasExpression |= params[i]->getExpression() != nullptr; 56 | } 57 | } 58 | 59 | std::shared_ptr BFunction::findClosestFunction() { 60 | return std::static_pointer_cast(shared_from_this()); 61 | } 62 | 63 | bool BFunction::isConstructor() { 64 | return m_isConstructor; 65 | } 66 | 67 | std::vector> BFunction::findAllParameters(const char *name) { 68 | std::vector> parameters; 69 | for(auto variable : m_variables) { 70 | if(variable.second->isParam() && (!name || 71 | (variable.second->getName() && variable.second->getName()->getValue() == name))) { 72 | parameters.push_back(variable.second); 73 | } 74 | } 75 | return parameters; 76 | } 77 | 78 | bool BFunction::hasSameSignature(std::shared_ptr function) { 79 | 80 | // Name must be identical 81 | if(function->getName()->getValue() != getName()->getValue()) { 82 | return false; 83 | } 84 | 85 | // Check if both functions hve the same return type 86 | if(!function->getType()->isSame(getType())) { 87 | return false; 88 | } 89 | 90 | // Check if the arguments number, order and type match 91 | auto thisParam = findAllParameters(); 92 | auto funcParam = function->findAllParameters(); 93 | if(thisParam.size() != funcParam.size()) { 94 | return false; 95 | } 96 | 97 | for(size_t i=0; i < thisParam.size(); i++) { 98 | if(!thisParam[i]->getType()->isSame(funcParam[i]->getType())) { 99 | return false; 100 | } 101 | } 102 | return true; 103 | } 104 | 105 | void BFunction::verifyOverride() { 106 | if(isClassMember()) { 107 | auto parentClass = std::static_pointer_cast(m_parentScope)->getExtends(); 108 | if(parentClass) { 109 | auto parGetFunc = parentClass->findAllFunctionsExtended(getName()->getValue().c_str()); 110 | if(!parGetFunc.empty()) { 111 | auto overFunction = parGetFunc.back(); 112 | if(!hasSameSignature(overFunction)) { 113 | BReport::getInstance().error() 114 | << "Function " << getName()->getValue() << " at line " 115 | << getName()->getLine() 116 | <<" tries to override a parent function with a different signature" << std::endl; 117 | BReport::getInstance().printError(); 118 | } 119 | } 120 | } 121 | } 122 | } 123 | 124 | void BFunction::verifyNoSuperConstructor() { 125 | 126 | // If function is a constructor and class extends another one, 127 | // then a super constructor call is required 128 | if(isConstructor()) { 129 | auto parentClass = std::static_pointer_cast(m_parentScope); 130 | if(parentClass->getExtends()) { 131 | BReport::getInstance().error() 132 | << "Constructor at line " 133 | << getName()->getLine() 134 | <<" is missing a super constructor" << std::endl; 135 | BReport::getInstance().printError(); 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /include/bashclass/IBType.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_IBTYPE_H 2 | #define BASHCLASS_IBTYPE_H 3 | 4 | #include 5 | #include 6 | 7 | class BClass; 8 | class BElementType; 9 | class IBType { 10 | protected: 11 | 12 | // Hold type scope 13 | std::shared_ptr m_typeScope; 14 | 15 | // Hold the dimension if the type is an array 16 | int m_dimension; 17 | public: 18 | 19 | /** 20 | * Initialize members 21 | */ 22 | IBType() : m_dimension(0){} 23 | 24 | // Values defining the built-in types names. For example: 25 | // var [int] a; 26 | // lexicalToken->getName() 27 | static const std::string TYPE_NAME_INT; 28 | static const std::string TYPE_NAME_CHAR; 29 | static const std::string TYPE_NAME_BOOLEAN; 30 | static const std::string TYPE_NAME_VOID; 31 | static const std::string TYPE_NAME_IDENTIFIER; 32 | 33 | // Values defining the built-in types values. For example: 34 | // var [int] a; 35 | // lexicalToken->getValue() 36 | static const std::string TYPE_VALUE_INT; 37 | static const std::string TYPE_VALUE_CHAR; 38 | static const std::string TYPE_VALUE_BOOLEAN; 39 | static const std::string TYPE_VALUE_VOID; 40 | 41 | // Undefined type is used by the compiler when an expression has an unknown type 42 | // e.g. Divide a string by another 43 | // When "undefined" is used by the user as input, it will behave as an alias 44 | // to "null" 45 | // "undefined" must be a reserved word to avoid a user defined class called 46 | // undefined 47 | static const std::string UNDEFINED; 48 | 49 | // Null is used to unlink a reference of an object 50 | static const std::string NULL_VALUE; 51 | 52 | // Those values represent the type name of data 53 | // a = [1234]; 54 | // lexicalToken->getName() 55 | static const std::string DATA_TYPE_NAME_INT; 56 | static const std::string DATA_TYPE_NAME_STRING; 57 | static const std::string DATA_TYPE_NAME_CHAR; 58 | static const std::string DATA_TYPE_NAME_BOOLEAN; 59 | static const std::string DATA_TYPE_NAME_BASH_SUB; 60 | static const std::string DATA_TYPE_NAME_BASH_SUB_INT; 61 | static const std::string DATA_TYPE_NAME_BASH_INLINE; 62 | static const std::string DATA_TYPE_NAME_BASH_BLOCK; 63 | 64 | /** 65 | * Get type name 66 | * @return type name 67 | */ 68 | virtual std::string getTypeName()=0; 69 | 70 | /** 71 | * Get type value 72 | * @return type value 73 | */ 74 | virtual std::string getTypeValue()=0; 75 | 76 | /** 77 | * Get type scope 78 | * @return type scope 79 | */ 80 | std::shared_ptr getTypeScope() {return m_typeScope;} 81 | 82 | /** 83 | * Int check 84 | * @return boolean 85 | */ 86 | bool isInt() { return getTypeName() == IBType::TYPE_NAME_INT;}; 87 | 88 | /** 89 | * Void check 90 | * @return boolean 91 | */ 92 | bool isVoid() {return getTypeName() == IBType::TYPE_NAME_VOID;} 93 | 94 | /** 95 | * Char check 96 | * @return boolean 97 | */ 98 | bool isChar() {return getTypeName() == IBType::TYPE_NAME_CHAR;} 99 | 100 | /** 101 | * Boolean check 102 | * @return boolean 103 | */ 104 | bool isBoolean() {return getTypeName() == IBType::TYPE_NAME_BOOLEAN;} 105 | 106 | /** 107 | * Identifier check 108 | * @return boolean 109 | */ 110 | bool isIdentifier() { return getTypeName() == IBType::TYPE_NAME_IDENTIFIER; } 111 | 112 | /** 113 | * Null check 114 | * @return boolean 115 | */ 116 | bool isNull() {return getTypeName() == IBType::NULL_VALUE;} 117 | 118 | /** 119 | * Undefined check 120 | * @return boolean 121 | */ 122 | bool isUndefined() { return getTypeName() == IBType::UNDEFINED;} 123 | 124 | /** 125 | * Check if the type is built-in 126 | */ 127 | bool isBuiltInType(); 128 | 129 | /** 130 | * Check if type is known 131 | */ 132 | bool hasKnownType(); 133 | 134 | /** 135 | * Set dimension 136 | * @param dimension 137 | */ 138 | void setDimension(int dimension) { m_dimension = dimension;} 139 | 140 | /** 141 | * Get dimension 142 | * @return dimension 143 | */ 144 | int getDimension() {return m_dimension;} 145 | 146 | /** 147 | * Check if type is an array 148 | * @return true if it is an array 149 | */ 150 | bool isArray() {return m_dimension > 0;} 151 | 152 | /** 153 | * Check if type is compatible with the provided one 154 | * e.g. a = b; 155 | * Then the check is as follow: a.isCompatible(b) 156 | * @return true if it is compatible 157 | */ 158 | bool isCompatible(std::shared_ptr type); 159 | 160 | /** 161 | * To string representation 162 | * @return string 163 | */ 164 | std::string toString(); 165 | 166 | /** 167 | * Cast type 168 | * @param type 169 | */ 170 | virtual void cast(std::shared_ptr type); 171 | 172 | /** 173 | * Check if provided type is the same as this one 174 | * @param type 175 | * @return true if both types are the same 176 | */ 177 | bool isSame(std::shared_ptr type); 178 | }; 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /include/bashclass/BScope.h: -------------------------------------------------------------------------------- 1 | #ifndef BASHCLASS_BSCOPE_H 2 | #define BASHCLASS_BSCOPE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class BVariable; 12 | class BFunction; 13 | class BClass; 14 | class BWhile; 15 | class BFor; 16 | class BChain; 17 | class BReturn; 18 | class BScope : public std::enable_shared_from_this { 19 | protected: 20 | 21 | // Register the variables defined in this scope 22 | std::map> m_variables; 23 | 24 | // Register the scopes defines in this scope 25 | std::map> m_scopes; 26 | 27 | // Register expressions 28 | std::map> m_expressions; 29 | 30 | // Register the return statements defined in this scope 31 | std::shared_ptr m_return; 32 | 33 | // Store the parent for this scope 34 | std::shared_ptr m_parentScope; 35 | public: 36 | virtual ~BScope(){} 37 | 38 | /** 39 | * Get a string representation of the scope structure 40 | */ 41 | std::stringstream getStructure(); 42 | 43 | /** 44 | * Find all variables 45 | * @param name Name of the variable | nullptr 46 | * @return if name is a nullptr, then return all the variables 47 | * in their order of insertion, otherwise return the variables 48 | * that matches the passed name 49 | */ 50 | std::vector> findAllVariables(const char* name = nullptr); 51 | 52 | /** 53 | * Find all classes 54 | * @param name Name of the class | nullptr 55 | * @return if name is a nullptr, then return all the classes 56 | * in their order of insertion, otherwise return the classes 57 | * that matches the passed name 58 | */ 59 | std::vector> findAllClasses(const char* name = nullptr); 60 | 61 | /** 62 | * Find all functions 63 | * @param name Name of the function | nullptr 64 | * @return if name is a nullptr, then return all the functions 65 | * in their order of insertion, otherwise return the functions 66 | * that matches the passed name 67 | */ 68 | std::vector> findAllFunctions(const char* name = nullptr); 69 | 70 | /** 71 | * Get parent scope 72 | * @return pointer to parent scope 73 | */ 74 | std::shared_ptr getParentScope() const {return m_parentScope;} 75 | 76 | /** 77 | * Set parent scope 78 | * @param scope Parent scope 79 | */ 80 | void setParentScope(std::shared_ptr scope) { m_parentScope = scope;} 81 | 82 | /** 83 | * Get scope by reference key 84 | * @param referenceKey 85 | * @return pointer to scope | nullptr 86 | */ 87 | std::shared_ptr getScopeByReferenceKey(unsigned int referenceKey); 88 | 89 | /** 90 | * Get all scopes 91 | * @return vector fo scopes 92 | */ 93 | std::vector> getAllScopes(); 94 | 95 | /** 96 | * Get variable by reference key 97 | * @param referenceKey 98 | * @return pointer to variable | nullptr 99 | */ 100 | std::shared_ptr getVariableByReferenceKey(unsigned int referenceKey); 101 | 102 | /** 103 | * Get label for that scope 104 | */ 105 | virtual std::stringstream getLabel()=0; 106 | 107 | /** 108 | * Find closest variable in current or ancestor scope 109 | * @param name Name of the variable 110 | * @return closest variable pointer | nullptr if not found 111 | */ 112 | virtual std::shared_ptr findClosestVariable(std::string name); 113 | 114 | /** 115 | * Find closest function: ancestor or itself 116 | * @return closest function pointer | nullptr if not found 117 | */ 118 | virtual std::shared_ptr findClosestFunction(); 119 | 120 | /** 121 | * Find closest class: ancestor or itself 122 | * @return closest class pointer | nullptr if not found 123 | */ 124 | virtual std::shared_ptr findClosestClass(); 125 | 126 | /** 127 | * Find closest while: ancestor or itself 128 | * @return closest while pointer | nullptr if not found 129 | */ 130 | virtual std::shared_ptr findClosestWhile(); 131 | 132 | /** 133 | * Find closest for: ancestor or itself 134 | * @return closest for pointer | nullptr if not found 135 | */ 136 | virtual std::shared_ptr findClosestFor(); 137 | 138 | /** 139 | * Register class 140 | * @param referenceKey 141 | * @param classScope 142 | */ 143 | void registerClass(unsigned int referenceKey, std::shared_ptr classScope); 144 | 145 | /** 146 | * Register function 147 | * @param referenceKey 148 | * @param functionScope 149 | */ 150 | void registerFunction(unsigned int referenceKey, std::shared_ptr functionScope); 151 | 152 | /** 153 | * Register scope 154 | * @param referenceKey 155 | * @param scope 156 | */ 157 | void registerScope(unsigned int referenceKey, std::shared_ptr scope); 158 | 159 | /** 160 | * Register variable 161 | * @param referenceKey 162 | * @param variable 163 | */ 164 | void registerVariable(unsigned int referenceKey, std::shared_ptr variable); 165 | 166 | /** 167 | * Register an expression 168 | * @param referenceKey 169 | * @param expression 170 | */ 171 | void registerExpression(unsigned int referenceKey, std::shared_ptr expression); 172 | 173 | /** 174 | * Get an expression 175 | * @param referenceKey 176 | * @return function call 177 | */ 178 | std::shared_ptr getExpressionByReferenceKey(unsigned int referenceKey); 179 | 180 | /** 181 | * Set return statement 182 | * @param ret 183 | */ 184 | void setReturn(std::shared_ptr ret); 185 | 186 | /** 187 | * Get return statement 188 | * @return return statement 189 | */ 190 | std::shared_ptr getReturn() {return m_return;} 191 | 192 | /** 193 | * Check if scope has a return statement 194 | * @return true if it has a return statement 195 | */ 196 | bool hasReturn(); 197 | 198 | /** 199 | * Check if can use break or continue in this scope 200 | */ 201 | void canBreakOrContinue(std::shared_ptr lexicalToken); 202 | }; 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /docs/bc2b.md: -------------------------------------------------------------------------------- 1 | # BashClass to Bash 2 | 3 | ## How it works? 4 | ### Introduction 5 | BashClass syntax is close to other programming languages like C++ and Java, however, instead of compiling to machine code or bytecode, BashClass compiles to Bash. 6 | 7 | ### Classes 8 | Creating classes in Bash is not possible, but since Bash 4.0, the language added associative arrays which can be used as an alternative way to store a structure of an object. Using this feature, one can keep track of "objects" by assigning them a unique id as part of the key. A key is usually composed of two parts: the object id and the member name of the object. 9 | 10 | ### Functions 11 | Functions in BashClass are converted to Bash functions in the generated Bash script. Each statement in a BashClass function is also converted to its corresponding Bash representation while maintaining the original order. 12 | 13 | ### Type checking 14 | BashClass performs type checking at compile time. An expression can be forced to be of a specific type by casting it. The type of an object can also be checked at runtime (Please refer to the example files in the [example](example) page for further details). 15 | 16 | ### Reference 17 | An object variable that is initialized in BashClass (using the `new` keyword) stores the unique id of the created object. 18 | 19 | ### Expressions 20 | Expressions in BashClass are generated step by step following the same operator precedence used in bash. 21 | 22 | ### Return 23 | BashClass function can be of any type or void. In the generated bash script, the function call passes an additional argument by reference which will hold the "returned" value. 24 | 25 | ### Arrays 26 | BashClass achieves multi-dimensional arrays using associative arrays in bash where a key is a combination of the indices concatenated by a delimiter. 27 | 28 | ## Generated code example 29 | ### Code in BashClass 30 | ``` 31 | class Square { 32 | var int side; 33 | constructor Square(var int side=0) { 34 | this.side = side; 35 | } 36 | 37 | function int getArea() { 38 | return side * side; 39 | } 40 | } 41 | 42 | function void print(var int num) { 43 | ># echo $1 44 | } 45 | 46 | function int main() { 47 | var Square sq = new Square(10); 48 | print(sq.getArea()); 49 | return 0; 50 | } 51 | ``` 52 | 53 | ### Generated BASH script 54 | ``` 55 | #!/bin/bash 56 | # 57 | # Bash version 4.4+ required! 58 | # This code is auto generated by bashc, do not make manual changes 59 | # ----------------------------------------------------------------- 60 | # Initialize array counter 61 | _array_uid_=1 62 | 63 | # Initialize class object counter 64 | _object_uid_=1 65 | declare -A _object_ 66 | 67 | ############# BASH FUNCTIONS ############## 68 | # Create array 69 | function _bash_createArray() { 70 | declare -n _return_=${1} 71 | declare -g -A "_array_${_array_uid_}" 72 | _return_=${_array_uid_} 73 | _array_uid_=$(( ${_array_uid_} + 1 )) 74 | } 75 | # Convert strings into char array 76 | function _bash_StrToCharArray() { 77 | declare string="${1}" 78 | declare -n _return_=${2} 79 | _bash_createArray _tmp_return_ 80 | _return_=${_tmp_return_} 81 | declare index=0 82 | declare -n indexValue="_array_${_return_}" 83 | while (( ${index} < ${#string} )); do 84 | indexValue[${index}]=${string:${index}:1} 85 | index=$(( ${index} + 1 )) 86 | done 87 | } 88 | ########################################### 89 | 90 | # Create function 91 | function _c_Square_f_Square() { 92 | declare _args_counter_=1 93 | 94 | # Create argument with a default value 95 | if (( 0 < $(( ${#} - 0 )) )); then 96 | declare _c_Square_f_Square_p_side="${1}" 97 | _args_counter_=$(( ${_args_counter_} + 1 )) 98 | else 99 | declare _c_Square_f_Square_p_side=0 100 | declare -n _result_0=_c_Square_f_Square_p_side 101 | _result_0=0 102 | declare _expression_0="${_result_0:-0}" 103 | _c_Square_f_Square_p_side=${_expression_0:-0} 104 | fi 105 | 106 | # Configure 'this' 107 | declare _this_=${!_args_counter_} 108 | _args_counter_=$(( ${_args_counter_} + 1 )) 109 | 110 | # Configure return statement 111 | declare -n _return_=${!_args_counter_} 112 | 113 | # Declare member 114 | _object_[${_this_},"_c_Square_v_side"]=0 115 | 116 | # Header info 117 | [[ -v _object_[${_this_},"__type__"] ]] || _object_[${_this_},"__type__"]="Square" 118 | # Evaluate expression 119 | declare _result_1=${_this_} 120 | declare -n _result_2=_object_[${_result_1},"_c_Square_v_side"] 121 | declare -n _result_3=_c_Square_f_Square_p_side 122 | _result_2=${_result_3:-0} 123 | declare _expression_1="${_result_2:-0}" 124 | 125 | # Return statement 126 | _return_=${_this_} 127 | } 128 | 129 | # Create function 130 | function _c_Square_f_getArea() { 131 | declare _args_counter_=1 132 | 133 | # Configure 'this' 134 | declare _this_=${!_args_counter_} 135 | _args_counter_=$(( ${_args_counter_} + 1 )) 136 | 137 | # Configure return statement 138 | declare -n _return_=${!_args_counter_} 139 | 140 | # Return statement 141 | declare -n _result_4=_object_[${_this_},"_c_Square_v_side"] 142 | declare -n _result_5=_object_[${_this_},"_c_Square_v_side"] 143 | declare _expression_2=$(( ${_result_4:-0} * ${_result_5:-0} )) 144 | _return_=${_expression_2:-0} 145 | return 146 | } 147 | 148 | # Create function 149 | function _f_print() { 150 | declare _args_counter_=1 151 | 152 | # Create argument 153 | declare _f_print_p_num="${1}" 154 | _args_counter_=$(( ${_args_counter_} + 1 )) 155 | 156 | # Run BASH code 157 | echo $1 158 | } 159 | 160 | # Create function 161 | function _f_main() { 162 | declare _args_counter_=1 163 | 164 | # Configure return statement 165 | declare -n _return_=${!_args_counter_} 166 | 167 | # Create variable 168 | declare _f_main_v_sq=0 169 | 170 | # Initialize variable 171 | declare -n _result_6=_f_main_v_sq 172 | declare _result_7 173 | _c_Square_f_Square "10" $(( _object_uid_++ )) _tmp_return_ 174 | _result_7=${_tmp_return_} 175 | _result_6=${_result_7:-0} 176 | declare _expression_3="${_result_6:-0}" 177 | 178 | # Evaluate expression 179 | declare -n _result_8=_f_main_v_sq 180 | declare _result_9 181 | _c_Square_f_getArea ${_result_8} _tmp_return_ 182 | _result_9=${_tmp_return_} 183 | _f_print "${_result_9:-0}" 184 | 185 | # Return statement 186 | _return_=0 187 | return 188 | } 189 | 190 | # Run main function 191 | _f_main _main_return_ 192 | exit ${_main_return_} 193 | 194 | # ----------------------------------------------------------------- 195 | ``` 196 | -------------------------------------------------------------------------------- /src/expression/BArithOperation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | const std::string BArithOperation::OP_LOGICAL_OR = "logical_or"; 9 | const std::string BArithOperation::OP_LOGICAL_AND = "logical_and"; 10 | const std::string BArithOperation::OP_IS_EQUAL = "is_equal"; 11 | const std::string BArithOperation::OP_IS_NOT_EQUAL = "is_not_equal"; 12 | const std::string BArithOperation::OP_LESS_THAN = "less_than"; 13 | const std::string BArithOperation::OP_GREATER_THAN = "greater_than"; 14 | const std::string BArithOperation::OP_LESS_OR_EQUAL = "less_equal_than"; 15 | const std::string BArithOperation::OP_GREATER_OR_EQUAL = "greater_equal_than"; 16 | const std::string BArithOperation::OP_NOT = "not"; 17 | const std::string BArithOperation::OP_BIT_OR = "bit_or"; 18 | const std::string BArithOperation::OP_BIT_XOR = "bit_xor"; 19 | const std::string BArithOperation::OP_BIT_AND = "bit_and"; 20 | const std::string BArithOperation::OP_LEFT_SHIFT = "left_shift"; 21 | const std::string BArithOperation::OP_RIGHT_SHIFT = "right_shift"; 22 | const std::string BArithOperation::OP_MINUS = "minus"; 23 | const std::string BArithOperation::OP_MULTIPLY = "multiply"; 24 | const std::string BArithOperation::OP_DIVIDE = "divide"; 25 | const std::string BArithOperation::OP_MOD = "mod"; 26 | const std::string BArithOperation::OP_EXPONENTIAL = "exponential"; 27 | const std::string BArithOperation::OP_PLUS = "plus"; 28 | const std::string BArithOperation::OP_ASSIGN = "assign"; 29 | 30 | 31 | std::shared_ptr BArithOperation::_evaluateRightOperand() { 32 | std::shared_ptr singleOperandType = m_rightOperand->getType(); 33 | 34 | // UNDEFINED 35 | if(singleOperandType->isUndefined()) { 36 | return singleOperandType; 37 | } 38 | 39 | // ! 40 | if(m_operatorToken->getName() == OP_NOT) { 41 | if(singleOperandType->isBoolean() && !singleOperandType->isArray()) { 42 | return singleOperandType; 43 | } 44 | 45 | BReport::getInstance().error() 46 | << "Operator " << m_operatorToken->getValue() 47 | << " expects operand to be a boolean" << std::endl; 48 | BReport::getInstance().printError(); 49 | return BTypeFactory::createUndefinedExpressionType(); 50 | } 51 | 52 | // +, - 53 | if(m_operatorToken->getName() == OP_PLUS || m_operatorToken->getName() == OP_MINUS) { 54 | if(singleOperandType->isInt() && !singleOperandType->isArray()) { 55 | return singleOperandType; 56 | } 57 | 58 | BReport::getInstance().error() 59 | << "Operator " << m_operatorToken->getValue() 60 | << " expects operand to be an integer" << std::endl; 61 | BReport::getInstance().printError(); 62 | return BTypeFactory::createUndefinedExpressionType(); 63 | } 64 | 65 | throw BException("Undefined operator in an expression with one operand"); 66 | } 67 | 68 | std::shared_ptr BArithOperation::_evaluateTwoOperands() { 69 | std::shared_ptr leftType = m_leftOperand->getType(); 70 | std::shared_ptr rightType = m_rightOperand->getType(); 71 | 72 | // UNDEFINED 73 | if(leftType->isUndefined() || rightType->isUndefined()) { 74 | return leftType; 75 | } 76 | 77 | // ==, != 78 | if(m_operatorToken->getName() == OP_IS_EQUAL || m_operatorToken->getName() == OP_IS_NOT_EQUAL) { 79 | if((leftType->getTypeValue() == rightType->getTypeValue() 80 | && leftType->getDimension() == rightType->getDimension()) 81 | || (leftType->isArray() && rightType->isNull()) 82 | || (rightType->isArray() && leftType->isNull()) 83 | || (leftType->isIdentifier() && rightType->isNull()) 84 | || (rightType->isIdentifier() && leftType->isNull())) { 85 | return BTypeFactory::createBooleanExpressionType(); 86 | } 87 | 88 | BReport::getInstance().error() 89 | << "Boolean expression with " << m_operatorToken->getValue() 90 | << " operator requires both operand to be of the same type." << std::endl; 91 | BReport::getInstance().printError(); 92 | return BTypeFactory::createUndefinedExpressionType(); 93 | } 94 | 95 | // ||, && 96 | if(m_operatorToken->getName() == OP_LOGICAL_OR || m_operatorToken->getName() == OP_LOGICAL_AND) { 97 | if(leftType->isBoolean() && rightType->isBoolean() && !leftType->isArray() && !rightType->isArray()) { 98 | return leftType; 99 | } 100 | 101 | BReport::getInstance().error() 102 | << "Boolean expression with " << m_operatorToken->getValue() 103 | << " operator requires both operands to be of boolean type" << std::endl; 104 | BReport::getInstance().printError(); 105 | return BTypeFactory::createUndefinedExpressionType(); 106 | } 107 | 108 | // <, >, <=, >= 109 | if(m_operatorToken->getName() == OP_LESS_THAN || m_operatorToken->getName() == OP_GREATER_THAN 110 | || m_operatorToken->getName() == OP_LESS_OR_EQUAL || m_operatorToken->getName() == OP_GREATER_OR_EQUAL) { 111 | 112 | if(leftType->isInt() && rightType->isInt() && !leftType->isArray() && !rightType->isArray()) { 113 | return BTypeFactory::createBooleanExpressionType(); 114 | } 115 | 116 | BReport::getInstance().error() 117 | << "Boolean expression with " << m_operatorToken->getValue() 118 | << " operator requires both operands to be of integer type" << std::endl; 119 | BReport::getInstance().printError(); 120 | return BTypeFactory::createUndefinedExpressionType(); 121 | } 122 | 123 | // |, ^, &, <<, >>, -, *, /, %, ** 124 | if(m_operatorToken->getName() == OP_BIT_OR || m_operatorToken->getName() == OP_BIT_XOR 125 | || m_operatorToken->getName() == OP_BIT_AND || m_operatorToken->getName() == OP_LEFT_SHIFT 126 | || m_operatorToken->getName() == OP_RIGHT_SHIFT || m_operatorToken->getName() == OP_MINUS 127 | || m_operatorToken->getName() == OP_MULTIPLY || m_operatorToken->getName() == OP_DIVIDE 128 | || m_operatorToken->getName() == OP_MOD || m_operatorToken->getName() == OP_EXPONENTIAL) { 129 | 130 | if(leftType->isInt() && rightType->isInt() && !leftType->isArray() && !rightType->isArray()) { 131 | return leftType; 132 | } 133 | 134 | BReport::getInstance().error() 135 | << "Integer expression with " << m_operatorToken->getValue() 136 | << " operator requires both operands to be of integer type" << std::endl; 137 | BReport::getInstance().printError(); 138 | return BTypeFactory::createUndefinedExpressionType(); 139 | } 140 | 141 | // + 142 | if(m_operatorToken->getName() == OP_PLUS) { 143 | 144 | if(leftType->isInt() && rightType->isInt() && !leftType->isArray() && !rightType->isArray()) { 145 | return leftType; 146 | } 147 | 148 | BReport::getInstance().error() 149 | << "Operator " << m_operatorToken->getValue() 150 | << " requires both operands to be integers" << std::endl; 151 | BReport::getInstance().printError(); 152 | return BTypeFactory::createUndefinedExpressionType(); 153 | } 154 | 155 | // = 156 | if(m_operatorToken->getName() == OP_ASSIGN) { 157 | 158 | // Left hand side must be a variable access 159 | auto variableAccessCast = std::dynamic_pointer_cast(m_leftOperand); 160 | if(variableAccessCast) { 161 | 162 | if(!variableAccessCast->last()->getVariable()) { 163 | throw BException("Cannot evaluate assignment type of an undefined variable access"); 164 | } 165 | 166 | // Check if type is compatible 167 | if(leftType->isCompatible(rightType)) { 168 | return leftType; 169 | } 170 | 171 | BReport::getInstance().error() 172 | << "Variable " << variableAccessCast->last()->getVariable()->getName()->getValue() 173 | << " expects an expression of type " 174 | << leftType->toString() << " but given " << rightType->toString() << std::endl; 175 | BReport::getInstance().printError(); 176 | return BTypeFactory::createUndefinedExpressionType(); 177 | } 178 | 179 | BReport::getInstance().error() 180 | << "Operator " << m_operatorToken->getValue() 181 | << " requires left operand to be a variable" << std::endl; 182 | BReport::getInstance().printError(); 183 | return BTypeFactory::createUndefinedExpressionType(); 184 | } 185 | throw BException("Undefined operator in an expression with two operands"); 186 | } 187 | 188 | void BArithOperation::evaluate() { 189 | 190 | // Check if expression is composed of one operand or two operands 191 | if(m_leftOperand && m_rightOperand) { 192 | m_type = _evaluateTwoOperands(); 193 | } else if(m_rightOperand) { 194 | m_type = _evaluateRightOperand(); 195 | } else { 196 | throw BException("Arithmetic operation is not composed correctly"); 197 | } 198 | } 199 | 200 | void BArithOperation::castType(std::shared_ptr type) { 201 | m_type->cast(type); 202 | } -------------------------------------------------------------------------------- /resources/src/grammar.json: -------------------------------------------------------------------------------- 1 | { 2 | "START": ["#start# START_BODY #end#"], 3 | "START_BODY": ["EPSILON","CLASS_DEC START_BODY","FUNCTION_DEC START_BODY","VARIABLE_DEC START_BODY","BASH_DEC START_BODY"], 4 | 5 | "CLASS_DEC": ["#newKey# CLASS #startClass# CLASS_NAME #className# CLASS_EXTENDS OPEN_CUR CLASS_BODY CLOSE_CUR #endClass#"], 6 | "CLASS" : ["'class'"], 7 | "CLASS_NAME" : ["'identifier'"], 8 | "CLASS_EXTENDS" : ["EPSILON","EXTENDS CLASS_NAME #classExtends#"], 9 | "CLASS_BODY" : ["EPSILON","CLASS_VARIABLE_DEC CLASS_BODY","FUNCTION_DEC CLASS_BODY","CONSTRUCTOR_DEC CLASS_BODY"], 10 | "CLASS_VARIABLE_DEC" : ["#newKey# VARIABLE #startClassVar# VARIABLE_TYPE #classVarType# VAR_ARRAY_TYPE_OPT_A VARIABLE_NAME #classVarName# VARIABLE_INIT SEMICOLON #endClassVar#"], 11 | "VAR_ARRAY_TYPE_A": ["OPEN_SQ CLOSE_SQ #arrayVar1#"], 12 | "VAR_ARRAY_TYPE_OPT_A": ["EPSILON","VAR_ARRAY_TYPE_A VAR_ARRAY_TYPE_OPT_A"], 13 | 14 | "EXTENDS" : ["'extends'"], 15 | 16 | "CONSTRUCTOR_DEC" : ["#newKey# CONSTRUCTOR #startFunction# #functionConstructor# FUNCTION_NAME #functionType# #functionName# OPEN_PAR FUNCTION_PARAM_DEC CLOSE_PAR OPEN_CUR CONSTRUCTOR_BODY CLOSE_CUR #endFunction#"], 17 | "CONSTRUCTOR": ["'constructor'"], 18 | "CONSTRUCTOR_BODY" : ["#startChain# SUPER_CONSTRUCTOR #superConstructorChainCall# IDENTIFIER_FUNCTION_CALL #functionCall# #endChain# #evalExpr# SEMICOLON FUNCTION_BODY", "#noSuperConstructor# FUNCTION_BODY"], 19 | "SUPER_CONSTRUCTOR" : ["'super_constructor'"], 20 | 21 | "FUNCTION_DEC" : ["#newKey# FUNCTION #startFunction# FUNCTION_EXTENDED_TYPE FUNCTION_NAME #functionName# OPEN_PAR FUNCTION_PARAM_DEC CLOSE_PAR OPEN_CUR FUNCTION_BODY CLOSE_CUR #endFunction#"], 22 | "FUNCTION": ["'function'"], 23 | "FUNCTION_EXTENDED_TYPE" : ["'void_type' #functionType#","VARIABLE_TYPE #functionType# FUNC_ARRAY_TYPE_OPT"], 24 | "FUNCTION_NAME" : ["'identifier'"], 25 | "FUNCTION_BODY" : ["EPSILON","VARIABLE_DEC FUNCTION_BODY","#newKey# EXPR_DEC #evalExpr# SEMICOLON FUNCTION_BODY","STATEMENT FUNCTION_BODY","RETURN_DEC FUNCTION_BODY","BASH_DEC FUNCTION_BODY"], 26 | "FUNCTION_PARAM_DEC" : ["EPSILON","FUNCTION_PARAM_A"], 27 | "FUNCTION_PARAM_A" : ["#newKey# VARIABLE #startParam# VARIABLE_TYPE #paramType# VAR_ARRAY_TYPE_OPT_A VARIABLE_NAME #paramName# VARIABLE_INIT #endParam# FUNCTION_PARAM_B"], 28 | "FUNCTION_PARAM_B" : ["EPSILON","COMMA FUNCTION_PARAM_A"], 29 | "FUNC_ARRAY_TYPE": ["OPEN_SQ CLOSE_SQ #arrayFunc#"], 30 | "FUNC_ARRAY_TYPE_OPT": ["EPSILON","FUNC_ARRAY_TYPE FUNC_ARRAY_TYPE_OPT"], 31 | 32 | "BASH_DEC" : ["BASH_INLINE #bashCode#", "BASH_BLOCK #bashCode#"], 33 | "BASH_INLINE" : ["'bash_inline'"], 34 | "BASH_BLOCK" : ["'bash_block'"], 35 | 36 | "VARIABLE_DEC" : ["#newKey# VARIABLE #startVar# VARIABLE_TYPE #varType# VAR_ARRAY_TYPE_OPT_B VARIABLE_NAME #varName# VARIABLE_INIT SEMICOLON #endVar#"], 37 | "VARIABLE_INIT" : ["EPSILON","#varAsOperand# OP_GROUP_AA #putOp# EXPR_A EXPR_AB #createExpr2# #varInit#"], 38 | "VARIABLE" : ["'var'"], 39 | "VARIABLE_TYPE" : ["'identifier'","'int_type'","'boolean_type'","'char_type'"], 40 | "VARIABLE_NAME" : ["'identifier'"], 41 | "VAR_ARRAY_TYPE_B": ["OPEN_SQ CLOSE_SQ #arrayVar2#"], 42 | "VAR_ARRAY_TYPE_OPT_B": ["EPSILON","VAR_ARRAY_TYPE_B VAR_ARRAY_TYPE_OPT_B"], 43 | 44 | "RETURN_DEC" : ["RETURN #startReturn# RETURN_OPT_EXPR SEMICOLON #endReturn#"], 45 | "RETURN_OPT_EXPR": ["EXPR_DEC #returnExpr#","EPSILON #returnVoid#"], 46 | "RETURN" : ["'return'"], 47 | 48 | "STATEMENT" : [ 49 | "#newKey# IF #startIf# OPEN_PAR EXPR_DEC #ifCond# CLOSE_PAR OPEN_CUR STATEMENT_BODY STATEMENT_BODY_RPT CLOSE_CUR #endIf# ELIF_OPT ELSE_OPT", 50 | "#newKey# WHILE #startWhile# OPEN_PAR EXPR_DEC #whileCond# CLOSE_PAR OPEN_CUR STATEMENT_BODY STATEMENT_BODY_RPT CLOSE_CUR #endWhile#", 51 | "#newKey# FOR #startFor# OPEN_PAR FOR_PRE_COND FOR_COND FOR_POST_COND CLOSE_PAR OPEN_CUR STATEMENT_BODY STATEMENT_BODY_RPT CLOSE_CUR #endFor#" 52 | ], 53 | "STATEMENT_BODY" : ["VARIABLE_DEC", "#newKey# EXPR_DEC #evalExpr# SEMICOLON","STATEMENT","RETURN_DEC", "BASH_DEC", "BREAK #breakContinue# SEMICOLON", "CONTINUE #breakContinue# SEMICOLON"], 54 | "STATEMENT_BODY_RPT" : ["EPSILON","STATEMENT_BODY STATEMENT_BODY_RPT"], 55 | 56 | "ELIF_OPT" : ["EPSILON", "#newKey# ELIF #startElif# OPEN_PAR EXPR_DEC #elifCond# CLOSE_PAR OPEN_CUR STATEMENT_BODY STATEMENT_BODY_RPT CLOSE_CUR #endElif# ELIF_OPT"], 57 | "ELSE_OPT" : ["EPSILON", "#newKey# ELSE #startElse# OPEN_CUR STATEMENT_BODY STATEMENT_BODY_RPT CLOSE_CUR #endElse#"], 58 | 59 | "IF" : ["'if'"], 60 | "ELIF" : ["'elif'"], 61 | "ELSE" : ["'else'"], 62 | "WHILE" : ["'while'"], 63 | "FOR" : ["'for'"], 64 | "BREAK" : ["'break'"], 65 | "CONTINUE" : ["'continue'"], 66 | 67 | "FOR_PRE_COND" : ["SEMICOLON", "EXPR_DEC #forPreCond# SEMICOLON"], 68 | "FOR_COND" : ["SEMICOLON", "EXPR_DEC #forCond# SEMICOLON"], 69 | "FOR_POST_COND" : ["EPSILON", "EXPR_DEC #forPostCond#"], 70 | 71 | "OPEN_PAR" : ["'open_parenthesis'"], 72 | "CLOSE_PAR" : ["'close_parenthesis'"], 73 | 74 | "OPEN_CUR" : ["'open_curly'"], 75 | "CLOSE_CUR" : ["'close_curly'"], 76 | 77 | "OPEN_SQ" : ["'open_square'"], 78 | "CLOSE_SQ" : ["'close_square'"], 79 | 80 | "COMMA" : ["'comma'"], 81 | "SEMICOLON" : ["'semicolon'"], 82 | "DOT" : ["'dot'"], 83 | 84 | "EXPR_DEC" : ["EXPR_AA"], 85 | "EXPR_AA" : ["EXPR_A EXPR_AB"], 86 | "EXPR_AB" : ["EPSILON","OP_GROUP_AA #putOp# EXPR_A EXPR_AB #createExpr2#"], 87 | "EXPR_A" : ["EXPR_C EXPR_B"], 88 | "EXPR_B" : ["EPSILON","OP_GROUP_A #putOp# EXPR_C #createExpr2# EXPR_B"], 89 | "EXPR_C" : ["EXPR_E EXPR_D"], 90 | "EXPR_D" : ["EPSILON","OP_GROUP_B #putOp# EXPR_E #createExpr2# EXPR_D"], 91 | "EXPR_E" : ["EXPR_G EXPR_F"], 92 | "EXPR_F" : ["EPSILON","OP_GROUP_C #putOp# EXPR_G #createExpr2# EXPR_F"], 93 | "EXPR_G" : ["EXPR_I EXPR_H"], 94 | "EXPR_H" : ["EPSILON","OP_GROUP_D #putOp# EXPR_I #createExpr2# EXPR_H"], 95 | "EXPR_I" : ["EXPR_K EXPR_J"], 96 | "EXPR_J" : ["EPSILON","OP_GROUP_E #putOp# EXPR_K #createExpr2# EXPR_J"], 97 | "EXPR_K" : ["EXPR_M EXPR_L"], 98 | "EXPR_L" : ["EPSILON","OP_GROUP_F #putOp# EXPR_M #createExpr2# EXPR_L"], 99 | "EXPR_M" : ["EXPR_O EXPR_N"], 100 | "EXPR_N" : ["EPSILON","OP_GROUP_G #putOp# EXPR_O #createExpr2# EXPR_N"], 101 | "EXPR_O" : ["EXPR_Q EXPR_P"], 102 | "EXPR_P" : ["EPSILON","OP_GROUP_H #putOp# EXPR_Q #createExpr2# EXPR_P"], 103 | "EXPR_Q" : ["EXPR_S EXPR_R"], 104 | "EXPR_R" : ["EPSILON","OP_GROUP_I #putOp# EXPR_S #createExpr2# EXPR_R"], 105 | "EXPR_S" : ["EXPR_U EXPR_T"], 106 | "EXPR_T" : ["EPSILON","OP_GROUP_J #putOp# EXPR_U #createExpr2# EXPR_T"], 107 | "EXPR_U" : ["EXPR_W EXPR_V"], 108 | "EXPR_V" : ["EPSILON","OP_GROUP_K #putOp# EXPR_W #createExpr2# EXPR_V"], 109 | "EXPR_W" : ["EXPR_X","OP_GROUP_L #putOp# EXPR_X #createExpr1#"], 110 | "EXPR_X" : ["EXPR_Y","OP_GROUP_I #putOp# EXPR_Y #createExpr1#"], 111 | "EXPR_Y" : ["OPEN_PAR EXPR_AA CLOSE_PAR CAST_EXPR","ARITH_ID"], 112 | 113 | "CAST_EXPR" : ["EPSILON","COLON VARIABLE_TYPE #castType# CAST_ARRAY #castExpr#"], 114 | 115 | "OPEN_CLOSE_SQ" : ["OPEN_SQ CLOSE_SQ"], 116 | "CAST_ARRAY" : ["EPSILON","OPEN_CLOSE_SQ #castArray# CAST_ARRAY"], 117 | 118 | "ARITH_ID" : [ 119 | "'integer' #tokenUse#", 120 | "'character' #tokenUse#", 121 | "'truefalse' #tokenUse#", 122 | "'string_literal' #tokenUse#", 123 | "'null' #tokenUse#", 124 | "'bash_sub' #tokenUse#", 125 | "'bash_sub_int' #tokenUse#", 126 | "NEW VARIABLE_TYPE NEW_CONS_OR_ARRAY", 127 | "ARITH_VAR_OR_FUNC_CALL" 128 | ], 129 | "NEW": ["'new'"], 130 | "COLON" : ["'colon'"], 131 | 132 | "NEW_CONS_OR_ARRAY" : [ 133 | "#startChain# #constructorChainCall# IDENTIFIER_FUNCTION_CALL ARITH_VAR_OR_FUNC_CALL_D #endChain#", 134 | "#newArray# #arrayUseType# ARRAY_USE ARRAY_USE_OPT" 135 | ], 136 | 137 | "ARRAY_USE" : ["OPEN_SQ CLOSE_SQ #arrayUseDim#"], 138 | "ARRAY_USE_OPT" : ["EPSILON","ARRAY_USE ARRAY_USE_OPT"], 139 | 140 | "ARITH_VAR_OR_FUNC_CALL" : ["#startChain# ARITH_VAR_OR_FUNC_CALL_A #endChain#"], 141 | "ARITH_VAR_OR_FUNC_CALL_A" : ["THIS ARITH_VAR_OR_FUNC_CALL_E", "ARITH_VAR_OR_FUNC_CALL_B","SUPER #superChainAccess# DOT ARITH_VAR_OR_FUNC_CALL_B"], 142 | "ARITH_VAR_OR_FUNC_CALL_B" : ["IDENTIFIER ARITH_VAR_OR_FUNC_CALL_C"], 143 | "ARITH_VAR_OR_FUNC_CALL_C" : ["#varChainAccess# INDEX_OPT ARITH_VAR_OR_FUNC_CALL_F","#functionChainCall# IDENTIFIER_FUNCTION_CALL INDEX_OPT ARITH_VAR_OR_FUNC_CALL_D"], 144 | "ARITH_VAR_OR_FUNC_CALL_D" : ["#functionCall# EPSILON","DOT ARITH_VAR_OR_FUNC_CALL_B"], 145 | "ARITH_VAR_OR_FUNC_CALL_E" : ["#thisChainAccess# DOT ARITH_VAR_OR_FUNC_CALL_B","#thisAccess# EPSILON"], 146 | "ARITH_VAR_OR_FUNC_CALL_F" : ["#varAccess# EPSILON","DOT ARITH_VAR_OR_FUNC_CALL_B"], 147 | 148 | "INDEX" : ["OPEN_SQ EXPR_DEC #indexAccess# CLOSE_SQ"], 149 | "INDEX_OPT" : ["EPSILON","INDEX INDEX_OPT"], 150 | 151 | "THIS" : ["'this_ref'"], 152 | "SUPER" : ["'super'"], 153 | 154 | "OP_GROUP_AA" : ["'assign'"], 155 | "OP_GROUP_A" : ["'logical_or'"], 156 | "OP_GROUP_B" : ["'logical_and'"], 157 | "OP_GROUP_C" : ["'bit_or'"], 158 | "OP_GROUP_D" : ["'bit_xor'"], 159 | "OP_GROUP_E" : ["'bit_and'"], 160 | "OP_GROUP_F" : ["'is_equal'","'is_not_equal'"], 161 | "OP_GROUP_G" : ["'less_than'","'greater_than'","'less_equal_than'","'greater_equal_than'"], 162 | "OP_GROUP_H" : ["'left_shift'","'right_shift'"], 163 | "OP_GROUP_I" : ["'plus'","'minus'"], 164 | "OP_GROUP_J" : ["'multiply'","'divide'","'mod'"], 165 | "OP_GROUP_K" : ["'exponential'"], 166 | "OP_GROUP_L" : ["'not'"], 167 | 168 | "IDENTIFIER" : ["'identifier'"], 169 | "IDENTIFIER_FUNCTION_CALL" : ["OPEN_PAR #startArgument# IDENTIFIER_FUNCTION_ARG_DEC #endArgument# CLOSE_PAR"], 170 | "IDENTIFIER_FUNCTION_ARG_DEC" : ["EPSILON", "IDENTIFIER_FUNCTION_ARG_A"], 171 | "IDENTIFIER_FUNCTION_ARG_A" : ["EXPR_DEC #setArgument# IDENTIFIER_FUNCTION_ARG_B"], 172 | "IDENTIFIER_FUNCTION_ARG_B" : ["EPSILON","COMMA IDENTIFIER_FUNCTION_ARG_A"] 173 | } 174 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/scope/BScope.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | std::vector> BScope::findAllVariables(const char* name) { 19 | std::vector> variables; 20 | for(auto variable : m_variables) { 21 | if(!name || (variable.second->getName() && variable.second->getName()->getValue() == name)) { 22 | variables.push_back(variable.second); 23 | } 24 | } 25 | return variables; 26 | } 27 | 28 | std::vector> BScope::findAllClasses(const char* name) { 29 | std::vector> classes; 30 | for(auto scope : m_scopes) { 31 | std::shared_ptr classScope = std::dynamic_pointer_cast(scope.second); 32 | if(classScope) { 33 | if(!classScope->getName()) { 34 | throw BException("Finding classes requires a class name to be defined"); 35 | } 36 | 37 | if(!name || (classScope->getName()->getValue() == name)) { 38 | classes.push_back(classScope); 39 | } 40 | } 41 | } 42 | return classes; 43 | } 44 | 45 | std::vector> BScope::findAllFunctions(const char *name) { 46 | std::vector> functions; 47 | for(auto scope : m_scopes) { 48 | std::shared_ptr functionScope = std::dynamic_pointer_cast(scope.second); 49 | if(functionScope) { 50 | if(!functionScope->getName()) { 51 | throw BException("Finding functions requires a function name to be defined"); 52 | } 53 | 54 | if (!name || (functionScope->getName()->getValue() == name)) { 55 | functions.push_back(functionScope); 56 | } 57 | } 58 | } 59 | return functions; 60 | } 61 | 62 | std::shared_ptr BScope::getScopeByReferenceKey(unsigned int referenceKey) { 63 | if(m_scopes.find(referenceKey) != m_scopes.end()) { 64 | return m_scopes[referenceKey]; 65 | } 66 | throw BException("Requesting scope with an unrecognized reference key"); 67 | } 68 | 69 | std::shared_ptr BScope::getVariableByReferenceKey(unsigned int referenceKey) { 70 | if(m_variables.find(referenceKey) != m_variables.end()) { 71 | return m_variables[referenceKey]; 72 | } 73 | throw BException("Requesting variable with an unrecognized reference key"); 74 | } 75 | 76 | std::vector> BScope::getAllScopes() { 77 | std::vector> scopes; 78 | for(auto pair : m_scopes) { 79 | scopes.push_back(pair.second); 80 | } 81 | return scopes; 82 | } 83 | 84 | std::shared_ptr BScope::findClosestVariable(std::string name) { 85 | auto variables = findAllVariables(name.c_str()); 86 | if(!variables.empty()) { 87 | // If multiple variable definition were found (semantic error), also select the front 88 | return variables.front(); 89 | } 90 | return m_parentScope ? m_parentScope->findClosestVariable(name) : nullptr; 91 | } 92 | 93 | std::stringstream BScope::getStructure() { 94 | std::stringstream structure; 95 | std::stack> structureStack; 96 | structureStack.push(shared_from_this()); 97 | while(!structureStack.empty()) { 98 | 99 | // Get the top of the stack 100 | std::shared_ptr top = structureStack.top(); 101 | structureStack.pop(); 102 | 103 | structure << "Scope: " << top->getLabel().str() << std::endl; 104 | for(auto variable : top->findAllVariables()) { 105 | structure << "Variable: " << variable->getLabel().str() << std::endl; 106 | } 107 | 108 | // Push all children scopes 109 | for(auto scope : top->m_scopes) { 110 | structureStack.push(scope.second); 111 | } 112 | } 113 | return structure; 114 | } 115 | 116 | void BScope::registerClass(unsigned int referenceKey, std::shared_ptr classScope) { 117 | 118 | // Class name is required 119 | if(!classScope->getName()) { 120 | throw BException("Cannot register a class without specifying its name first"); 121 | } 122 | 123 | // Check if class was added previously 124 | auto getClass = findAllClasses(classScope->getName()->getValue().c_str()); 125 | if(!getClass.empty()) { 126 | BReport::getInstance().error() 127 | << "Class " << classScope->getName()->getValue() << " at line " 128 | << classScope->getName()->getLine() << " was defined previously" << std::endl; 129 | BReport::getInstance().printError(); 130 | } 131 | 132 | // Register class in this scope 133 | registerScope(referenceKey, classScope); 134 | } 135 | 136 | void BScope::registerFunction(unsigned int referenceKey, std::shared_ptr functionScope) { 137 | 138 | // Function name is required 139 | if(!functionScope->getName()) { 140 | throw BException("Cannot register a function without specifying its name first"); 141 | } 142 | 143 | // Check if function was added previously 144 | auto getFunc = findAllFunctions(functionScope->getName()->getValue().c_str()); 145 | if(!getFunc.empty()) { 146 | BReport::getInstance().error() 147 | << "Function " << functionScope->getName()->getValue() << " at line " 148 | << functionScope->getName()->getLine() 149 | <<" was defined previously in the same scope" << std::endl; 150 | BReport::getInstance().printError(); 151 | } 152 | 153 | // Register function in this scope 154 | registerScope(referenceKey, functionScope); 155 | 156 | // Check the name of the function 157 | if(functionScope->isConstructor()) { 158 | 159 | auto parentClass = std::static_pointer_cast(functionScope->getParentScope()); 160 | 161 | if(!parentClass->getName()) { 162 | throw BException("Cannot verify if the constructor name is not defined"); 163 | } 164 | 165 | if(functionScope->getName()->getValue() != parentClass->getName()->getValue()) { 166 | BReport::getInstance().error() 167 | << "Constructor " << functionScope->getName()->getValue() << " at line " 168 | << functionScope->getName()->getLine() 169 | <<" must be named " << parentClass->getName()->getValue() << std::endl; 170 | BReport::getInstance().printError(); 171 | } 172 | } else if(functionScope->isClassMember()) { 173 | auto parentClass = std::static_pointer_cast(functionScope->getParentScope()); 174 | if(functionScope->getName()->getValue() == parentClass->getName()->getValue()) { 175 | BReport::getInstance().error() 176 | << "Function " << functionScope->getName()->getValue() << " at line " 177 | << functionScope->getName()->getLine() 178 | <<" cannot have a constructor name" << std::endl; 179 | BReport::getInstance().printError(); 180 | } 181 | } 182 | } 183 | 184 | void BScope::registerScope(unsigned int referenceKey, std::shared_ptr scope) { 185 | m_scopes[referenceKey] = scope; 186 | scope->setParentScope(shared_from_this()); 187 | } 188 | 189 | void BScope::registerVariable(unsigned int referenceKey, std::shared_ptr variable) { 190 | 191 | // Variable name is required 192 | if(!variable->getName()) { 193 | throw BException("Cannot register a variable without specifying its name"); 194 | } 195 | 196 | // Check if variable was added previously 197 | auto getVar = findAllVariables(variable->getName()->getValue().c_str()); 198 | if(!getVar.empty()) { 199 | BReport::getInstance().error() 200 | << (variable->isParam() ? "Parameter " : "Variable ") 201 | << variable->getName()->getValue() << " at line " << variable->getName()->getLine() 202 | << " was defined previously in the same scope" << std::endl; 203 | BReport::getInstance().printError(); 204 | } 205 | 206 | // Register variable in this scope 207 | m_variables[referenceKey] = variable; 208 | variable->setParentScope(shared_from_this()); 209 | } 210 | 211 | void BScope::setReturn(std::shared_ptr ret) { 212 | 213 | // If several return statement are found in the same scope, 214 | // then only the first one is registered 215 | if(m_return) { 216 | auto function = findClosestFunction(); 217 | BReport::getInstance().error() 218 | << "Multiple return statements are set within the same scope in function " 219 | << function->getName()->getValue() << std::endl; 220 | BReport::getInstance().printError(); 221 | } else { 222 | 223 | // Set return statement in this scope 224 | ret->setParentScope(shared_from_this()); 225 | m_return = ret; 226 | 227 | // Verify return statement 228 | ret->verifyReturn(); 229 | } 230 | } 231 | 232 | void BScope::registerExpression(unsigned int referenceKey, std::shared_ptr expression) { 233 | m_expressions[referenceKey] = expression; 234 | } 235 | 236 | std::shared_ptr BScope::getExpressionByReferenceKey(unsigned int referenceKey) { 237 | if(m_expressions.find(referenceKey) == m_expressions.end()) { 238 | throw BException("Requesting an expression with an unrecognized reference key"); 239 | } 240 | return m_expressions[referenceKey]; 241 | } 242 | 243 | bool BScope::hasReturn() { 244 | 245 | // Check if a return statement has been set in this scope 246 | if(m_return) { 247 | return true; 248 | } 249 | 250 | // Check if the scopes if/elif/else have a return 251 | for(auto scope : m_scopes) { 252 | auto ifScope = std::dynamic_pointer_cast(scope.second); 253 | if(ifScope) { 254 | 255 | // Check if the if statement has a return 256 | bool returnExist = ifScope->hasReturn(); 257 | 258 | // Check if all the elif has a return 259 | for(auto elifScope : ifScope->getElifScopes()) { 260 | returnExist &= elifScope->hasReturn(); 261 | } 262 | 263 | // Check if there is a an else statement and has a return 264 | if(returnExist && ifScope->getElse() && ifScope->getElse()->hasReturn()) { 265 | return true; 266 | } 267 | } 268 | } 269 | return false; 270 | } 271 | 272 | std::shared_ptr BScope::findClosestFunction() { 273 | if(!m_parentScope) { 274 | throw BException("Cannot find closest function for a scope with an undefined parent scope"); 275 | } 276 | return m_parentScope->findClosestFunction(); 277 | } 278 | 279 | std::shared_ptr BScope::findClosestClass() { 280 | if(!m_parentScope) { 281 | throw BException("Cannot find closest class for a scope with an undefined parent scope"); 282 | } 283 | return m_parentScope->findClosestClass(); 284 | } 285 | 286 | std::shared_ptr BScope::findClosestWhile() { 287 | if(!m_parentScope) { 288 | throw BException("Cannot find closest while loop for a scope with an undefined parent scope"); 289 | } 290 | return m_parentScope->findClosestWhile(); 291 | } 292 | 293 | std::shared_ptr BScope::findClosestFor() { 294 | if(!m_parentScope) { 295 | throw BException("Cannot find closest for loop for a scope with an undefined parent scope"); 296 | } 297 | return m_parentScope->findClosestFor(); 298 | } 299 | 300 | void BScope::canBreakOrContinue(std::shared_ptr lexicalToken) { 301 | if(!findClosestWhile() && !findClosestFor()) { 302 | BReport::getInstance().error() 303 | << "Cannot use " << lexicalToken->getValue() << " outside a loop at line " 304 | << lexicalToken->getLine() << " and column " << lexicalToken->getColumn() << std::endl; 305 | BReport::getInstance().printError(); 306 | } 307 | } -------------------------------------------------------------------------------- /src/chain/BChain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void BChain::addVariable(std::shared_ptr scope, std::shared_ptr token) { 12 | 13 | // Prepare variable call 14 | std::shared_ptr variableCall = std::make_shared(); 15 | variableCall->setLexicalToken(token); 16 | 17 | // Check if the variable is the first callable item to be added 18 | if(m_callables.empty()) { 19 | auto variable = scope->findClosestVariable(token->getValue()); 20 | if(variable) { 21 | variableCall->setVariable(variable); 22 | } else { 23 | BReport::getInstance().error() 24 | << "Undefined variable " << token->getValue() 25 | << " at line " << token->getLine() << " and column " 26 | << token->getColumn() << std::endl; 27 | BReport::getInstance().printError(); 28 | } 29 | } else { 30 | 31 | // Cast previous element 32 | auto lastElement = last(); 33 | 34 | // Check if previous element is recognized 35 | if(!lastElement->isFound()) { 36 | BReport::getInstance().error() 37 | << "Cannot access variable member " << token->getValue() 38 | << " of undefined at line " << token->getLine() << " and column " 39 | << token->getColumn() << std::endl; 40 | BReport::getInstance().printError(); 41 | } else { 42 | 43 | // Get the type of the previous element 44 | std::shared_ptr lastType = lastElement->getType(); 45 | 46 | // Check the type of the previous element 47 | if(lastType->isIdentifier()) { 48 | 49 | // If type was found 50 | if(lastType->getTypeScope()) { 51 | 52 | // Search for the new variable in class and its parent classes 53 | std::shared_ptr tmpClass = lastType->getTypeScope(); 54 | std::vector> variables; 55 | while(variables.empty() && tmpClass) { 56 | variables = tmpClass->findAllVariables(token->getValue().c_str()); 57 | tmpClass = tmpClass->getExtends(); 58 | } 59 | 60 | // Check if variable was found 61 | if(!variables.empty()) { 62 | variableCall->setVariable(variables.front()); 63 | } else { 64 | BReport::getInstance().error() 65 | << "Class " << lastType->getTypeScope()->getName()->getValue() 66 | << " does not have a variable member " 67 | << token->getValue() << " at line " 68 | << token->getLine() << " and column " 69 | << token->getColumn() << std::endl; 70 | BReport::getInstance().printError(); 71 | } 72 | } else { 73 | BReport::getInstance().error() 74 | << "Cannot find variable member " 75 | << token->getValue() << " at line " 76 | << token->getLine() << " and column " 77 | << token->getColumn() << " because the previous element has an undefined type" 78 | << std::endl; 79 | BReport::getInstance().printError(); 80 | } 81 | } else if(lastType->isBuiltInType()) { 82 | BReport::getInstance().error() 83 | << "Variable member " << token->getValue() 84 | << " at line " << token->getLine() 85 | << " and column " << token->getColumn() 86 | << " does not exist. Previous element type does not have any known members." << std::endl; 87 | BReport::getInstance().printError(); 88 | } else { 89 | throw BException("Cannot verify new variable type because previous element is of an unrecognized type"); 90 | } 91 | } 92 | } 93 | 94 | // Add variable to the chain 95 | m_callables.push_back(variableCall); 96 | } 97 | 98 | void BChain::addFunction(std::shared_ptr scope, std::shared_ptr token) { 99 | 100 | // Prepare function call 101 | auto functionCall = std::make_shared(); 102 | functionCall->setLexicalToken(token); 103 | 104 | // Check if the function is the first callable item to be added 105 | if(m_callables.empty()) { 106 | 107 | // If function call is inside a class, then start searching 108 | // for a function member of that class or its parent ones 109 | auto classScope = scope->findClosestClass(); 110 | if(classScope) { 111 | auto tmpClass = classScope; 112 | while(!functionCall->getFunction() && tmpClass) { 113 | auto functions = tmpClass->findAllFunctions(token->getValue().c_str()); 114 | if(!functions.empty()) { 115 | functionCall->setFunction(functions.front()); 116 | } 117 | tmpClass = tmpClass->getExtends(); 118 | } 119 | } 120 | 121 | // If not a class member, then search in the global scope 122 | if(!functionCall->getFunction()) { 123 | auto functions = BGlobal::getInstance()->findAllFunctions(token->getValue().c_str()); 124 | if(!functions.empty()) { 125 | functionCall->setFunction(functions.front()); 126 | } else { 127 | BReport::getInstance().error() 128 | << "Undefined function " << token->getValue() 129 | << " at line " << token->getLine() << " and column " 130 | << token->getColumn() << std::endl; 131 | BReport::getInstance().printError(); 132 | } 133 | 134 | } 135 | } else { 136 | 137 | // Cast previous element 138 | auto lastElement = last(); 139 | 140 | // Check if the previous element is recognized 141 | if(!lastElement->isFound()) { 142 | BReport::getInstance().error() 143 | << "Cannot access function member " << token->getValue() 144 | << " of undefined at line " << token->getLine() << " and column " 145 | << token->getColumn() << std::endl; 146 | BReport::getInstance().printError(); 147 | } else { 148 | 149 | // Get the type of the previous element 150 | auto lastType = lastElement->getType(); 151 | 152 | // Check the type of the previous element 153 | if(lastType->isIdentifier()) { 154 | 155 | // Check if type was found 156 | if(lastType->getTypeScope()) { 157 | auto tmpClass = lastType->getTypeScope(); 158 | std::vector> functions; 159 | while (functions.empty() && tmpClass) { 160 | functions = tmpClass->findAllFunctions(token->getValue().c_str()); 161 | tmpClass = tmpClass->getExtends(); 162 | } 163 | 164 | if(!functions.empty()) { 165 | functionCall->setFunction(functions.front()); 166 | } else { 167 | BReport::getInstance().error() 168 | << "Class " << lastType->getTypeScope()->getName()->getValue() 169 | << " does not have a function member " 170 | << token->getValue() << " at line " 171 | << token->getLine() << " and column " 172 | << token->getColumn() << std::endl; 173 | BReport::getInstance().printError(); 174 | } 175 | } else { 176 | BReport::getInstance().error() 177 | << "Cannot find function member " 178 | << token->getValue() << " at line " 179 | << token->getLine() << " and column " 180 | << token->getColumn() << " because the previous element has an undefined type" 181 | << std::endl; 182 | BReport::getInstance().printError(); 183 | } 184 | 185 | } else { 186 | BReport::getInstance().error() 187 | << "Function member " << token->getValue() 188 | << " at line " << token->getLine() 189 | << " and column " << token->getColumn() 190 | << " does not exist. Previous element type does not have any known members." << std::endl; 191 | BReport::getInstance().printError(); 192 | } 193 | } 194 | } 195 | 196 | // Add function to the chain 197 | m_callables.push_back(functionCall); 198 | } 199 | 200 | void BChain::addConstructor(std::shared_ptr scope, std::shared_ptr token) { 201 | 202 | // Prepare function call 203 | auto functionCall = std::make_shared(); 204 | functionCall->setLexicalToken(token); 205 | 206 | if(!m_callables.empty()) { 207 | throw BException("A constructor call must be at the beginning of the chain"); 208 | } 209 | 210 | // Search for the class and constructor 211 | auto classes = BGlobal::getInstance()->findAllClasses(token->getValue().c_str()); 212 | if(classes.empty()) { 213 | BReport::getInstance().error() 214 | << "Undefined class " << token->getValue() << " at line " << token->getLine() 215 | << " and column " << token->getColumn() << std::endl; 216 | BReport::getInstance().printError(); 217 | } else { 218 | 219 | // Search for the constructor 220 | auto functions = classes.front()->findAllConstructors(); 221 | 222 | // Set function if found 223 | if(functions.empty()) { 224 | BReport::getInstance().error() 225 | << "Call to an undefined constructor for class " << token->getValue() << " at line " << token->getLine() 226 | << " and column " << token->getColumn() << std::endl; 227 | BReport::getInstance().printError(); 228 | } else { 229 | functionCall->setFunction(functions.front()); 230 | } 231 | } 232 | 233 | // Add function to the chain 234 | m_callables.push_back(functionCall); 235 | } 236 | 237 | void BChain::addSuperConstructor(std::shared_ptr scope, std::shared_ptr token) { 238 | 239 | // Prepare function call 240 | auto functionCall = std::make_shared(); 241 | functionCall->setLexicalToken(token); 242 | 243 | if(!m_callables.empty()) { 244 | throw BException("A super constructor call must be at the beginning of the chain"); 245 | } 246 | 247 | // Search for the class and constructor 248 | auto classScope = scope->findClosestClass(); 249 | if(!classScope) { 250 | BReport::getInstance().error() 251 | << "Cannot call super constructor outside a constructor function at line " << token->getLine() 252 | << " and column " << token->getColumn() << std::endl; 253 | BReport::getInstance().printError(); 254 | } else { 255 | 256 | // Check if super constructor is defined 257 | if(!classScope->getExtends()) { 258 | BReport::getInstance().error() 259 | << "Cannot call super constructor at line " << token->getLine() 260 | << " and column " << token->getColumn() << " because class " << classScope->getName()->getValue() 261 | << " does not extend from another class" << std::endl; 262 | BReport::getInstance().printError(); 263 | } else { 264 | 265 | // Search for the constructor 266 | auto functions = classScope->getExtends()->findAllConstructors(); 267 | 268 | // Set function if found 269 | if(functions.empty()) { 270 | BReport::getInstance().error() 271 | << "Call to an undefined constructor for class " 272 | << classScope->getExtends()->getName()->getValue() << " at line " << token->getLine() 273 | << " and column " << token->getColumn() << std::endl; 274 | BReport::getInstance().printError(); 275 | } else { 276 | functionCall->setFunction(functions.front()); 277 | } 278 | } 279 | } 280 | 281 | // Add function to the chain 282 | m_callables.push_back(functionCall); 283 | } 284 | 285 | void BChain::addThis(std::shared_ptr scope, std::shared_ptr thisReference) { 286 | 287 | // Callable chain must be empty 288 | if(!m_callables.empty()) { 289 | throw BException("A 'this' reference must always be at the beginning of the chain"); 290 | } 291 | 292 | // Find the parent class of the this reference 293 | auto classScope = scope->findClosestClass(); 294 | 295 | // Check if a parent class was found 296 | if(classScope) { 297 | thisReference->setReference(classScope); 298 | } else { 299 | BReport::getInstance().error() 300 | << "Undefined reference for 'this' at line " << thisReference->getLexicalToken()->getLine() 301 | << " and column " << thisReference->getLexicalToken()->getColumn() << std::endl; 302 | BReport::getInstance().printError(); 303 | } 304 | 305 | // Add this reference to the chain anyway 306 | m_callables.push_back(thisReference); 307 | } 308 | 309 | void BChain::addSuper(std::shared_ptr scope, std::shared_ptr superReference) { 310 | 311 | // Callable chain must be empty 312 | if(!m_callables.empty()) { 313 | throw BException("A 'super' reference must always be at the beginning of the chain"); 314 | } 315 | 316 | // Find the parent class of the this reference 317 | auto classScope = scope->findClosestClass(); 318 | 319 | // Check if a parent class was found 320 | if(classScope) { 321 | 322 | // Set the source reference 323 | superReference->setSrcReference(classScope); 324 | 325 | // Check if class extends from another 326 | if(!classScope->getExtends()) { 327 | BReport::getInstance().error() 328 | << "Cannot call 'super' at line " << superReference->getLexicalToken()->getLine() 329 | << " and column " << superReference->getLexicalToken()->getColumn() << " because class " 330 | << classScope->getName()->getValue() << " does not extend from another class" << std::endl; 331 | BReport::getInstance().printError(); 332 | } 333 | } else { 334 | BReport::getInstance().error() 335 | << "Undefined reference for 'super' at line " << superReference->getLexicalToken()->getLine() 336 | << " and column " << superReference->getLexicalToken()->getColumn() << std::endl; 337 | BReport::getInstance().printError(); 338 | } 339 | 340 | // Add this reference to the chain anyway 341 | m_callables.push_back(superReference); 342 | } 343 | 344 | std::shared_ptr BChain::operator[](int index) { 345 | if(index < 0 || index >= m_callables.size()) { 346 | throw BException("Accessing an index out of bound in a chain call"); 347 | } 348 | return m_callables[index]; 349 | } 350 | 351 | std::shared_ptr BChain::last() { 352 | if(m_callables.empty()) { 353 | throw BException("Accessing last element of an empty chain"); 354 | } 355 | return m_callables.back(); 356 | } 357 | --------------------------------------------------------------------------------