diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c9f64fe..138f5540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,8 @@ if (LIBSCRATCHCPP_USE_LLVM) target_sources(scratchcpp PUBLIC include/scratchcpp/dev/compiler.h + include/scratchcpp/dev/compilervalue.h + include/scratchcpp/dev/compilerconstant.h include/scratchcpp/dev/executablecode.h include/scratchcpp/dev/executioncontext.h ) diff --git a/include/scratchcpp/block.h b/include/scratchcpp/block.h index fe6cf382..76c70dc1 100644 --- a/include/scratchcpp/block.h +++ b/include/scratchcpp/block.h @@ -10,6 +10,9 @@ namespace libscratchcpp class IEngine; class Target; +#ifdef USE_LLVM +class CompilerValue; +#endif class Input; class Field; class Comment; @@ -25,7 +28,11 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity Block(const std::string &id, const std::string &opcode); Block(const Block &) = delete; +#ifdef USE_LLVM + CompilerValue *compile(Compiler *compiler); +#else void compile(Compiler *compiler); +#endif const std::string &opcode() const; @@ -76,7 +83,7 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity BlockComp compileFunction() const; void setCompileFunction(BlockComp newCompileFunction); - BlockComp hatPredicateCompileFunction() const; + HatPredicateCompileFunc hatPredicateCompileFunction() const; void setHatPredicateCompileFunction(HatPredicateCompileFunc newHatPredicateCompileFunction); bool mutationHasNext() const; diff --git a/include/scratchcpp/dev/compiler.h b/include/scratchcpp/dev/compiler.h index b42f976d..ffc4ed7f 100644 --- a/include/scratchcpp/dev/compiler.h +++ b/include/scratchcpp/dev/compiler.h @@ -14,6 +14,8 @@ namespace libscratchcpp class IEngine; class Target; class ExecutableCode; +class CompilerValue; +class CompilerConstant; class Variable; class List; class Input; @@ -33,6 +35,9 @@ class LIBSCRATCHCPP_EXPORT Compiler Unknown }; + using ArgTypes = std::vector; + using Args = std::vector; + Compiler(IEngine *engine, Target *target); Compiler(const Compiler &) = delete; @@ -42,63 +47,63 @@ class LIBSCRATCHCPP_EXPORT Compiler std::shared_ptr compile(std::shared_ptr startBlock); - void addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const std::vector &argTypes = {}); - void addConstValue(const Value &value); - void addVariableValue(Variable *variable); - void addListContents(List *list); - void addListItem(List *list); - void addListItemIndex(List *list); - void addListContains(List *list); - void addListSize(List *list); - void addInput(const std::string &name); - - void createAdd(); - void createSub(); - void createMul(); - void createDiv(); - - void createCmpEQ(); - void createCmpGT(); - void createCmpLT(); - - void createAnd(); - void createOr(); - void createNot(); - - void createMod(); - void createRound(); - void createAbs(); - void createFloor(); - void createCeil(); - void createSqrt(); - void createSin(); - void createCos(); - void createTan(); - void createAsin(); - void createAcos(); - void createAtan(); - void createLn(); - void createLog10(); - void createExp(); - void createExp10(); - - void createVariableWrite(Variable *variable); + CompilerValue *addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {}); + CompilerConstant *addConstValue(const Value &value); + CompilerValue *addVariableValue(Variable *variable); + CompilerValue *addListContents(List *list); + CompilerValue *addListItem(List *list, CompilerValue *index); + CompilerValue *addListItemIndex(List *list, CompilerValue *item); + CompilerValue *addListContains(List *list, CompilerValue *item); + CompilerValue *addListSize(List *list); + CompilerValue *addInput(const std::string &name); + + CompilerValue *createAdd(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createSub(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createMul(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createDiv(CompilerValue *operand1, CompilerValue *operand2); + + CompilerValue *createCmpEQ(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createCmpGT(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createCmpLT(CompilerValue *operand1, CompilerValue *operand2); + + CompilerValue *createAnd(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createOr(CompilerValue *operand1, CompilerValue *operand2); + CompilerValue *createNot(CompilerValue *operand); + + CompilerValue *createMod(CompilerValue *num1, CompilerValue *num2); + CompilerValue *createRound(CompilerValue *num); + CompilerValue *createAbs(CompilerValue *num); + CompilerValue *createFloor(CompilerValue *num); + CompilerValue *createCeil(CompilerValue *num); + CompilerValue *createSqrt(CompilerValue *num); + CompilerValue *createSin(CompilerValue *num); + CompilerValue *createCos(CompilerValue *num); + CompilerValue *createTan(CompilerValue *num); + CompilerValue *createAsin(CompilerValue *num); + CompilerValue *createAcos(CompilerValue *num); + CompilerValue *createAtan(CompilerValue *num); + CompilerValue *createLn(CompilerValue *num); + CompilerValue *createLog10(CompilerValue *num); + CompilerValue *createExp(CompilerValue *num); + CompilerValue *createExp10(CompilerValue *num); + + void createVariableWrite(Variable *variable, CompilerValue *value); void createListClear(List *list); - void createListRemove(List *list); - void createListAppend(List *list); - void createListInsert(List *list); - void createListReplace(List *list); + void createListRemove(List *list, CompilerValue *index); + void createListAppend(List *list, CompilerValue *item); + void createListInsert(List *list, CompilerValue *index, CompilerValue *item); + void createListReplace(List *list, CompilerValue *index, CompilerValue *item); - void beginIfStatement(); + void beginIfStatement(CompilerValue *cond); void beginElseBranch(); void endIf(); - void moveToIf(std::shared_ptr substack); - void moveToIfElse(std::shared_ptr substack1, std::shared_ptr substack2); - void moveToRepeatLoop(std::shared_ptr substack); - void moveToWhileLoop(std::shared_ptr substack); - void moveToRepeatUntilLoop(std::shared_ptr substack); + void moveToIf(CompilerValue *cond, std::shared_ptr substack); + void moveToIfElse(CompilerValue *cond, std::shared_ptr substack1, std::shared_ptr substack2); + void moveToRepeatLoop(CompilerValue *count, std::shared_ptr substack); + void moveToWhileLoop(CompilerValue *cond, std::shared_ptr substack); + void moveToRepeatUntilLoop(CompilerValue *cond, std::shared_ptr substack); void beginLoopCondition(); void warp(); @@ -108,7 +113,7 @@ class LIBSCRATCHCPP_EXPORT Compiler const std::unordered_set &unsupportedBlocks() const; private: - void addInput(Input *input); + CompilerValue *addInput(Input *input); spimpl::unique_impl_ptr impl; }; diff --git a/include/scratchcpp/dev/compilerconstant.h b/include/scratchcpp/dev/compilerconstant.h new file mode 100644 index 00000000..51d6347b --- /dev/null +++ b/include/scratchcpp/dev/compilerconstant.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "compilervalue.h" + +namespace libscratchcpp +{ + +class CompilerConstantPrivate; + +/*! \brief The CompilerConstant class represents a constant value in compiled code. */ +class LIBSCRATCHCPP_EXPORT CompilerConstant : public CompilerValue +{ + public: + CompilerConstant(Compiler::StaticType type, const Value &value); + CompilerConstant(const CompilerConstant &) = delete; + + bool isConst() const override final { return true; }; + + const Value &value() const; + + private: + spimpl::unique_impl_ptr impl; +}; + +} // namespace libscratchcpp diff --git a/include/scratchcpp/dev/compilervalue.h b/include/scratchcpp/dev/compilervalue.h new file mode 100644 index 00000000..c783d8ac --- /dev/null +++ b/include/scratchcpp/dev/compilervalue.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "compiler.h" + +namespace libscratchcpp +{ + +class CompilerValuePrivate; + +/*! \brief The CompilerValue class represents a local value in compiled code. */ +class LIBSCRATCHCPP_EXPORT CompilerValue +{ + public: + CompilerValue(Compiler::StaticType type); + CompilerValue(const CompilerValue &) = delete; + virtual ~CompilerValue() { } + + Compiler::StaticType type() const; + void setType(Compiler::StaticType type); + + virtual bool isConst() const { return false; }; + + private: + spimpl::unique_impl_ptr impl; +}; + +} // namespace libscratchcpp diff --git a/include/scratchcpp/global.h b/include/scratchcpp/global.h index c72c14f6..e5824008 100644 --- a/include/scratchcpp/global.h +++ b/include/scratchcpp/global.h @@ -25,6 +25,9 @@ namespace libscratchcpp class VirtualMachine; class Compiler; +#ifdef USE_LLVM +class CompilerValue; +#endif class Block; class Value; @@ -35,12 +38,21 @@ class Value; */ using BlockFunc = unsigned int (*)(VirtualMachine *vm); +#ifdef USE_LLVM +/*! + * \typedef BlockComp + * + * BlockComp is a function pointer for functions which are used to compile blocks. + */ +using BlockComp = CompilerValue *(*)(Compiler *); +#else /*! * \typedef BlockComp * * BlockComp is a function pointer for functions which are used to compile blocks to bytecode. */ using BlockComp = void (*)(Compiler *); +#endif // USE_LLVM /*! * \typedef MonitorNameFunc @@ -56,12 +68,21 @@ using MonitorNameFunc = const std::string &(*)(Block *); */ using MonitorChangeFunc = void (*)(Block *, const Value &newValue); +#ifdef USE_LLVM +/*! + * \typedef HatPredicateCompileFunc + * + * HatPredicateCompileFunc is a function pointer for functions which are used to compile edge-activated hat predicates. + */ +using HatPredicateCompileFunc = CompilerValue *(*)(Compiler *vm); +#else /*! * \typedef HatPredicateCompileFunc * * HatPredicateCompileFunc is a function pointer for functions which are used to compile edge-activated hat predicates to bytecode. */ using HatPredicateCompileFunc = void (*)(Compiler *vm); +#endif // USE_LLVM } // namespace libscratchcpp diff --git a/include/scratchcpp/inputvalue.h b/include/scratchcpp/inputvalue.h index 32c4cb0f..f1580c75 100644 --- a/include/scratchcpp/inputvalue.h +++ b/include/scratchcpp/inputvalue.h @@ -10,6 +10,9 @@ namespace libscratchcpp { +#ifdef USE_LLVM +class CompilerValue; +#endif class Block; class Entity; class InputValuePrivate; @@ -34,7 +37,11 @@ class LIBSCRATCHCPP_EXPORT InputValue InputValue(Type type = Type::Number); +#ifdef USE_LLVM + CompilerValue *compile(Compiler *compiler); +#else void compile(Compiler *compiler); +#endif Type type() const; void setType(Type newType); diff --git a/src/dev/engine/CMakeLists.txt b/src/dev/engine/CMakeLists.txt index 61d172da..a4933a98 100644 --- a/src/dev/engine/CMakeLists.txt +++ b/src/dev/engine/CMakeLists.txt @@ -3,6 +3,12 @@ target_sources(scratchcpp compiler.cpp compiler_p.cpp compiler_p.h + compilervalue.cpp + compilervalue_p.cpp + compilervalue_p.h + compilerconstant.cpp + compilerconstant_p.cpp + compilerconstant_p.h executioncontext.cpp executioncontext_p.cpp executioncontext_p.h diff --git a/src/dev/engine/compiler.cpp b/src/dev/engine/compiler.cpp index c8f134fa..51583120 100644 --- a/src/dev/engine/compiler.cpp +++ b/src/dev/engine/compiler.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include #include @@ -77,219 +78,220 @@ std::shared_ptr Compiler::compile(std::shared_ptr startBl * Adds a call to the given function.\n * For example: extern "C" bool some_block(Target *target, double arg1, const char *arg2) */ -void Compiler::addFunctionCall(const std::string &functionName, StaticType returnType, const std::vector &argTypes) +CompilerValue *Compiler::addFunctionCall(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args) { - impl->builder->addFunctionCall(functionName, returnType, argTypes); + assert(argTypes.size() == args.size()); + return impl->builder->addFunctionCall(functionName, returnType, argTypes, args); } -/*! Adds a constant value to the compiled code. */ -void Compiler::addConstValue(const Value &value) +/*! Adds the given constant to the compiled code. */ +CompilerConstant *Compiler::addConstValue(const Value &value) { - impl->builder->addConstValue(value); + return static_cast(impl->builder->addConstValue(value)); } -/*! Adds the given variable to the code (to read it). */ -void Compiler::addVariableValue(Variable *variable) +/*! Adds the value of the given variable to the code. */ +CompilerValue *Compiler::addVariableValue(Variable *variable) { - impl->builder->addVariableValue(variable); + return impl->builder->addVariableValue(variable); } -/*! Adds the given list to the code (to read its string representation). */ -void Compiler::addListContents(List *list) +/*! Adds the string representation of the given list to the code. */ +CompilerValue *Compiler::addListContents(List *list) { - impl->builder->addListContents(list); + return impl->builder->addListContents(list); } -/*! Adds the item with index from the last value of the given list to the code. */ -void Compiler::addListItem(List *list) +/*! Adds the item with index of the given list to the code. */ +CompilerValue *Compiler::addListItem(List *list, CompilerValue *index) { - impl->builder->addListItem(list); + return impl->builder->addListItem(list, index); } -/*! Adds the index of the item from the last value of the given list to the code. */ -void Compiler::addListItemIndex(List *list) +/*! Adds the index of item of the given list to the code. */ +CompilerValue *Compiler::addListItemIndex(List *list, CompilerValue *item) { - impl->builder->addListItemIndex(list); + return impl->builder->addListItemIndex(list, item); } -/*! Adds the result of a list contains item from the check to the code. */ -void Compiler::addListContains(List *list) +/*! Adds the result of a list contains item check to the code. */ +CompilerValue *Compiler::addListContains(List *list, CompilerValue *item) { - impl->builder->addListContains(list); + return impl->builder->addListContains(list, item); } /*! Adds the length of the given list to the code. */ -void Compiler::addListSize(List *list) +CompilerValue *Compiler::addListSize(List *list) { - impl->builder->addListSize(list); + return impl->builder->addListSize(list); } /*! Compiles the given input (resolved by name) and adds it to the compiled code. */ -void Compiler::addInput(const std::string &name) +CompilerValue *Compiler::addInput(const std::string &name) { - addInput(impl->block->inputAt(impl->block->findInput(name)).get()); + return addInput(impl->block->inputAt(impl->block->findInput(name)).get()); } -/*! Creates an add instruction from the last 2 values. */ -void Compiler::createAdd() +/*! Creates an add instruction. */ +CompilerValue *Compiler::createAdd(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createAdd(); + return impl->builder->createAdd(operand1, operand2); } -/*! Creates a subtract instruction from the last 2 values. */ -void Compiler::createSub() +/*! Creates a subtract instruction. */ +CompilerValue *Compiler::createSub(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createSub(); + return impl->builder->createSub(operand1, operand2); } -/*! Creates a multiply instruction from the last 2 values. */ -void Compiler::createMul() +/*! Creates a multiply instruction. */ +CompilerValue *Compiler::createMul(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createMul(); + return impl->builder->createMul(operand1, operand2); } -/*! Creates a divide instruction from the last 2 values. */ -void Compiler::createDiv() +/*! Creates a divide instruction. */ +CompilerValue *Compiler::createDiv(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createDiv(); + return impl->builder->createDiv(operand1, operand2); } -/*! Creates an equality comparison instruction using the last 2 values. */ -void Compiler::createCmpEQ() +/*! Creates an equality comparison instruction. */ +CompilerValue *Compiler::createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createCmpEQ(); + return impl->builder->createCmpEQ(operand1, operand2); } -/*! Creates a greater than comparison instruction using the last 2 values. */ -void Compiler::createCmpGT() +/*! Creates a greater than comparison instruction. */ +CompilerValue *Compiler::createCmpGT(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createCmpGT(); + return impl->builder->createCmpGT(operand1, operand2); } -/*! Creates a lower than comparison instruction using the last 2 values. */ -void Compiler::createCmpLT() +/*! Creates a lower than comparison instruction. */ +CompilerValue *Compiler::createCmpLT(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createCmpLT(); + return impl->builder->createCmpLT(operand1, operand2); } -/*! Creates an AND operation using the last 2 values. */ -void Compiler::createAnd() +/*! Creates an AND operation. */ +CompilerValue *Compiler::createAnd(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createAnd(); + return impl->builder->createAnd(operand1, operand2); } -/*! Creates an OR operation using the last 2 values. */ -void Compiler::createOr() +/*! Creates an OR operation. */ +CompilerValue *Compiler::createOr(CompilerValue *operand1, CompilerValue *operand2) { - impl->builder->createOr(); + return impl->builder->createOr(operand1, operand2); } -/*! Creates a NOT operation using the last value. */ -void Compiler::createNot() +/*! Creates a NOT operation. */ +CompilerValue *Compiler::createNot(CompilerValue *operand) { - impl->builder->createNot(); + return impl->builder->createNot(operand); } -/*! Creates a remainder operation using the last 2 values. */ -void Compiler::createMod() +/*! Creates a remainder operation. */ +CompilerValue *Compiler::createMod(CompilerValue *num1, CompilerValue *num2) { - impl->builder->createMod(); + return impl->builder->createMod(num1, num2); } -/*! Creates a round operation using the last value. */ -void Compiler::createRound() +/*! Creates a round operation. */ +CompilerValue *Compiler::createRound(CompilerValue *num) { - impl->builder->createRound(); + return impl->builder->createRound(num); } -/*! Creates an abs operation using the last value. */ -void Compiler::createAbs() +/*! Creates an abs operation. */ +CompilerValue *Compiler::createAbs(CompilerValue *num) { - impl->builder->createAbs(); + return impl->builder->createAbs(num); } -/*! Creates a floor operation using the last value. */ -void Compiler::createFloor() +/*! Creates a floor operation. */ +CompilerValue *Compiler::createFloor(CompilerValue *num) { - impl->builder->createFloor(); + return impl->builder->createFloor(num); } -/*! Creates a ceiling operation using the last value. */ -void Compiler::createCeil() +/*! Creates a ceiling operation. */ +CompilerValue *Compiler::createCeil(CompilerValue *num) { - impl->builder->createCeil(); + return impl->builder->createCeil(num); } -/*! Creates a square root operation using the last value. */ -void Compiler::createSqrt() +/*! Creates a square root operation. */ +CompilerValue *Compiler::createSqrt(CompilerValue *num) { - impl->builder->createSqrt(); + return impl->builder->createSqrt(num); } -/*! Creates a sin operation using the last value. */ -void Compiler::createSin() +/*! Creates a sin operation. */ +CompilerValue *Compiler::createSin(CompilerValue *num) { - impl->builder->createSin(); + return impl->builder->createSin(num); } -/*! Creates a cos operation using the last value. */ -void Compiler::createCos() +/*! Creates a cos operation. */ +CompilerValue *Compiler::createCos(CompilerValue *num) { - impl->builder->createCos(); + return impl->builder->createCos(num); } -/*! Creates a tan operation using the last value. */ -void Compiler::createTan() +/*! Creates a tan operation. */ +CompilerValue *Compiler::createTan(CompilerValue *num) { - impl->builder->createTan(); + return impl->builder->createTan(num); } -/*! Creates an asin operation using the last value. */ -void Compiler::createAsin() +/*! Creates an asin operation. */ +CompilerValue *Compiler::createAsin(CompilerValue *num) { - impl->builder->createAsin(); + return impl->builder->createAsin(num); } -/*! Creates an acos operation using the last value. */ -void Compiler::createAcos() +/*! Creates an acos operation. */ +CompilerValue *Compiler::createAcos(CompilerValue *num) { - impl->builder->createAcos(); + return impl->builder->createAcos(num); } -/*! Creates an atan operation using the last value. */ -void Compiler::createAtan() +/*! Creates an atan operation. */ +CompilerValue *Compiler::createAtan(CompilerValue *num) { - impl->builder->createAtan(); + return impl->builder->createAtan(num); } -/*! Creates an ln operation using the last value. */ -void Compiler::createLn() +/*! Creates an ln operation. */ +CompilerValue *Compiler::createLn(CompilerValue *num) { - impl->builder->createLn(); + return impl->builder->createLn(num); } -/*! Creates a log10 operation using the last value. */ -void Compiler::createLog10() +/*! Creates a log10 operation. */ +CompilerValue *Compiler::createLog10(CompilerValue *num) { - impl->builder->createLog10(); + return impl->builder->createLog10(num); } -/*! Creates an e^x operation using the last value. */ -void Compiler::createExp() +/*! Creates an e^x operation. */ +CompilerValue *Compiler::createExp(CompilerValue *num) { - impl->builder->createExp(); + return impl->builder->createExp(num); } -/*! Creates a 10^x operation using the last value. */ -void Compiler::createExp10() +/*! Creates a 10^x operation. */ +CompilerValue *Compiler::createExp10(CompilerValue *num) { - impl->builder->createExp10(); + return impl->builder->createExp10(num); } -/*! Creates a variable write operation using the last value. */ -void Compiler::createVariableWrite(Variable *variable) +/*! Creates a variable write operation. */ +void Compiler::createVariableWrite(Variable *variable, CompilerValue *value) { - impl->builder->createVariableWrite(variable); + impl->builder->createVariableWrite(variable, value); } /*! Creates a clear list operation. */ @@ -302,36 +304,36 @@ void Compiler::createListClear(List *list) * Creates a remove item from list operation. * \note The index starts with 0 and is cast to number, special strings like "last" are not handled. */ -void Compiler::createListRemove(List *list) +void Compiler::createListRemove(List *list, CompilerValue *index) { - impl->builder->createListRemove(list); + impl->builder->createListRemove(list, index); } -/*! Creates a list append operation using the last value. */ -void Compiler::createListAppend(List *list) +/*! Creates a list append operation. */ +void Compiler::createListAppend(List *list, CompilerValue *item) { - impl->builder->createListAppend(list); + impl->builder->createListAppend(list, item); } -/*! Creates a list insert operation using the last 2 values (index, value). */ -void Compiler::createListInsert(List *list) +/*! Creates a list insert operation. */ +void Compiler::createListInsert(List *list, CompilerValue *index, CompilerValue *item) { - impl->builder->createListInsert(list); + impl->builder->createListInsert(list, index, item); } -/*! Creates a list replace operation using the last 2 values (index, value). */ -void Compiler::createListReplace(List *list) +/*! Creates a list replace operation. */ +void Compiler::createListReplace(List *list, CompilerValue *index, CompilerValue *item) { - impl->builder->createListReplace(list); + impl->builder->createListReplace(list, index, item); } /*! * Starts a custom if statement. * \note The if statement must be terminated using endIf() after compiling your block. */ -void Compiler::beginIfStatement() +void Compiler::beginIfStatement(CompilerValue *cond) { - impl->builder->beginIfStatement(); + impl->builder->beginIfStatement(cond); impl->customIfStatementCount++; } @@ -355,7 +357,7 @@ void Compiler::endIf() } /*! Jumps to the given if substack. */ -void Compiler::moveToIf(std::shared_ptr substack) +void Compiler::moveToIf(CompilerValue *cond, std::shared_ptr substack) { if (!substack) return; // ignore empty if statements @@ -363,11 +365,11 @@ void Compiler::moveToIf(std::shared_ptr substack) impl->substackHit = true; impl->substackTree.push_back({ { impl->block, nullptr }, CompilerPrivate::SubstackType::IfStatement }); impl->block = substack; - impl->builder->beginIfStatement(); + impl->builder->beginIfStatement(cond); } /*! Jumps to the given if/else substack. The second substack is used for the else branch. */ -void Compiler::moveToIfElse(std::shared_ptr substack1, std::shared_ptr substack2) +void Compiler::moveToIfElse(CompilerValue *cond, std::shared_ptr substack1, std::shared_ptr substack2) { if (!substack1 && !substack2) return; // ignore empty if statements @@ -375,43 +377,43 @@ void Compiler::moveToIfElse(std::shared_ptr substack1, std::shared_ptrsubstackHit = true; impl->substackTree.push_back({ { impl->block, substack2 }, CompilerPrivate::SubstackType::IfStatement }); impl->block = substack1; - impl->builder->beginIfStatement(); + impl->builder->beginIfStatement(cond); if (!impl->block) impl->substackEnd(); } /*! Jumps to the given repeat loop substack. */ -void Compiler::moveToRepeatLoop(std::shared_ptr substack) +void Compiler::moveToRepeatLoop(CompilerValue *count, std::shared_ptr substack) { impl->substackHit = true; impl->substackTree.push_back({ { impl->block, nullptr }, CompilerPrivate::SubstackType::Loop }); impl->block = substack; - impl->builder->beginRepeatLoop(); + impl->builder->beginRepeatLoop(count); if (!impl->block) impl->substackEnd(); } /*! Jumps to the given while loop substack. */ -void Compiler::moveToWhileLoop(std::shared_ptr substack) +void Compiler::moveToWhileLoop(CompilerValue *cond, std::shared_ptr substack) { impl->substackHit = true; impl->substackTree.push_back({ { impl->block, nullptr }, CompilerPrivate::SubstackType::Loop }); impl->block = substack; - impl->builder->beginWhileLoop(); + impl->builder->beginWhileLoop(cond); if (!impl->block) impl->substackEnd(); } /*! Jumps to the given until loop substack. */ -void Compiler::moveToRepeatUntilLoop(std::shared_ptr substack) +void Compiler::moveToRepeatUntilLoop(CompilerValue *cond, std::shared_ptr substack) { impl->substackHit = true; impl->substackTree.push_back({ { impl->block, nullptr }, CompilerPrivate::SubstackType::Loop }); impl->block = substack; - impl->builder->beginRepeatUntilLoop(); + impl->builder->beginRepeatUntilLoop(cond); if (!impl->block) impl->substackEnd(); @@ -447,55 +449,57 @@ const std::unordered_set &Compiler::unsupportedBlocks() const return impl->unsupportedBlocks; } -void Compiler::addInput(Input *input) +CompilerValue *Compiler::addInput(Input *input) { - if (!input) { - addConstValue(Value()); - return; - } + if (!input) + return addConstValue(Value()); switch (input->type()) { case Input::Type::Shadow: case Input::Type::NoShadow: { if (input->pointsToDropdownMenu()) - addConstValue(input->selectedMenuItem()); + return addConstValue(input->selectedMenuItem()); else { + CompilerValue *ret = nullptr; auto previousBlock = impl->block; impl->block = input->valueBlock(); if (impl->block) { if (impl->block->compileFunction()) - impl->block->compile(this); + ret = impl->block->compile(this); else { std::cout << "warning: unsupported reporter block: " << impl->block->opcode() << std::endl; impl->unsupportedBlocks.insert(impl->block->opcode()); - addConstValue(Value()); + ret = addConstValue(Value()); } } else - addConstValue(input->primaryValue()->value()); + ret = addConstValue(input->primaryValue()->value()); impl->block = previousBlock; + return ret; } - - break; } case Input::Type::ObscuredShadow: { + CompilerValue *ret = nullptr; auto previousBlock = impl->block; impl->block = input->valueBlock(); + if (impl->block) { if (impl->block->compileFunction()) - impl->block->compile(this); + ret = impl->block->compile(this); else { std::cout << "warning: unsupported reporter block: " << impl->block->opcode() << std::endl; impl->unsupportedBlocks.insert(impl->block->opcode()); - addConstValue(Value()); + ret = addConstValue(Value()); } } else - input->primaryValue()->compile(this); + ret = input->primaryValue()->compile(this); impl->block = previousBlock; - break; + return ret; } } + + return nullptr; } diff --git a/src/dev/engine/compiler_p.h b/src/dev/engine/compiler_p.h index 0a23d71d..080afc96 100644 --- a/src/dev/engine/compiler_p.h +++ b/src/dev/engine/compiler_p.h @@ -12,6 +12,7 @@ namespace libscratchcpp class IEngine; class Target; class Block; +class CompilerValue; class ICodeBuilderFactory; class ICodeBuilder; diff --git a/src/dev/engine/compilerconstant.cpp b/src/dev/engine/compilerconstant.cpp new file mode 100644 index 00000000..fb7dcf3b --- /dev/null +++ b/src/dev/engine/compilerconstant.cpp @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include "compilerconstant_p.h" + +using namespace libscratchcpp; + +/*! Constructs CompilerConstant. */ +CompilerConstant::CompilerConstant(Compiler::StaticType type, const Value &value) : + CompilerValue(type), + impl(spimpl::make_unique_impl(value)) +{ +} + +/*! Returns the constant value. */ +const Value &CompilerConstant::value() const +{ + return impl->value; +} diff --git a/src/dev/engine/compilerconstant_p.cpp b/src/dev/engine/compilerconstant_p.cpp new file mode 100644 index 00000000..c1e0b07e --- /dev/null +++ b/src/dev/engine/compilerconstant_p.cpp @@ -0,0 +1,8 @@ +#include "compilerconstant_p.h" + +using namespace libscratchcpp; + +CompilerConstantPrivate::CompilerConstantPrivate(const Value &value) : + value(value) +{ +} diff --git a/src/dev/engine/compilerconstant_p.h b/src/dev/engine/compilerconstant_p.h new file mode 100644 index 00000000..c7b983ef --- /dev/null +++ b/src/dev/engine/compilerconstant_p.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace libscratchcpp +{ + +struct CompilerConstantPrivate +{ + CompilerConstantPrivate(const Value &value); + + Value value; +}; + +} // namespace libscratchcpp diff --git a/src/dev/engine/compilervalue.cpp b/src/dev/engine/compilervalue.cpp new file mode 100644 index 00000000..9a601321 --- /dev/null +++ b/src/dev/engine/compilervalue.cpp @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include "compilervalue_p.h" + +using namespace libscratchcpp; + +/*! Constructs CompilerValue. */ +CompilerValue::CompilerValue(Compiler::StaticType type) : + impl(spimpl::make_unique_impl(type)) +{ +} + +/*! Returns the type of this value. */ +Compiler::StaticType CompilerValue::type() const +{ + return impl->type; +} + +/*! Sets the type of this value. */ +void CompilerValue::setType(Compiler::StaticType type) +{ + impl->type = type; +} diff --git a/src/dev/engine/compilervalue_p.cpp b/src/dev/engine/compilervalue_p.cpp new file mode 100644 index 00000000..a526ae6e --- /dev/null +++ b/src/dev/engine/compilervalue_p.cpp @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include "compilervalue_p.h" + +using namespace libscratchcpp; + +CompilerValuePrivate::CompilerValuePrivate(Compiler::StaticType type) : + type(type) +{ +} diff --git a/src/dev/engine/compilervalue_p.h b/src/dev/engine/compilervalue_p.h new file mode 100644 index 00000000..99a9112e --- /dev/null +++ b/src/dev/engine/compilervalue_p.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace libscratchcpp +{ + +struct CompilerValuePrivate +{ + CompilerValuePrivate(Compiler::StaticType type); + + Compiler::StaticType type = Compiler::StaticType::Unknown; +}; + +} // namespace libscratchcpp diff --git a/src/dev/engine/internal/icodebuilder.h b/src/dev/engine/internal/icodebuilder.h index 30d60cfe..4e966667 100644 --- a/src/dev/engine/internal/icodebuilder.h +++ b/src/dev/engine/internal/icodebuilder.h @@ -19,60 +19,60 @@ class ICodeBuilder virtual std::shared_ptr finalize() = 0; - virtual void addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const std::vector &argTypes) = 0; - virtual void addConstValue(const Value &value) = 0; - virtual void addVariableValue(Variable *variable) = 0; - virtual void addListContents(List *list) = 0; - virtual void addListItem(List *list) = 0; - virtual void addListItemIndex(List *list) = 0; - virtual void addListContains(List *list) = 0; - virtual void addListSize(List *list) = 0; - - virtual void createAdd() = 0; - virtual void createSub() = 0; - virtual void createMul() = 0; - virtual void createDiv() = 0; - - virtual void createCmpEQ() = 0; - virtual void createCmpGT() = 0; - virtual void createCmpLT() = 0; - - virtual void createAnd() = 0; - virtual void createOr() = 0; - virtual void createNot() = 0; - - virtual void createMod() = 0; - virtual void createRound() = 0; - virtual void createAbs() = 0; - virtual void createFloor() = 0; - virtual void createCeil() = 0; - virtual void createSqrt() = 0; - virtual void createSin() = 0; - virtual void createCos() = 0; - virtual void createTan() = 0; - virtual void createAsin() = 0; - virtual void createAcos() = 0; - virtual void createAtan() = 0; - virtual void createLn() = 0; - virtual void createLog10() = 0; - virtual void createExp() = 0; - virtual void createExp10() = 0; - - virtual void createVariableWrite(Variable *variable) = 0; + virtual CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0; + virtual CompilerConstant *addConstValue(const Value &value) = 0; + virtual CompilerValue *addVariableValue(Variable *variable) = 0; + virtual CompilerValue *addListContents(List *list) = 0; + virtual CompilerValue *addListItem(List *list, CompilerValue *index) = 0; + virtual CompilerValue *addListItemIndex(List *list, CompilerValue *item) = 0; + virtual CompilerValue *addListContains(List *list, CompilerValue *item) = 0; + virtual CompilerValue *addListSize(List *list) = 0; + + virtual CompilerValue *createAdd(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createSub(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createMul(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createDiv(CompilerValue *operand1, CompilerValue *operand2) = 0; + + virtual CompilerValue *createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createCmpGT(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createCmpLT(CompilerValue *operand1, CompilerValue *operand2) = 0; + + virtual CompilerValue *createAnd(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createOr(CompilerValue *operand1, CompilerValue *operand2) = 0; + virtual CompilerValue *createNot(CompilerValue *operand) = 0; + + virtual CompilerValue *createMod(CompilerValue *num1, CompilerValue *num2) = 0; + virtual CompilerValue *createRound(CompilerValue *num) = 0; + virtual CompilerValue *createAbs(CompilerValue *num) = 0; + virtual CompilerValue *createFloor(CompilerValue *num) = 0; + virtual CompilerValue *createCeil(CompilerValue *num) = 0; + virtual CompilerValue *createSqrt(CompilerValue *num) = 0; + virtual CompilerValue *createSin(CompilerValue *num) = 0; + virtual CompilerValue *createCos(CompilerValue *num) = 0; + virtual CompilerValue *createTan(CompilerValue *num) = 0; + virtual CompilerValue *createAsin(CompilerValue *num) = 0; + virtual CompilerValue *createAcos(CompilerValue *num) = 0; + virtual CompilerValue *createAtan(CompilerValue *num) = 0; + virtual CompilerValue *createLn(CompilerValue *num) = 0; + virtual CompilerValue *createLog10(CompilerValue *num) = 0; + virtual CompilerValue *createExp(CompilerValue *num) = 0; + virtual CompilerValue *createExp10(CompilerValue *num) = 0; + + virtual void createVariableWrite(Variable *variable, CompilerValue *value) = 0; virtual void createListClear(List *list) = 0; - virtual void createListRemove(List *list) = 0; - virtual void createListAppend(List *list) = 0; - virtual void createListInsert(List *list) = 0; - virtual void createListReplace(List *list) = 0; + virtual void createListRemove(List *list, CompilerValue *index) = 0; + virtual void createListAppend(List *list, CompilerValue *item) = 0; + virtual void createListInsert(List *list, CompilerValue *index, CompilerValue *item) = 0; + virtual void createListReplace(List *list, CompilerValue *index, CompilerValue *item) = 0; - virtual void beginIfStatement() = 0; + virtual void beginIfStatement(CompilerValue *cond) = 0; virtual void beginElseBranch() = 0; virtual void endIf() = 0; - virtual void beginRepeatLoop() = 0; - virtual void beginWhileLoop() = 0; - virtual void beginRepeatUntilLoop() = 0; + virtual void beginRepeatLoop(CompilerValue *count) = 0; + virtual void beginWhileLoop(CompilerValue *cond) = 0; + virtual void beginRepeatUntilLoop(CompilerValue *cond) = 0; virtual void beginLoopCondition() = 0; virtual void endLoop() = 0; diff --git a/src/dev/engine/internal/llvm/CMakeLists.txt b/src/dev/engine/internal/llvm/CMakeLists.txt index 1a4ce89a..4ef97a05 100644 --- a/src/dev/engine/internal/llvm/CMakeLists.txt +++ b/src/dev/engine/internal/llvm/CMakeLists.txt @@ -2,7 +2,9 @@ target_sources(scratchcpp PRIVATE llvmcodebuilder.cpp llvmcodebuilder.h + llvmregisterbase.h llvmregister.h + llvmconstantregister.h llvminstruction.h llvmifstatement.h llvmloop.h diff --git a/src/dev/engine/internal/llvm/llvmcodebuilder.cpp b/src/dev/engine/internal/llvm/llvmcodebuilder.cpp index d6943ba6..864dc252 100644 --- a/src/dev/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/dev/engine/internal/llvm/llvmcodebuilder.cpp @@ -9,9 +9,11 @@ #include #include #include +#include #include "llvmcodebuilder.h" #include "llvmexecutablecode.h" +#include "llvmconstantregister.h" #include "llvmifstatement.h" #include "llvmloop.h" #include "llvmtypes.h" @@ -33,8 +35,6 @@ LLVMCodeBuilder::LLVMCodeBuilder(Target *target, const std::string &id, bool war llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmParser(); - m_constValues.push_back({}); - m_regs.push_back({}); initTypes(); createVariableMap(); createListMap(); @@ -127,13 +127,13 @@ std::shared_ptr LLVMCodeBuilder::finalize() args.push_back(castValue(arg.second, arg.first)); } - llvm::Type *retType = getType(step.functionReturnReg ? step.functionReturnReg->type : Compiler::StaticType::Void); + llvm::Type *retType = getType(step.functionReturnReg ? step.functionReturnReg->type() : Compiler::StaticType::Void); llvm::Value *ret = m_builder.CreateCall(resolveFunction(step.functionName, llvm::FunctionType::get(retType, types, false)), args); if (step.functionReturnReg) { step.functionReturnReg->value = ret; - if (step.functionReturnReg->type == Compiler::StaticType::String) + if (step.functionReturnReg->type() == Compiler::StaticType::String) m_heap.push_back(step.functionReturnReg->value); } @@ -484,7 +484,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() assert(step.args.size() == 0); const LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable]; step.functionReturnReg->value = varPtr.onStack ? varPtr.stackPtr : varPtr.heapPtr; - step.functionReturnReg->type = varPtr.type; + step.functionReturnReg->setType(varPtr.type); break; } @@ -617,7 +617,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() const LLVMListPtr &listPtr = m_listPtrs[step.workList]; llvm::Value *index = m_builder.CreateFPToUI(castValue(arg.second, arg.first), m_builder.getInt64Ty()); step.functionReturnReg->value = getListItem(listPtr, index, func); - step.functionReturnReg->type = listPtr.type; + step.functionReturnReg->setType(listPtr.type); break; } @@ -878,12 +878,6 @@ std::shared_ptr LLVMCodeBuilder::finalize() else coro->end(); - if (!m_tmpRegs.empty()) { - std::cout - << "warning: " << m_tmpRegs.size() << " registers were leaked by script '" << m_module->getName().str() << "', function '" << func->getName().str() - << "' (if you see this as a regular user, this is a bug and should be reported)" << std::endl; - } - verifyFunction(func); // Create resume function @@ -913,40 +907,36 @@ std::shared_ptr LLVMCodeBuilder::finalize() return std::make_shared(std::move(m_module)); } -void LLVMCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const std::vector &argTypes) +CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { + assert(argTypes.size() == args.size()); + LLVMInstruction ins(LLVMInstruction::Type::FunctionCall); ins.functionName = functionName; - assert(m_tmpRegs.size() >= argTypes.size()); - size_t j = 0; - - for (size_t i = m_tmpRegs.size() - argTypes.size(); i < m_tmpRegs.size(); i++) - ins.args.push_back({ argTypes[j++], m_tmpRegs[i] }); - - m_tmpRegs.erase(m_tmpRegs.end() - argTypes.size(), m_tmpRegs.end()); + for (size_t i = 0; i < args.size(); i++) + ins.args.push_back({ argTypes[i], static_cast(args[i]) }); if (returnType != Compiler::StaticType::Void) { auto reg = std::make_shared(returnType); reg->isRawValue = true; - ins.functionReturnReg = reg; - m_regs[m_currentFunction].push_back(reg); - m_tmpRegs.push_back(reg); + ins.functionReturnReg = reg.get(); + m_instructions.push_back(ins); + return addReg(reg); } m_instructions.push_back(ins); + return nullptr; } -void LLVMCodeBuilder::addConstValue(const Value &value) +CompilerConstant *LLVMCodeBuilder::addConstValue(const Value &value) { - auto reg = std::make_shared(TYPE_MAP[value.type()]); - reg->isConstValue = true; - reg->constValue = value; - m_regs[m_currentFunction].push_back(reg); - m_tmpRegs.push_back(reg); + auto constReg = std::make_shared(TYPE_MAP[value.type()], value); + auto reg = std::reinterpret_pointer_cast(constReg); + return static_cast(addReg(reg)); } -void LLVMCodeBuilder::addVariableValue(Variable *variable) +CompilerValue *LLVMCodeBuilder::addVariableValue(Variable *variable) { LLVMInstruction ins(LLVMInstruction::Type::ReadVariable); ins.workVariable = variable; @@ -954,236 +944,239 @@ void LLVMCodeBuilder::addVariableValue(Variable *variable) auto ret = std::make_shared(Compiler::StaticType::Unknown); ret->isRawValue = false; - ins.functionReturnReg = ret; - m_regs[m_currentFunction].push_back(ret); - m_tmpRegs.push_back(ret); + ins.functionReturnReg = ret.get(); m_instructions.push_back(ins); + return addReg(ret); } -void LLVMCodeBuilder::addListContents(List *list) +CompilerValue *LLVMCodeBuilder::addListContents(List *list) { + return addConstValue(Value()); } -void LLVMCodeBuilder::addListItem(List *list) +CompilerValue *LLVMCodeBuilder::addListItem(List *list, CompilerValue *index) { LLVMInstruction ins(LLVMInstruction::Type::GetListItem); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); - assert(m_tmpRegs.size() >= 1); - ins.args.push_back({ Compiler::StaticType::Number, m_tmpRegs[0] }); - - m_tmpRegs.erase(m_tmpRegs.end() - 1, m_tmpRegs.end()); + ins.args.push_back({ Compiler::StaticType::Number, static_cast(index) }); auto ret = std::make_shared(Compiler::StaticType::Unknown); ret->isRawValue = false; - ins.functionReturnReg = ret; - m_regs[m_currentFunction].push_back(ret); - m_tmpRegs.push_back(ret); + ins.functionReturnReg = ret.get(); m_instructions.push_back(ins); + return addReg(ret); } -void LLVMCodeBuilder::addListItemIndex(List *list) +CompilerValue *LLVMCodeBuilder::addListItemIndex(List *list, CompilerValue *item) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::GetListItemIndex, Compiler::StaticType::Number, Compiler::StaticType::Unknown, 1); + LLVMInstruction ins(LLVMInstruction::Type::GetListItemIndex); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + return createOp(ins, Compiler::StaticType::Number, Compiler::StaticType::Unknown, { item }); } -void LLVMCodeBuilder::addListContains(List *list) +CompilerValue *LLVMCodeBuilder::addListContains(List *list, CompilerValue *item) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::ListContainsItem, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, 1); + LLVMInstruction ins(LLVMInstruction::Type::ListContainsItem); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + return createOp(ins, Compiler::StaticType::Bool, Compiler::StaticType::Unknown, { item }); } -void LLVMCodeBuilder::addListSize(List *list) +CompilerValue *LLVMCodeBuilder::addListSize(List *list) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::GetListSize, Compiler::StaticType::Number, {}, 0); + LLVMInstruction ins(LLVMInstruction::Type::GetListSize); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + return createOp(ins, Compiler::StaticType::Number); } -void LLVMCodeBuilder::createAdd() +CompilerValue *LLVMCodeBuilder::createAdd(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::Add, Compiler::StaticType::Number, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::Add, Compiler::StaticType::Number, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createSub() +CompilerValue *LLVMCodeBuilder::createSub(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::Sub, Compiler::StaticType::Number, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::Sub, Compiler::StaticType::Number, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createMul() +CompilerValue *LLVMCodeBuilder::createMul(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::Mul, Compiler::StaticType::Number, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::Mul, Compiler::StaticType::Number, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createDiv() +CompilerValue *LLVMCodeBuilder::createDiv(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::Div, Compiler::StaticType::Number, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::Div, Compiler::StaticType::Number, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createCmpEQ() +CompilerValue *LLVMCodeBuilder::createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::CmpEQ, Compiler::StaticType::Bool, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::CmpEQ, Compiler::StaticType::Bool, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createCmpGT() +CompilerValue *LLVMCodeBuilder::createCmpGT(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::CmpGT, Compiler::StaticType::Bool, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::CmpGT, Compiler::StaticType::Bool, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createCmpLT() +CompilerValue *LLVMCodeBuilder::createCmpLT(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::CmpLT, Compiler::StaticType::Bool, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::CmpLT, Compiler::StaticType::Bool, Compiler::StaticType::Number, { operand1, operand2 }); } -void LLVMCodeBuilder::createAnd() +CompilerValue *LLVMCodeBuilder::createAnd(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::And, Compiler::StaticType::Bool, Compiler::StaticType::Bool, 2); + return createOp(LLVMInstruction::Type::And, Compiler::StaticType::Bool, Compiler::StaticType::Bool, { operand1, operand2 }); } -void LLVMCodeBuilder::createOr() +CompilerValue *LLVMCodeBuilder::createOr(CompilerValue *operand1, CompilerValue *operand2) { - createOp(LLVMInstruction::Type::Or, Compiler::StaticType::Bool, Compiler::StaticType::Bool, 2); + return createOp(LLVMInstruction::Type::Or, Compiler::StaticType::Bool, Compiler::StaticType::Bool, { operand1, operand2 }); } -void LLVMCodeBuilder::createNot() +CompilerValue *LLVMCodeBuilder::createNot(CompilerValue *operand) { - createOp(LLVMInstruction::Type::Not, Compiler::StaticType::Bool, Compiler::StaticType::Bool, 1); + return createOp(LLVMInstruction::Type::Not, Compiler::StaticType::Bool, Compiler::StaticType::Bool, { operand }); } -void LLVMCodeBuilder::createMod() +CompilerValue *LLVMCodeBuilder::createMod(CompilerValue *num1, CompilerValue *num2) { - createOp(LLVMInstruction::Type::Mod, Compiler::StaticType::Number, Compiler::StaticType::Number, 2); + return createOp(LLVMInstruction::Type::Mod, Compiler::StaticType::Number, Compiler::StaticType::Number, { num1, num2 }); } -void LLVMCodeBuilder::createRound() +CompilerValue *LLVMCodeBuilder::createRound(CompilerValue *num) { - createOp(LLVMInstruction::Type::Round, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Round, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createAbs() +CompilerValue *LLVMCodeBuilder::createAbs(CompilerValue *num) { - createOp(LLVMInstruction::Type::Abs, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Abs, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createFloor() +CompilerValue *LLVMCodeBuilder::createFloor(CompilerValue *num) { - createOp(LLVMInstruction::Type::Floor, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Floor, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createCeil() +CompilerValue *LLVMCodeBuilder::createCeil(CompilerValue *num) { - createOp(LLVMInstruction::Type::Ceil, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Ceil, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createSqrt() +CompilerValue *LLVMCodeBuilder::createSqrt(CompilerValue *num) { - createOp(LLVMInstruction::Type::Sqrt, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Sqrt, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createSin() +CompilerValue *LLVMCodeBuilder::createSin(CompilerValue *num) { - createOp(LLVMInstruction::Type::Sin, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Sin, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createCos() +CompilerValue *LLVMCodeBuilder::createCos(CompilerValue *num) { - createOp(LLVMInstruction::Type::Cos, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Cos, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createTan() +CompilerValue *LLVMCodeBuilder::createTan(CompilerValue *num) { - createOp(LLVMInstruction::Type::Tan, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Tan, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createAsin() +CompilerValue *LLVMCodeBuilder::createAsin(CompilerValue *num) { - createOp(LLVMInstruction::Type::Asin, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Asin, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createAcos() +CompilerValue *LLVMCodeBuilder::createAcos(CompilerValue *num) { - createOp(LLVMInstruction::Type::Acos, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Acos, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createAtan() +CompilerValue *LLVMCodeBuilder::createAtan(CompilerValue *num) { - createOp(LLVMInstruction::Type::Atan, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Atan, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createLn() +CompilerValue *LLVMCodeBuilder::createLn(CompilerValue *num) { - createOp(LLVMInstruction::Type::Ln, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Ln, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createLog10() +CompilerValue *LLVMCodeBuilder::createLog10(CompilerValue *num) { - createOp(LLVMInstruction::Type::Log10, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Log10, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createExp() +CompilerValue *LLVMCodeBuilder::createExp(CompilerValue *num) { - createOp(LLVMInstruction::Type::Exp, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Exp, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createExp10() +CompilerValue *LLVMCodeBuilder::createExp10(CompilerValue *num) { - createOp(LLVMInstruction::Type::Exp10, Compiler::StaticType::Number, Compiler::StaticType::Number, 1); + return createOp(LLVMInstruction::Type::Exp10, Compiler::StaticType::Number, Compiler::StaticType::Number, { num }); } -void LLVMCodeBuilder::createVariableWrite(Variable *variable) +void LLVMCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *value) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::WriteVariable, Compiler::StaticType::Void, Compiler::StaticType::Unknown, 1); + LLVMInstruction ins(LLVMInstruction::Type::WriteVariable); ins.workVariable = variable; m_variablePtrs[variable] = LLVMVariablePtr(); + createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { value }); } void LLVMCodeBuilder::createListClear(List *list) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::ClearList, Compiler::StaticType::Void, Compiler::StaticType::Void, 0); + LLVMInstruction ins(LLVMInstruction::Type::ClearList); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + createOp(ins, Compiler::StaticType::Void); } -void LLVMCodeBuilder::createListRemove(List *list) +void LLVMCodeBuilder::createListRemove(List *list, CompilerValue *index) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::RemoveListItem, Compiler::StaticType::Void, Compiler::StaticType::Number, 1); + LLVMInstruction ins(LLVMInstruction::Type::RemoveListItem); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Number, { index }); } -void LLVMCodeBuilder::createListAppend(List *list) +void LLVMCodeBuilder::createListAppend(List *list, CompilerValue *item) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::AppendToList, Compiler::StaticType::Void, Compiler::StaticType::Unknown, 1); + LLVMInstruction ins(LLVMInstruction::Type::AppendToList); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + createOp(ins, Compiler::StaticType::Void, Compiler::StaticType::Unknown, { item }); } -void LLVMCodeBuilder::createListInsert(List *list) +void LLVMCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::InsertToList, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, 2); + LLVMInstruction ins(LLVMInstruction::Type::InsertToList); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + createOp(ins, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, { index, item }); } -void LLVMCodeBuilder::createListReplace(List *list) +void LLVMCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item) { - LLVMInstruction &ins = createOp(LLVMInstruction::Type::ListReplace, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, 2); + LLVMInstruction ins(LLVMInstruction::Type::ListReplace); ins.workList = list; m_listPtrs[list] = LLVMListPtr(); + createOp(ins, Compiler::StaticType::Void, { Compiler::StaticType::Number, Compiler::StaticType::Unknown }, { index, item }); } -void LLVMCodeBuilder::beginIfStatement() +void LLVMCodeBuilder::beginIfStatement(CompilerValue *cond) { LLVMInstruction ins(LLVMInstruction::Type::BeginIf); - assert(!m_tmpRegs.empty()); - ins.args.push_back({ Compiler::StaticType::Bool, m_tmpRegs.back() }); - m_tmpRegs.pop_back(); + ins.args.push_back({ Compiler::StaticType::Bool, static_cast(cond) }); m_instructions.push_back(ins); } @@ -1197,36 +1190,30 @@ void LLVMCodeBuilder::endIf() m_instructions.push_back(LLVMInstruction(LLVMInstruction::Type::EndIf)); } -void LLVMCodeBuilder::beginRepeatLoop() +void LLVMCodeBuilder::beginRepeatLoop(CompilerValue *count) { LLVMInstruction ins(LLVMInstruction::Type::BeginRepeatLoop); - assert(!m_tmpRegs.empty()); - ins.args.push_back({ Compiler::StaticType::Number, m_tmpRegs.back() }); - m_tmpRegs.pop_back(); + ins.args.push_back({ Compiler::StaticType::Number, static_cast(count) }); m_instructions.push_back(ins); } -void LLVMCodeBuilder::beginWhileLoop() +void LLVMCodeBuilder::beginWhileLoop(CompilerValue *cond) { LLVMInstruction ins(LLVMInstruction::Type::BeginWhileLoop); - assert(!m_tmpRegs.empty()); - ins.args.push_back({ Compiler::StaticType::Bool, m_tmpRegs.back() }); - m_tmpRegs.pop_back(); + ins.args.push_back({ Compiler::StaticType::Bool, static_cast(cond) }); m_instructions.push_back(ins); } -void LLVMCodeBuilder::beginRepeatUntilLoop() +void LLVMCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond) { LLVMInstruction ins(LLVMInstruction::Type::BeginRepeatUntilLoop); - assert(!m_tmpRegs.empty()); - ins.args.push_back({ Compiler::StaticType::Bool, m_tmpRegs.back() }); - m_tmpRegs.pop_back(); + ins.args.push_back({ Compiler::StaticType::Bool, static_cast(cond) }); m_instructions.push_back(ins); } void LLVMCodeBuilder::beginLoopCondition() { - m_instructions.push_back(LLVMInstruction(LLVMInstruction::Type::BeginLoopCondition)); + m_instructions.push_back({ LLVMInstruction::Type::BeginLoopCondition }); } void LLVMCodeBuilder::endLoop() @@ -1240,13 +1227,6 @@ void LLVMCodeBuilder::endLoop() void LLVMCodeBuilder::yield() { m_instructions.push_back({ LLVMInstruction::Type::Yield }); - m_currentFunction++; - - assert(m_currentFunction == m_constValues.size()); - m_constValues.push_back({}); - - assert(m_currentFunction == m_regs.size()); - m_regs.push_back({}); } void LLVMCodeBuilder::initTypes() @@ -1376,6 +1356,12 @@ void LLVMCodeBuilder::optimize() modulePassManager.run(*m_module, moduleAnalysisManager); } +CompilerValue *LLVMCodeBuilder::addReg(std::shared_ptr reg) +{ + m_regs.push_back(reg); + return reg.get(); +} + void LLVMCodeBuilder::freeHeap() { // Free dynamically allocated memory @@ -1385,19 +1371,19 @@ void LLVMCodeBuilder::freeHeap() m_heap.clear(); } -llvm::Value *LLVMCodeBuilder::castValue(LLVMRegisterPtr reg, Compiler::StaticType targetType) +llvm::Value *LLVMCodeBuilder::castValue(LLVMRegister *reg, Compiler::StaticType targetType) { - if (reg->isConstValue) - return castConstValue(reg->constValue, targetType); + if (reg->isConst()) + return castConstValue(reg->constValue(), targetType); if (reg->isRawValue) return castRawValue(reg, targetType); - assert(reg->type != Compiler::StaticType::Void && targetType != Compiler::StaticType::Void); + assert(reg->type() != Compiler::StaticType::Void && targetType != Compiler::StaticType::Void); switch (targetType) { case Compiler::StaticType::Number: - switch (reg->type) { + switch (reg->type()) { case Compiler::StaticType::Number: { // Read number directly llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0); @@ -1423,7 +1409,7 @@ llvm::Value *LLVMCodeBuilder::castValue(LLVMRegisterPtr reg, Compiler::StaticTyp } case Compiler::StaticType::Bool: - switch (reg->type) { + switch (reg->type()) { case Compiler::StaticType::Number: { // True if != 0 llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0); @@ -1448,7 +1434,7 @@ llvm::Value *LLVMCodeBuilder::castValue(LLVMRegisterPtr reg, Compiler::StaticTyp } case Compiler::StaticType::String: - switch (reg->type) { + switch (reg->type()) { case Compiler::StaticType::Number: case Compiler::StaticType::Bool: case Compiler::StaticType::Unknown: { @@ -1475,14 +1461,14 @@ llvm::Value *LLVMCodeBuilder::castValue(LLVMRegisterPtr reg, Compiler::StaticTyp } } -llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegisterPtr reg, Compiler::StaticType targetType) +llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegister *reg, Compiler::StaticType targetType) { - if (reg->type == targetType) + if (reg->type() == targetType) return reg->value; switch (targetType) { case Compiler::StaticType::Number: - switch (reg->type) { + switch (reg->type()) { case Compiler::StaticType::Bool: // Cast bool to double return m_builder.CreateUIToFP(reg->value, m_builder.getDoubleTy()); @@ -1498,7 +1484,7 @@ llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegisterPtr reg, Compiler::Static } case Compiler::StaticType::Bool: - switch (reg->type) { + switch (reg->type()) { case Compiler::StaticType::Number: // Cast double to bool (true if != 0) return m_builder.CreateFCmpONE(reg->value, llvm::ConstantFP::get(m_ctx, llvm::APFloat(0.0))); @@ -1513,7 +1499,7 @@ llvm::Value *LLVMCodeBuilder::castRawValue(LLVMRegisterPtr reg, Compiler::Static } case Compiler::StaticType::String: - switch (reg->type) { + switch (reg->type()) { case Compiler::StaticType::Number: { // Convert double to string llvm::Value *ptr = m_builder.CreateCall(resolve_value_doubleToCString(), reg->value); @@ -1559,12 +1545,12 @@ llvm::Constant *LLVMCodeBuilder::castConstValue(const Value &value, Compiler::St } } -Compiler::StaticType LLVMCodeBuilder::optimizeRegisterType(LLVMRegisterPtr reg) +Compiler::StaticType LLVMCodeBuilder::optimizeRegisterType(LLVMRegister *reg) { - Compiler::StaticType ret = reg->type; + Compiler::StaticType ret = reg->type(); // Optimize string constants that represent numbers - if (reg->isConstValue && reg->type == Compiler::StaticType::String && reg->constValue.isValidNumber()) + if (reg->isConst() && reg->type() == Compiler::StaticType::String && reg->constValue().isValidNumber()) ret = Compiler::StaticType::Number; return ret; @@ -1676,44 +1662,36 @@ void LLVMCodeBuilder::updateListDataPtr(const LLVMListPtr &listPtr, llvm::Functi m_builder.CreateStore(m_builder.getInt1(false), listPtr.dataPtrDirty); } -LLVMInstruction &LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount) +CompilerValue *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args) { std::vector types; - types.reserve(argCount); + types.reserve(args.size()); - for (size_t i = 0; i < argCount; i++) + for (size_t i = 0; i < args.size(); i++) types.push_back(argType); - return createOp(type, retType, types, argCount); + return createOp(ins, retType, types, args); } -LLVMInstruction &LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const std::vector &argTypes, size_t argCount) +CompilerValue *LLVMCodeBuilder::createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) { - LLVMInstruction ins(type); - - assert(m_tmpRegs.size() >= argCount); - size_t j = 0; - - for (size_t i = m_tmpRegs.size() - argCount; i < m_tmpRegs.size(); i++) { - ins.args.push_back({ argTypes[j], m_tmpRegs[i] }); - j++; - } + m_instructions.push_back(ins); + LLVMInstruction &createdIns = m_instructions.back(); - m_tmpRegs.erase(m_tmpRegs.end() - argCount, m_tmpRegs.end()); + for (size_t i = 0; i < args.size(); i++) + createdIns.args.push_back({ argTypes[i], static_cast(args[i]) }); if (retType != Compiler::StaticType::Void) { auto ret = std::make_shared(retType); ret->isRawValue = true; - ins.functionReturnReg = ret; - m_regs[m_currentFunction].push_back(ret); - m_tmpRegs.push_back(ret); + createdIns.functionReturnReg = ret.get(); + return addReg(ret); } - m_instructions.push_back(ins); - return m_instructions.back(); + return nullptr; } -void LLVMCodeBuilder::createValueStore(LLVMRegisterPtr reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType) +void LLVMCodeBuilder::createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType) { llvm::Value *converted = nullptr; @@ -1789,7 +1767,7 @@ void LLVMCodeBuilder::createValueStore(LLVMRegisterPtr reg, llvm::Value *targetP } } -void LLVMCodeBuilder::createReusedValueStore(LLVMRegisterPtr reg, llvm::Value *targetPtr, Compiler::StaticType sourceType) +void LLVMCodeBuilder::createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType) { llvm::Value *converted = nullptr; @@ -1841,7 +1819,7 @@ llvm::Value *LLVMCodeBuilder::getListItem(const LLVMListPtr &listPtr, llvm::Valu return m_builder.CreateGEP(m_valueDataType, m_builder.CreateLoad(m_valueDataType->getPointerTo(), listPtr.dataPtr), index); } -llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMRegisterPtr item, llvm::Function *func) +llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item, llvm::Function *func) { llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr); llvm::BasicBlock *condBlock = llvm::BasicBlock::Create(m_ctx, "", func); @@ -1863,10 +1841,10 @@ llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMR // if (list[index] == item) m_builder.SetInsertPoint(bodyBlock); - LLVMRegisterPtr currentItem = std::make_shared(listPtr.type); - currentItem->isRawValue = false; - currentItem->value = getListItem(listPtr, m_builder.CreateLoad(m_builder.getInt64Ty(), index), func); - llvm::Value *cmp = createComparison(currentItem, item, Comparison::EQ); + LLVMRegister currentItem(listPtr.type); + currentItem.isRawValue = false; + currentItem.value = getListItem(listPtr, m_builder.CreateLoad(m_builder.getInt64Ty(), index), func); + llvm::Value *cmp = createComparison(¤tItem, item, Comparison::EQ); m_builder.CreateCondBr(cmp, cmpIfBlock, cmpElseBlock); // goto nextBlock @@ -1891,21 +1869,21 @@ llvm::Value *LLVMCodeBuilder::getListItemIndex(const LLVMListPtr &listPtr, LLVMR return m_builder.CreateLoad(m_builder.getInt64Ty(), index); } -llvm::Value *LLVMCodeBuilder::createValue(LLVMRegisterPtr reg) +llvm::Value *LLVMCodeBuilder::createValue(LLVMRegister *reg) { - if (reg->isConstValue) { + if (reg->isConst()) { // Create a constant ValueData instance and store it - llvm::Constant *value = castConstValue(reg->constValue, TYPE_MAP[reg->constValue.type()]); + llvm::Constant *value = castConstValue(reg->constValue(), TYPE_MAP[reg->constValue().type()]); llvm::Value *ret = m_builder.CreateAlloca(m_valueDataType); - switch (reg->constValue.type()) { + switch (reg->constValue().type()) { case ValueType::Number: value = llvm::ConstantExpr::getBitCast(value, m_valueDataType->getElementType(0)); break; case ValueType::Bool: // Assuming union type is int64 - value = m_builder.getInt64(reg->constValue.toBool()); + value = m_builder.getInt64(reg->constValue().toBool()); break; case ValueType::String: @@ -1917,21 +1895,21 @@ llvm::Value *LLVMCodeBuilder::createValue(LLVMRegisterPtr reg) break; } - llvm::Constant *type = m_builder.getInt32(static_cast(reg->constValue.type())); + llvm::Constant *type = m_builder.getInt32(static_cast(reg->constValue().type())); llvm::Constant *padding = m_builder.getInt32(0); llvm::Constant *constValue = llvm::ConstantStruct::get(m_valueDataType, { value, type, padding, m_builder.getInt64(0) }); m_builder.CreateStore(constValue, ret); return ret; } else if (reg->isRawValue) { - llvm::Value *value = castRawValue(reg, reg->type); + llvm::Value *value = castRawValue(reg, reg->type()); llvm::Value *ret = m_builder.CreateAlloca(m_valueDataType); // Store value llvm::Value *valueField = m_builder.CreateStructGEP(m_valueDataType, ret, 0); m_builder.CreateStore(value, valueField); - auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [®](const std::pair &pair) { return pair.second == reg->type; }); + auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [®](const std::pair &pair) { return pair.second == reg->type(); }); if (it == TYPE_MAP.end()) { assert(false); @@ -1948,26 +1926,26 @@ llvm::Value *LLVMCodeBuilder::createValue(LLVMRegisterPtr reg) return reg->value; } -llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegisterPtr arg1, LLVMRegisterPtr arg2, Comparison type) +llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type) { - auto type1 = arg1->type; - auto type2 = arg2->type; + auto type1 = arg1->type(); + auto type2 = arg2->type(); - if (arg1->isConstValue && arg2->isConstValue) { + if (arg1->isConst() && arg2->isConst()) { // If both operands are constant, perform the comparison at compile time bool result = false; switch (type) { case Comparison::EQ: - result = arg1->constValue == arg2->constValue; + result = arg1->constValue() == arg2->constValue(); break; case Comparison::GT: - result = arg1->constValue > arg2->constValue; + result = arg1->constValue() > arg2->constValue(); break; case Comparison::LT: - result = arg1->constValue < arg2->constValue; + result = arg1->constValue() < arg2->constValue(); break; default: @@ -1978,10 +1956,10 @@ llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegisterPtr arg1, LLVMRegiste return m_builder.getInt1(result); } else { // Optimize comparison of constant with number/bool - if (arg1->isConstValue && arg1->constValue.isValidNumber() && (type2 == Compiler::StaticType::Number || type2 == Compiler::StaticType::Bool)) + if (arg1->isConst() && arg1->constValue().isValidNumber() && (type2 == Compiler::StaticType::Number || type2 == Compiler::StaticType::Bool)) type1 = Compiler::StaticType::Number; - if (arg2->isConstValue && arg2->constValue.isValidNumber() && (type1 == Compiler::StaticType::Number || type1 == Compiler::StaticType::Bool)) + if (arg2->isConst() && arg2->constValue().isValidNumber() && (type1 == Compiler::StaticType::Number || type1 == Compiler::StaticType::Bool)) type2 = Compiler::StaticType::Number; // Optimize number and bool comparison diff --git a/src/dev/engine/internal/llvm/llvmcodebuilder.h b/src/dev/engine/internal/llvm/llvmcodebuilder.h index fa296136..cd84d1a8 100644 --- a/src/dev/engine/internal/llvm/llvmcodebuilder.h +++ b/src/dev/engine/internal/llvm/llvmcodebuilder.h @@ -17,6 +17,7 @@ namespace libscratchcpp { class Target; +class LLVMConstantRegister; class LLVMCodeBuilder : public ICodeBuilder { @@ -25,60 +26,60 @@ class LLVMCodeBuilder : public ICodeBuilder std::shared_ptr finalize() override; - void addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const std::vector &argTypes) override; - void addConstValue(const Value &value) override; - void addVariableValue(Variable *variable) override; - void addListContents(List *list) override; - void addListItem(List *list) override; - void addListItemIndex(List *list) override; - void addListContains(List *list) override; - void addListSize(List *list) override; - - void createAdd() override; - void createSub() override; - void createMul() override; - void createDiv() override; - - void createCmpEQ() override; - void createCmpGT() override; - void createCmpLT() override; - - void createAnd() override; - void createOr() override; - void createNot() override; - - void createMod() override; - void createRound() override; - void createAbs() override; - void createFloor() override; - void createCeil() override; - void createSqrt() override; - void createSin() override; - void createCos() override; - void createTan() override; - void createAsin() override; - void createAcos() override; - void createAtan() override; - void createLn() override; - void createLog10() override; - void createExp() override; - void createExp10() override; - - void createVariableWrite(Variable *variable) override; + CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override; + CompilerConstant *addConstValue(const Value &value) override; + CompilerValue *addVariableValue(Variable *variable) override; + CompilerValue *addListContents(List *list) override; + CompilerValue *addListItem(List *list, CompilerValue *index) override; + CompilerValue *addListItemIndex(List *list, CompilerValue *item) override; + CompilerValue *addListContains(List *list, CompilerValue *item) override; + CompilerValue *addListSize(List *list) override; + + CompilerValue *createAdd(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createSub(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createMul(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createDiv(CompilerValue *operand1, CompilerValue *operand2) override; + + CompilerValue *createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createCmpGT(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createCmpLT(CompilerValue *operand1, CompilerValue *operand2) override; + + CompilerValue *createAnd(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createOr(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createNot(CompilerValue *operand) override; + + CompilerValue *createMod(CompilerValue *num1, CompilerValue *num2) override; + CompilerValue *createRound(CompilerValue *num) override; + CompilerValue *createAbs(CompilerValue *num) override; + CompilerValue *createFloor(CompilerValue *num) override; + CompilerValue *createCeil(CompilerValue *num) override; + CompilerValue *createSqrt(CompilerValue *num) override; + CompilerValue *createSin(CompilerValue *num) override; + CompilerValue *createCos(CompilerValue *num) override; + CompilerValue *createTan(CompilerValue *num) override; + CompilerValue *createAsin(CompilerValue *num) override; + CompilerValue *createAcos(CompilerValue *num) override; + CompilerValue *createAtan(CompilerValue *num) override; + CompilerValue *createLn(CompilerValue *num) override; + CompilerValue *createLog10(CompilerValue *num) override; + CompilerValue *createExp(CompilerValue *num) override; + CompilerValue *createExp10(CompilerValue *num) override; + + void createVariableWrite(Variable *variable, CompilerValue *value) override; void createListClear(List *list) override; - void createListRemove(List *list) override; - void createListAppend(List *list) override; - void createListInsert(List *list) override; - void createListReplace(List *list) override; + void createListRemove(List *list, CompilerValue *index) override; + void createListAppend(List *list, CompilerValue *item) override; + void createListInsert(List *list, CompilerValue *index, CompilerValue *item) override; + void createListReplace(List *list, CompilerValue *index, CompilerValue *item) override; - void beginIfStatement() override; + void beginIfStatement(CompilerValue *cond) override; void beginElseBranch() override; void endIf() override; - void beginRepeatLoop() override; - void beginWhileLoop() override; - void beginRepeatUntilLoop() override; + void beginRepeatLoop(CompilerValue *count) override; + void beginWhileLoop(CompilerValue *cond) override; + void beginRepeatUntilLoop(CompilerValue *cond) override; void beginLoopCondition() override; void endLoop() override; @@ -101,11 +102,13 @@ class LLVMCodeBuilder : public ICodeBuilder void verifyFunction(llvm::Function *func); void optimize(); + CompilerValue *addReg(std::shared_ptr reg); + void freeHeap(); - llvm::Value *castValue(LLVMRegisterPtr reg, Compiler::StaticType targetType); - llvm::Value *castRawValue(LLVMRegisterPtr reg, Compiler::StaticType targetType); + llvm::Value *castValue(LLVMRegister *reg, Compiler::StaticType targetType); + llvm::Value *castRawValue(LLVMRegister *reg, Compiler::StaticType targetType); llvm::Constant *castConstValue(const Value &value, Compiler::StaticType targetType); - Compiler::StaticType optimizeRegisterType(LLVMRegisterPtr reg); + Compiler::StaticType optimizeRegisterType(LLVMRegister *reg); llvm::Type *getType(Compiler::StaticType type); llvm::Value *isNaN(llvm::Value *num); llvm::Value *removeNaN(llvm::Value *num); @@ -117,17 +120,17 @@ class LLVMCodeBuilder : public ICodeBuilder void reloadLists(); void updateListDataPtr(const LLVMListPtr &listPtr, llvm::Function *func); - LLVMInstruction &createOp(LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount); - LLVMInstruction &createOp(LLVMInstruction::Type type, Compiler::StaticType retType, const std::vector &argTypes, size_t argCount); + CompilerValue *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, Compiler::StaticType argType, const Compiler::Args &args); + CompilerValue *createOp(const LLVMInstruction &ins, Compiler::StaticType retType, const Compiler::ArgTypes &argTypes = {}, const Compiler::Args &args = {}); - void createValueStore(LLVMRegisterPtr reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType); - void createReusedValueStore(LLVMRegisterPtr reg, llvm::Value *targetPtr, Compiler::StaticType sourceType); + void createValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType); + void createReusedValueStore(LLVMRegister *reg, llvm::Value *targetPtr, Compiler::StaticType sourceType); void createValueCopy(llvm::Value *source, llvm::Value *target); void copyStructField(llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType); llvm::Value *getListItem(const LLVMListPtr &listPtr, llvm::Value *index, llvm::Function *func); - llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, LLVMRegisterPtr item, llvm::Function *func); - llvm::Value *createValue(LLVMRegisterPtr reg); - llvm::Value *createComparison(LLVMRegisterPtr arg1, LLVMRegisterPtr arg2, Comparison type); + llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item, llvm::Function *func); + llvm::Value *createValue(LLVMRegister *reg); + llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type); llvm::FunctionCallee resolveFunction(const std::string name, llvm::FunctionType *type); llvm::FunctionCallee resolve_value_init(); @@ -175,10 +178,7 @@ class LLVMCodeBuilder : public ICodeBuilder llvm::StructType *m_valueDataType = nullptr; std::vector m_instructions; - size_t m_currentFunction = 0; - std::vector m_constValues; - std::vector> m_regs; - std::vector m_tmpRegs; + std::vector> m_regs; bool m_defaultWarp = false; bool m_warp = false; diff --git a/src/dev/engine/internal/llvm/llvmconstantregister.h b/src/dev/engine/internal/llvm/llvmconstantregister.h new file mode 100644 index 00000000..94c0d229 --- /dev/null +++ b/src/dev/engine/internal/llvm/llvmconstantregister.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "llvmregister.h" + +namespace libscratchcpp +{ + +struct LLVMConstantRegister + : public LLVMRegisterBase + , public CompilerConstant +{ + LLVMConstantRegister(Compiler::StaticType type, const Value &value) : + LLVMRegisterBase(), + CompilerConstant(type, value) + { + } + + const Value &constValue() const override { return CompilerConstant::value(); } +}; + +} // namespace libscratchcpp diff --git a/src/dev/engine/internal/llvm/llvminstruction.h b/src/dev/engine/internal/llvm/llvminstruction.h index afc13d1d..d1b1dcc8 100644 --- a/src/dev/engine/internal/llvm/llvminstruction.h +++ b/src/dev/engine/internal/llvm/llvminstruction.h @@ -69,8 +69,8 @@ struct LLVMInstruction Type type; std::string functionName; - std::vector> args; // target type, register - LLVMRegisterPtr functionReturnReg; + std::vector> args; // target type, register + LLVMRegister *functionReturnReg = nullptr; Variable *workVariable = nullptr; // for variables List *workList = nullptr; // for lists }; diff --git a/src/dev/engine/internal/llvm/llvmregister.h b/src/dev/engine/internal/llvm/llvmregister.h index 96e4dee3..2c7bc7f5 100644 --- a/src/dev/engine/internal/llvm/llvmregister.h +++ b/src/dev/engine/internal/llvm/llvmregister.h @@ -2,8 +2,7 @@ #pragma once -#include -#include +#include "llvmregisterbase.h" namespace llvm { @@ -16,19 +15,24 @@ namespace libscratchcpp { struct LLVMRegister + : public LLVMRegisterBase + , public CompilerValue { LLVMRegister(Compiler::StaticType type) : - type(type) + LLVMRegisterBase(), + CompilerValue(type) { } - Compiler::StaticType type = Compiler::StaticType::Void; - llvm::Value *value = nullptr; - bool isRawValue = false; - bool isConstValue = false; - Value constValue; + const Value &constValue() const override + { + if (isConst()) + return static_cast(static_cast(this))->value(); + else { + static const Value null = Value(); + return null; + } + } }; -using LLVMRegisterPtr = std::shared_ptr; - } // namespace libscratchcpp diff --git a/src/dev/engine/internal/llvm/llvmregisterbase.h b/src/dev/engine/internal/llvm/llvmregisterbase.h new file mode 100644 index 00000000..2267a6df --- /dev/null +++ b/src/dev/engine/internal/llvm/llvmregisterbase.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include + +namespace llvm +{ + +class Value; + +} + +namespace libscratchcpp +{ + +struct LLVMRegisterBase +{ + virtual const Value &constValue() const = 0; + + llvm::Value *value = nullptr; + bool isRawValue = false; +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp index 5a8dd135..590bbe17 100644 --- a/src/engine/internal/engine.cpp +++ b/src/engine/internal/engine.cpp @@ -1003,7 +1003,11 @@ void Engine::addHatBlock(IExtension *extension, const std::string &opcode) if (m_compileFunctions.find(extension) == m_compileFunctions.cend()) m_compileFunctions[extension] = {}; +#ifdef USE_LLVM + m_compileFunctions[extension][opcode] = [](Compiler *compiler) -> CompilerValue * { return nullptr; }; +#else m_compileFunctions[extension][opcode] = [](Compiler *compiler) {}; +#endif } void Engine::addInput(IExtension *extension, const std::string &name, int id) diff --git a/src/scratch/block.cpp b/src/scratch/block.cpp index 0350ccd4..8e014bc1 100644 --- a/src/scratch/block.cpp +++ b/src/scratch/block.cpp @@ -4,6 +4,10 @@ #include #include #include +#ifdef USE_LLVM +#include +#include +#endif #include #include "block_p.h" @@ -17,12 +21,23 @@ Block::Block(const std::string &id, const std::string &opcode) : { } +#ifdef USE_LLVM +/*! Calls the compile function. */ +CompilerValue *Block::compile(Compiler *compiler) +{ + if (impl->compileFunction) + return impl->compileFunction(compiler); + else + return nullptr; +} +#else /*! Calls the compile function. */ void Block::compile(Compiler *compiler) { if (impl->compileFunction) return impl->compileFunction(compiler); } +#endif /*! Returns the opcode. */ const std::string &Block::opcode() const @@ -43,7 +58,7 @@ void Block::setCompileFunction(BlockComp newCompileFunction) } /*! Returns the edge-activated hat predicate compile function. \see Block sections */ -BlockComp Block::hatPredicateCompileFunction() const +HatPredicateCompileFunc Block::hatPredicateCompileFunction() const { return impl->hatPredicateCompileFunction; } diff --git a/src/scratch/inputvalue.cpp b/src/scratch/inputvalue.cpp index 2d66269d..03edf80a 100644 --- a/src/scratch/inputvalue.cpp +++ b/src/scratch/inputvalue.cpp @@ -3,6 +3,7 @@ #include #ifdef USE_LLVM #include +#include #else #include #endif @@ -26,55 +27,68 @@ InputValue::InputValue(Type type) : { } +#ifdef USE_LLVM /*! Compiles the input value. */ -void InputValue::compile(Compiler *compiler) +CompilerValue *InputValue::compile(Compiler *compiler) { switch (impl->type) { case Type::Color: // TODO: Add support for colors - break; + return nullptr; case Type::Variable: { assert(impl->valuePtr); -#ifdef USE_LLVM Variable *var = dynamic_cast(impl->valuePtr.get()); if (var) - compiler->addVariableValue(var); + return compiler->addVariableValue(var); else - compiler->addConstValue(Value()); -#else - compiler->addInstruction(vm::OP_READ_VAR, { compiler->variableIndex(impl->valuePtr) }); -#endif - - break; + return compiler->addConstValue(Value()); } case Type::List: { assert(impl->valuePtr); -#ifdef USE_LLVM List *list = dynamic_cast(impl->valuePtr.get()); if (list) - compiler->addListContents(list); + return compiler->addListContents(list); else - compiler->addConstValue(Value()); + return compiler->addConstValue(Value()); + } + + default: + return compiler->addConstValue(impl->value); + } +} #else +/*! Compiles the input value. */ +void InputValue::compile(Compiler *compiler) +{ + switch (impl->type) { + case Type::Color: + // TODO: Add support for colors + break; + + case Type::Variable: { + assert(impl->valuePtr); + compiler->addInstruction(vm::OP_READ_VAR, { compiler->variableIndex(impl->valuePtr) }); + + break; + } + + case Type::List: { + assert(impl->valuePtr); compiler->addInstruction(vm::OP_READ_LIST, { compiler->listIndex(impl->valuePtr) }); -#endif break; } default: -#ifdef USE_LLVM - compiler->addConstValue(impl->value); -#else compiler->addInstruction(vm::OP_CONST, { compiler->constIndex(this) }); -#endif break; } } +#endif // USE_LLVM /*! Returns the type of the value. */ InputValue::Type InputValue::type() const diff --git a/test/dev/compiler/CMakeLists.txt b/test/dev/compiler/CMakeLists.txt index 546ac5c6..feee72ca 100644 --- a/test/dev/compiler/CMakeLists.txt +++ b/test/dev/compiler/CMakeLists.txt @@ -1,6 +1,8 @@ add_executable( compiler_test compiler_test.cpp + compilervalue_test.cpp + compilerconstant_test.cpp ) target_link_libraries( diff --git a/test/dev/compiler/compiler_test.cpp b/test/dev/compiler/compiler_test.cpp index 9042a515..8eb81046 100644 --- a/test/dev/compiler/compiler_test.cpp +++ b/test/dev/compiler/compiler_test.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -68,15 +69,21 @@ TEST_F(CompilerTest, AddFunctionCall) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); m_compareBlock = block; - block->setCompileFunction([](Compiler *compiler) { - ASSERT_EQ(compiler->block(), m_compareBlock); - std::vector args = { Compiler::StaticType::Number, Compiler::StaticType::Bool }; - EXPECT_CALL(*m_builder, addFunctionCall("test1", Compiler::StaticType::Void, args)); - compiler->addFunctionCall("test1", Compiler::StaticType::Void, args); - - args = { Compiler::StaticType::String }; - EXPECT_CALL(*m_builder, addFunctionCall("test2", Compiler::StaticType::Bool, args)); - compiler->addFunctionCall("test2", Compiler::StaticType::Bool, args); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + EXPECT_EQ(compiler->block(), m_compareBlock); + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + Compiler::ArgTypes argTypes = { Compiler::StaticType::Number, Compiler::StaticType::Bool }; + Compiler::Args args = { &arg1, &arg2 }; + EXPECT_CALL(*m_builder, addFunctionCall("test1", Compiler::StaticType::Void, argTypes, args)); + compiler->addFunctionCall("test1", Compiler::StaticType::Void, argTypes, args); + + args = { &arg1 }; + argTypes = { Compiler::StaticType::String }; + EXPECT_CALL(*m_builder, addFunctionCall("test2", Compiler::StaticType::Bool, argTypes, args)); + compiler->addFunctionCall("test2", Compiler::StaticType::Bool, argTypes, args); + + return nullptr; }); compile(compiler, block); @@ -86,15 +93,19 @@ TEST_F(CompilerTest, AddConstValue) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, addConstValue(Value(1))); - compiler->addConstValue(1); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerConstant ret(Compiler::StaticType::Unknown, Value()); - EXPECT_CALL(*m_builder, addConstValue(Value("test"))); + EXPECT_CALL(*m_builder, addConstValue(Value(1))).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addConstValue(1), &ret); + + EXPECT_CALL(*m_builder, addConstValue(Value("test"))).WillOnce(Return(&ret)); compiler->addConstValue("test"); - EXPECT_CALL(*m_builder, addConstValue(Value(3.5))); - compiler->addConstValue(3.5); + EXPECT_CALL(*m_builder, addConstValue(Value(3.5))).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addConstValue(3.5), nullptr); + + return nullptr; }); compile(compiler, block); @@ -104,13 +115,17 @@ TEST_F(CompilerTest, AddVariableValue) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue ret(Compiler::StaticType::Unknown); Variable var1("", ""), var2("", ""); - EXPECT_CALL(*m_builder, addVariableValue(&var1)); - compiler->addVariableValue(&var1); - EXPECT_CALL(*m_builder, addVariableValue(&var2)); - compiler->addVariableValue(&var2); + EXPECT_CALL(*m_builder, addVariableValue(&var1)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addVariableValue(&var1), &ret); + + EXPECT_CALL(*m_builder, addVariableValue(&var2)).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addVariableValue(&var2), nullptr); + + return nullptr; }); compile(compiler, block); @@ -120,13 +135,17 @@ TEST_F(CompilerTest, AddListContents) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue ret(Compiler::StaticType::Unknown); List list1("", ""), list2("", ""); - EXPECT_CALL(*m_builder, addListContents(&list1)); - compiler->addListContents(&list1); - EXPECT_CALL(*m_builder, addListContents(&list2)); - compiler->addListContents(&list2); + EXPECT_CALL(*m_builder, addListContents(&list1)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addListContents(&list1), &ret); + + EXPECT_CALL(*m_builder, addListContents(&list2)).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addListContents(&list2), nullptr); + + return nullptr; }); compile(compiler, block); @@ -136,13 +155,18 @@ TEST_F(CompilerTest, AddListItem) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue ret(Compiler::StaticType::Unknown); + CompilerValue arg(Compiler::StaticType::Unknown); List list1("", ""), list2("", ""); - EXPECT_CALL(*m_builder, addListItem(&list1)); - compiler->addListItem(&list1); - EXPECT_CALL(*m_builder, addListItem(&list2)); - compiler->addListItem(&list2); + EXPECT_CALL(*m_builder, addListItem(&list1, &arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addListItem(&list1, &arg), &ret); + + EXPECT_CALL(*m_builder, addListItem(&list2, &arg)).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addListItem(&list2, &arg), nullptr); + + return nullptr; }); compile(compiler, block); @@ -152,13 +176,18 @@ TEST_F(CompilerTest, AddListItemIndex) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue ret(Compiler::StaticType::Unknown); + CompilerValue arg(Compiler::StaticType::Unknown); List list1("", ""), list2("", ""); - EXPECT_CALL(*m_builder, addListItemIndex(&list1)); - compiler->addListItemIndex(&list1); - EXPECT_CALL(*m_builder, addListItemIndex(&list2)); - compiler->addListItemIndex(&list2); + EXPECT_CALL(*m_builder, addListItemIndex(&list1, &arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addListItemIndex(&list1, &arg), &ret); + + EXPECT_CALL(*m_builder, addListItemIndex(&list2, &arg)).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addListItemIndex(&list2, &arg), nullptr); + + return nullptr; }); compile(compiler, block); @@ -168,13 +197,17 @@ TEST_F(CompilerTest, AddListSize) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue ret(Compiler::StaticType::Unknown); List list1("", ""), list2("", ""); - EXPECT_CALL(*m_builder, addListSize(&list1)); - compiler->addListSize(&list1); - EXPECT_CALL(*m_builder, addListSize(&list2)); - compiler->addListSize(&list2); + EXPECT_CALL(*m_builder, addListSize(&list1)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addListSize(&list1), &ret); + + EXPECT_CALL(*m_builder, addListSize(&list2)).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addListSize(&list2), nullptr); + + return nullptr; }); compile(compiler, block); @@ -184,13 +217,18 @@ TEST_F(CompilerTest, AddListContains) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue ret(Compiler::StaticType::Unknown); + CompilerValue arg(Compiler::StaticType::Unknown); List list1("", ""), list2("", ""); - EXPECT_CALL(*m_builder, addListContains(&list1)); - compiler->addListContains(&list1); - EXPECT_CALL(*m_builder, addListContains(&list2)); - compiler->addListContains(&list2); + EXPECT_CALL(*m_builder, addListContains(&list1, &arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addListContains(&list1, &arg), &ret); + + EXPECT_CALL(*m_builder, addListContains(&list2, &arg)).WillOnce(Return(nullptr)); + EXPECT_EQ(compiler->addListContains(&list2, &arg), nullptr); + + return nullptr; }); compile(compiler, block); @@ -202,9 +240,9 @@ TEST_F(CompilerTest, AddInput) auto block = std::make_shared("a", ""); auto valueBlock = std::make_shared("b", ""); m_compareBlock = valueBlock; - valueBlock->setCompileFunction([](Compiler *compiler) { - ASSERT_EQ(compiler->block(), m_compareBlock); - compiler->addConstValue("value block"); + valueBlock->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + EXPECT_EQ(compiler->block(), m_compareBlock); + return compiler->addConstValue("value block"); }); auto menu = std::make_shared("c", ""); @@ -248,36 +286,40 @@ TEST_F(CompilerTest, AddInput) obscuredShadowBlock->setValueBlock(valueBlock); block->addInput(obscuredShadowBlock); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, addConstValue(Value())); - compiler->addInput("INVALID"); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerConstant constRet(Compiler::StaticType::Unknown, Value()); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, addConstValue(Value())).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("INVALID"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("test"))); - compiler->addInput("SHADOW"); + EXPECT_CALL(*m_builder, addConstValue(Value("test"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("SHADOW"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("value block"))); - compiler->addInput("SHADOW_BLOCK"); + EXPECT_CALL(*m_builder, addConstValue(Value("value block"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("SHADOW_BLOCK"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("selected item"))); - compiler->addInput("SHADOW_MENU"); + EXPECT_CALL(*m_builder, addConstValue(Value("selected item"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("SHADOW_MENU"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("test"))); - compiler->addInput("NO_SHADOW"); + EXPECT_CALL(*m_builder, addConstValue(Value("test"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("NO_SHADOW"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("value block"))); - compiler->addInput("NO_SHADOW_BLOCK"); + EXPECT_CALL(*m_builder, addConstValue(Value("value block"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("NO_SHADOW_BLOCK"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("selected item"))); - compiler->addInput("NO_SHADOW_MENU"); + EXPECT_CALL(*m_builder, addConstValue(Value("selected item"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("NO_SHADOW_MENU"), &constRet); - EXPECT_CALL(*m_builder, addConstValue(Value("test"))); - compiler->addInput("OBSCURED_SHADOW"); + EXPECT_CALL(*m_builder, addConstValue(Value("test"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("OBSCURED_SHADOW"), &constRet); - EXPECT_CALL(*m_builder, addVariableValue(m_testVar.get())); - compiler->addInput("OBSCURED_SHADOW_VARIABLE"); + EXPECT_CALL(*m_builder, addVariableValue(m_testVar.get())).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->addInput("OBSCURED_SHADOW_VARIABLE"), &ret); - EXPECT_CALL(*m_builder, addConstValue(Value("value block"))); - compiler->addInput("OBSCURED_SHADOW_BLOCK"); + EXPECT_CALL(*m_builder, addConstValue(Value("value block"))).WillOnce(Return(&constRet)); + EXPECT_EQ(compiler->addInput("OBSCURED_SHADOW_BLOCK"), &constRet); + + return nullptr; }); compile(compiler, block); @@ -288,9 +330,14 @@ TEST_F(CompilerTest, CreateAdd) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createAdd); - compiler->createAdd(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createAdd(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createAdd(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -301,9 +348,14 @@ TEST_F(CompilerTest, CreateSub) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createSub); - compiler->createSub(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createSub(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createSub(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -314,9 +366,14 @@ TEST_F(CompilerTest, CreateMul) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createMul); - compiler->createMul(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createMul(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createMul(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -327,9 +384,14 @@ TEST_F(CompilerTest, CreateDiv) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createDiv); - compiler->createDiv(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createDiv(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createDiv(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -340,9 +402,14 @@ TEST_F(CompilerTest, CreateCmpEQ) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createCmpEQ); - compiler->createCmpEQ(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createCmpEQ(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createCmpEQ(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -353,9 +420,14 @@ TEST_F(CompilerTest, CreateCmpGT) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createCmpGT); - compiler->createCmpGT(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createCmpGT(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createCmpGT(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -366,9 +438,14 @@ TEST_F(CompilerTest, CreateCmpLT) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createCmpLT); - compiler->createCmpLT(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createCmpLT(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createCmpLT(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -379,9 +456,14 @@ TEST_F(CompilerTest, CreateAnd) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createAnd); - compiler->createAnd(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createAnd(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createAnd(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -392,9 +474,14 @@ TEST_F(CompilerTest, CreateOr) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createOr); - compiler->createOr(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createOr(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createOr(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -405,9 +492,13 @@ TEST_F(CompilerTest, CreateNot) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createNot); - compiler->createNot(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createNot(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createNot(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -418,9 +509,14 @@ TEST_F(CompilerTest, CreateMod) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createMod); - compiler->createMod(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg1(Compiler::StaticType::Unknown); + CompilerValue arg2(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createMod(&arg1, &arg2)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createMod(&arg1, &arg2), &ret); + + return nullptr; }); compile(compiler, block); @@ -431,9 +527,13 @@ TEST_F(CompilerTest, CreateRound) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createRound); - compiler->createRound(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createRound(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createRound(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -444,9 +544,13 @@ TEST_F(CompilerTest, CreateAbs) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createAbs); - compiler->createAbs(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createAbs(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createAbs(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -457,9 +561,13 @@ TEST_F(CompilerTest, CreateFloor) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createFloor); - compiler->createFloor(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createFloor(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createFloor(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -470,9 +578,13 @@ TEST_F(CompilerTest, CreateCeil) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createCeil); - compiler->createCeil(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createCeil(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createCeil(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -483,9 +595,13 @@ TEST_F(CompilerTest, CreateSqrt) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createSqrt); - compiler->createSqrt(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createSqrt(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createSqrt(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -496,9 +612,13 @@ TEST_F(CompilerTest, CreateSin) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createSin); - compiler->createSin(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createSin(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createSin(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -509,9 +629,13 @@ TEST_F(CompilerTest, CreateCos) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createCos); - compiler->createCos(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createCos(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createCos(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -522,9 +646,13 @@ TEST_F(CompilerTest, CreateTan) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createTan); - compiler->createTan(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createTan(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createTan(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -535,9 +663,13 @@ TEST_F(CompilerTest, CreateAsin) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createAsin); - compiler->createAsin(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createAsin(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createAsin(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -548,9 +680,13 @@ TEST_F(CompilerTest, CreateAcos) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createAcos); - compiler->createAcos(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createAcos(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createAcos(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -561,9 +697,13 @@ TEST_F(CompilerTest, CreateAtan) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createAtan); - compiler->createAtan(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createAtan(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createAtan(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -574,9 +714,13 @@ TEST_F(CompilerTest, CreateLn) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createLn); - compiler->createLn(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createLn(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createLn(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -587,9 +731,13 @@ TEST_F(CompilerTest, CreateLog10) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createLog10); - compiler->createLog10(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createLog10(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createLog10(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -600,9 +748,13 @@ TEST_F(CompilerTest, CreateExp) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createExp); - compiler->createExp(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createExp(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createExp(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -613,9 +765,13 @@ TEST_F(CompilerTest, CreateExp10) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, createExp10); - compiler->createExp10(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + CompilerValue ret(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createExp10(&arg)).WillOnce(Return(&ret)); + EXPECT_EQ(compiler->createExp10(&arg), &ret); + + return nullptr; }); compile(compiler, block); @@ -626,10 +782,13 @@ TEST_F(CompilerTest, CreateVariableWrite) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { auto var = std::make_shared("", ""); - EXPECT_CALL(*m_builder, createVariableWrite(var.get())); - compiler->createVariableWrite(var.get()); + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, createVariableWrite(var.get(), &arg)); + compiler->createVariableWrite(var.get(), &arg); + + return nullptr; }); compile(compiler, block); @@ -640,18 +799,21 @@ TEST_F(CompilerTest, CustomIfStatement) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("", ""); - block->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginIfStatement()); - compiler->beginIfStatement(); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginIfStatement(&arg)); + compiler->beginIfStatement(&arg); EXPECT_CALL(*m_builder, endIf()); compiler->endIf(); - EXPECT_CALL(*m_builder, beginIfStatement()); - compiler->beginIfStatement(); + EXPECT_CALL(*m_builder, beginIfStatement(&arg)); + compiler->beginIfStatement(&arg); EXPECT_CALL(*m_builder, beginElseBranch()); compiler->beginElseBranch(); EXPECT_CALL(*m_builder, endIf()); compiler->endIf(); + + return nullptr; }); compile(compiler, block); @@ -663,25 +825,29 @@ TEST_F(CompilerTest, MoveToIf) EXPECT_CALL(*m_builder, beginElseBranch).Times(0); auto if1 = std::make_shared("", "if"); - if1->setCompileFunction([](Compiler *compiler) { + if1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); EXPECT_CALL(*m_builder, beginIfStatement).Times(0); EXPECT_CALL(*m_builder, endIf).Times(0); - compiler->moveToIf(nullptr); + compiler->moveToIf(&arg, nullptr); + return nullptr; }); auto if2 = std::make_shared("", "if"); if1->setNext(if2); if2->setParent(if1); - if2->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginIfStatement()); + if2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginIfStatement(&arg)); EXPECT_CALL(*m_builder, addConstValue(Value())); EXPECT_CALL(*m_builder, endIf()); - compiler->moveToIf(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToIf(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); auto substack1 = std::make_shared("", "substack"); substack1->setParent(if2); - substack1->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(Value()); }); + substack1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(Value()); }); auto input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack1); @@ -695,32 +861,36 @@ TEST_F(CompilerTest, MoveToIfElse) Compiler compiler(&m_engine, &m_target); auto if1 = std::make_shared("", "if"); - if1->setCompileFunction([](Compiler *compiler) { + if1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); EXPECT_CALL(*m_builder, beginIfStatement).Times(0); EXPECT_CALL(*m_builder, beginElseBranch).Times(0); EXPECT_CALL(*m_builder, endIf).Times(0); - compiler->moveToIfElse(nullptr, nullptr); + compiler->moveToIfElse(&arg, nullptr, nullptr); + return nullptr; }); auto if2 = std::make_shared("", "if"); if1->setNext(if2); if2->setParent(if1); - if2->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginIfStatement()); + if2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginIfStatement(&arg)); EXPECT_CALL(*m_builder, addConstValue(Value(1))); EXPECT_CALL(*m_builder, beginElseBranch()); EXPECT_CALL(*m_builder, addConstValue(Value(2))); EXPECT_CALL(*m_builder, endIf()); - compiler->moveToIfElse(compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); + compiler->moveToIfElse(&arg, compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); + return nullptr; }); auto substack1 = std::make_shared("", "substack"); substack1->setParent(if2); - substack1->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); }); + substack1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(1); }); auto substack2 = std::make_shared("", "substack"); substack2->setParent(if2); - substack2->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); }); + substack2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(2); }); auto input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack1); @@ -733,29 +903,35 @@ TEST_F(CompilerTest, MoveToIfElse) auto if3 = std::make_shared("", "if"); if2->setNext(if3); if3->setParent(if2); - if3->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginIfStatement()).Times(3); + if3->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginIfStatement).Times(3); EXPECT_CALL(*m_builder, beginElseBranch()).Times(3); EXPECT_CALL(*m_builder, endIf()).Times(3); EXPECT_CALL(*m_builder, addConstValue(Value(1))); EXPECT_CALL(*m_builder, addConstValue(Value(2))); EXPECT_CALL(*m_builder, addConstValue(Value(3))); EXPECT_CALL(*m_builder, addConstValue(Value(4))); - compiler->moveToIfElse(compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); + compiler->moveToIfElse(&arg, compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); + return nullptr; }); // if auto ifSubstack1 = std::make_shared("", "if"); ifSubstack1->setParent(if3); - ifSubstack1->setCompileFunction([](Compiler *compiler) { compiler->moveToIfElse(compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); }); + ifSubstack1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + compiler->moveToIfElse(&arg, compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); + return nullptr; + }); substack1 = std::make_shared("", "substack"); substack1->setParent(ifSubstack1); - substack1->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); }); + substack1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(1); }); substack2 = std::make_shared("", "substack"); substack2->setParent(ifSubstack1); - substack2->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); }); + substack2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(2); }); input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack1); @@ -767,15 +943,19 @@ TEST_F(CompilerTest, MoveToIfElse) // else auto ifSubstack2 = std::make_shared("", "if"); ifSubstack2->setParent(if3); - ifSubstack2->setCompileFunction([](Compiler *compiler) { compiler->moveToIfElse(compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); }); + ifSubstack2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + compiler->moveToIfElse(&arg, compiler->input("SUBSTACK")->valueBlock(), compiler->input("SUBSTACK2")->valueBlock()); + return nullptr; + }); substack1 = std::make_shared("", "substack"); substack1->setParent(ifSubstack2); - substack1->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(3); }); + substack1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(3); }); substack2 = std::make_shared("", "substack"); substack2->setParent(ifSubstack2); - substack2->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(4); }); + substack2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(4); }); input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack1); @@ -796,17 +976,19 @@ TEST_F(CompilerTest, MoveToIfElse) auto if4 = std::make_shared("", "if"); if3->setNext(if4); if4->setParent(if3); - if4->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginIfStatement()); + if4->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginIfStatement(&arg)); EXPECT_CALL(*m_builder, beginElseBranch()); EXPECT_CALL(*m_builder, addConstValue(Value(2))); EXPECT_CALL(*m_builder, endIf()); - compiler->moveToIfElse(nullptr, compiler->input("SUBSTACK2")->valueBlock()); + compiler->moveToIfElse(&arg, nullptr, compiler->input("SUBSTACK2")->valueBlock()); + return nullptr; }); substack2 = std::make_shared("", "substack"); substack2->setParent(if4); - substack2->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); }); + substack2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(2); }); input = std::make_shared("SUBSTACK2", Input::Type::NoShadow); input->setValueBlock(substack2); @@ -816,17 +998,19 @@ TEST_F(CompilerTest, MoveToIfElse) auto if5 = std::make_shared("", "if"); if4->setNext(if5); if5->setParent(if4); - if5->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginIfStatement()); + if5->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginIfStatement(&arg)); EXPECT_CALL(*m_builder, addConstValue(Value(1))); EXPECT_CALL(*m_builder, beginElseBranch()).Times(0); EXPECT_CALL(*m_builder, endIf()); - compiler->moveToIfElse(compiler->input("SUBSTACK")->valueBlock(), nullptr); + compiler->moveToIfElse(&arg, compiler->input("SUBSTACK")->valueBlock(), nullptr); + return nullptr; }); substack1 = std::make_shared("", "substack"); substack1->setParent(if5); - substack1->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); }); + substack1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(1); }); input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack1); @@ -836,7 +1020,7 @@ TEST_F(CompilerTest, MoveToIfElse) auto block = std::make_shared("", ""); block->setParent(if5); if5->setNext(block); - block->setCompileFunction([](Compiler *compiler) { compiler->addConstValue("after"); }); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue("after"); }); EXPECT_CALL(*m_builder, addConstValue(Value("after"))); compile(compiler, if1); @@ -847,25 +1031,29 @@ TEST_F(CompilerTest, MoveToRepeatLoop) Compiler compiler(&m_engine, &m_target); auto l1 = std::make_shared("", "loop"); - l1->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatLoop()); + l1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatLoop(&arg)); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToRepeatLoop(nullptr); + compiler->moveToRepeatLoop(&arg, nullptr); + return nullptr; }); auto l2 = std::make_shared("", "loop"); l1->setNext(l2); l2->setParent(l1); - l2->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatLoop()); + l2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatLoop(&arg)); EXPECT_CALL(*m_builder, addConstValue(Value(2))); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToRepeatLoop(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToRepeatLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); auto substack = std::make_shared("", "substack"); substack->setParent(l2); - substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); }); + substack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(2); }); auto input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack); @@ -875,21 +1063,27 @@ TEST_F(CompilerTest, MoveToRepeatLoop) auto l3 = std::make_shared("", "loop"); l2->setNext(l3); l3->setParent(l2); - l3->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatLoop()).Times(2); + l3->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatLoop).Times(2); EXPECT_CALL(*m_builder, endLoop()).Times(2); EXPECT_CALL(*m_builder, addConstValue(Value(1))); - compiler->moveToRepeatLoop(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToRepeatLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); // Begin loop auto loopSubstack = std::make_shared("", "loop"); loopSubstack->setParent(l3); - loopSubstack->setCompileFunction([](Compiler *compiler) { compiler->moveToRepeatLoop(compiler->input("SUBSTACK")->valueBlock()); }); + loopSubstack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + compiler->moveToRepeatLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; + }); substack = std::make_shared("", "substack"); substack->setParent(loopSubstack); - substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); }); + substack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(1); }); input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack); @@ -904,17 +1098,19 @@ TEST_F(CompilerTest, MoveToRepeatLoop) auto l4 = std::make_shared("", "loop"); l3->setNext(l4); l4->setParent(l3); - l4->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatLoop()); + l4->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatLoop(&arg)); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToRepeatLoop(nullptr); + compiler->moveToRepeatLoop(&arg, nullptr); + return nullptr; }); // Code after the loop auto block = std::make_shared("", ""); block->setParent(l4); l4->setNext(block); - block->setCompileFunction([](Compiler *compiler) { compiler->addConstValue("after"); }); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue("after"); }); EXPECT_CALL(*m_builder, addConstValue(Value("after"))); compile(compiler, l1); @@ -925,25 +1121,29 @@ TEST_F(CompilerTest, MoveToWhileLoop) Compiler compiler(&m_engine, &m_target); auto l1 = std::make_shared("", "loop"); - l1->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginWhileLoop()); + l1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginWhileLoop(&arg)); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToWhileLoop(nullptr); + compiler->moveToWhileLoop(&arg, nullptr); + return nullptr; }); auto l2 = std::make_shared("", "loop"); l1->setNext(l2); l2->setParent(l1); - l2->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginWhileLoop()); + l2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginWhileLoop(&arg)); EXPECT_CALL(*m_builder, addConstValue(Value(2))); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToWhileLoop(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToWhileLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); auto substack = std::make_shared("", "substack"); substack->setParent(l2); - substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); }); + substack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(2); }); auto input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack); @@ -953,21 +1153,27 @@ TEST_F(CompilerTest, MoveToWhileLoop) auto l3 = std::make_shared("", "loop"); l2->setNext(l3); l3->setParent(l2); - l3->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginWhileLoop()).Times(2); + l3->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginWhileLoop).Times(2); EXPECT_CALL(*m_builder, endLoop()).Times(2); EXPECT_CALL(*m_builder, addConstValue(Value(1))); - compiler->moveToWhileLoop(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToWhileLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); // Begin loop auto loopSubstack = std::make_shared("", "loop"); loopSubstack->setParent(l3); - loopSubstack->setCompileFunction([](Compiler *compiler) { compiler->moveToWhileLoop(compiler->input("SUBSTACK")->valueBlock()); }); + loopSubstack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + compiler->moveToWhileLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; + }); substack = std::make_shared("", "substack"); substack->setParent(loopSubstack); - substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); }); + substack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(1); }); input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack); @@ -982,17 +1188,19 @@ TEST_F(CompilerTest, MoveToWhileLoop) auto l4 = std::make_shared("", "loop"); l3->setNext(l4); l4->setParent(l3); - l4->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginWhileLoop()); + l4->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginWhileLoop(&arg)); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToWhileLoop(nullptr); + compiler->moveToWhileLoop(&arg, nullptr); + return nullptr; }); // Code after the loop auto block = std::make_shared("", ""); block->setParent(l4); l4->setNext(block); - block->setCompileFunction([](Compiler *compiler) { compiler->addConstValue("after"); }); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue("after"); }); EXPECT_CALL(*m_builder, addConstValue(Value("after"))); compile(compiler, l1); @@ -1003,25 +1211,29 @@ TEST_F(CompilerTest, MoveToRepeatUntilLoop) Compiler compiler(&m_engine, &m_target); auto l1 = std::make_shared("", "loop"); - l1->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatUntilLoop()); + l1->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatUntilLoop(&arg)); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToRepeatUntilLoop(nullptr); + compiler->moveToRepeatUntilLoop(&arg, nullptr); + return nullptr; }); auto l2 = std::make_shared("", "loop"); l1->setNext(l2); l2->setParent(l1); - l2->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatUntilLoop()); + l2->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatUntilLoop(&arg)); EXPECT_CALL(*m_builder, addConstValue(Value(2))); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToRepeatUntilLoop(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToRepeatUntilLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); auto substack = std::make_shared("", "substack"); substack->setParent(l2); - substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); }); + substack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(2); }); auto input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack); @@ -1031,21 +1243,27 @@ TEST_F(CompilerTest, MoveToRepeatUntilLoop) auto l3 = std::make_shared("", "loop"); l2->setNext(l3); l3->setParent(l2); - l3->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatUntilLoop()).Times(2); + l3->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatUntilLoop).Times(2); EXPECT_CALL(*m_builder, endLoop()).Times(2); EXPECT_CALL(*m_builder, addConstValue(Value(1))); - compiler->moveToRepeatUntilLoop(compiler->input("SUBSTACK")->valueBlock()); + compiler->moveToRepeatUntilLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; }); // Begin loop auto loopSubstack = std::make_shared("", "loop"); loopSubstack->setParent(l3); - loopSubstack->setCompileFunction([](Compiler *compiler) { compiler->moveToRepeatUntilLoop(compiler->input("SUBSTACK")->valueBlock()); }); + loopSubstack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + compiler->moveToRepeatUntilLoop(&arg, compiler->input("SUBSTACK")->valueBlock()); + return nullptr; + }); substack = std::make_shared("", "substack"); substack->setParent(loopSubstack); - substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); }); + substack->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(1); }); input = std::make_shared("SUBSTACK", Input::Type::NoShadow); input->setValueBlock(substack); @@ -1060,17 +1278,19 @@ TEST_F(CompilerTest, MoveToRepeatUntilLoop) auto l4 = std::make_shared("", "loop"); l3->setNext(l4); l4->setParent(l3); - l4->setCompileFunction([](Compiler *compiler) { - EXPECT_CALL(*m_builder, beginRepeatUntilLoop()); + l4->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + CompilerValue arg(Compiler::StaticType::Unknown); + EXPECT_CALL(*m_builder, beginRepeatUntilLoop(&arg)); EXPECT_CALL(*m_builder, endLoop()); - compiler->moveToRepeatUntilLoop(nullptr); + compiler->moveToRepeatUntilLoop(&arg, nullptr); + return nullptr; }); // Code after the loop auto block = std::make_shared("", ""); block->setParent(l4); l4->setNext(block); - block->setCompileFunction([](Compiler *compiler) { compiler->addConstValue("after"); }); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue("after"); }); EXPECT_CALL(*m_builder, addConstValue(Value("after"))); compile(compiler, l1); @@ -1080,9 +1300,10 @@ TEST_F(CompilerTest, BeginLoopCondition) { Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); - block->setCompileFunction([](Compiler *compiler) { + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { EXPECT_CALL(*m_builder, beginLoopCondition()); compiler->beginLoopCondition(); + return nullptr; }); compile(compiler, block); @@ -1093,9 +1314,10 @@ TEST_F(CompilerTest, Input) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); block->addInput(std::make_shared("TEST", Input::Type::Shadow)); - block->setCompileFunction([](Compiler *compiler) { - ASSERT_EQ(compiler->input("INVALID"), nullptr); - ASSERT_EQ(compiler->input("TEST"), compiler->block()->inputAt(0).get()); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + EXPECT_EQ(compiler->input("INVALID"), nullptr); + EXPECT_EQ(compiler->input("TEST"), compiler->block()->inputAt(0).get()); + return nullptr; }); compile(compiler, block); @@ -1106,9 +1328,10 @@ TEST_F(CompilerTest, Field) Compiler compiler(&m_engine, &m_target); auto block = std::make_shared("a", ""); block->addField(std::make_shared("TEST", "test")); - block->setCompileFunction([](Compiler *compiler) { - ASSERT_EQ(compiler->field("INVALID"), nullptr); - ASSERT_EQ(compiler->field("TEST"), compiler->block()->fieldAt(0).get()); + block->setCompileFunction([](Compiler *compiler) -> CompilerValue * { + EXPECT_EQ(compiler->field("INVALID"), nullptr); + EXPECT_EQ(compiler->field("TEST"), compiler->block()->fieldAt(0).get()); + return nullptr; }); compile(compiler, block); @@ -1118,15 +1341,15 @@ TEST_F(CompilerTest, UnsupportedBlocks) { auto valueBlock1 = std::make_shared("v1", "value_block1"); auto valueBlock2 = std::make_shared("v2", "value_block2"); - valueBlock2->setCompileFunction([](Compiler *) {}); + valueBlock2->setCompileFunction([](Compiler *) -> CompilerValue * { return nullptr; }); auto valueBlock3 = std::make_shared("v3", "value_block3"); auto valueBlock4 = std::make_shared("v4", "value_block4"); - valueBlock4->setCompileFunction([](Compiler *) {}); + valueBlock4->setCompileFunction([](Compiler *) -> CompilerValue * { return nullptr; }); auto valueBlock5 = std::make_shared("v5", "value_block5"); auto valueBlock6 = std::make_shared("v6", "value_block6"); - valueBlock6->setCompileFunction([](Compiler *) {}); + valueBlock6->setCompileFunction([](Compiler *) -> CompilerValue * { return nullptr; }); auto block1 = std::make_shared("b1", "block1"); @@ -1153,13 +1376,14 @@ TEST_F(CompilerTest, UnsupportedBlocks) auto input6 = std::make_shared("INPUT6", Input::Type::ObscuredShadow); input6->setValueBlock(valueBlock6); block3->addInput(input6); - block3->setCompileFunction([](Compiler *compiler) { + block3->setCompileFunction([](Compiler *compiler) -> CompilerValue * { compiler->addInput("INPUT1"); compiler->addInput("INPUT2"); compiler->addInput("INPUT3"); compiler->addInput("INPUT4"); compiler->addInput("INPUT5"); compiler->addInput("INPUT6"); + return nullptr; }); block3->setParent(block2); block2->setNext(block3); @@ -1169,7 +1393,7 @@ TEST_F(CompilerTest, UnsupportedBlocks) block3->setNext(block4); Compiler compiler(&m_engine, &m_target); - EXPECT_CALL(*m_builder, addConstValue).WillRepeatedly(Return()); + EXPECT_CALL(*m_builder, addConstValue).WillRepeatedly(Return(nullptr)); compile(compiler, block1); ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set({ "block1", "block2", "value_block1", "value_block3", "value_block5", "block4" })); diff --git a/test/dev/compiler/compilerconstant_test.cpp b/test/dev/compiler/compilerconstant_test.cpp new file mode 100644 index 00000000..c7c58720 --- /dev/null +++ b/test/dev/compiler/compilerconstant_test.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +using namespace libscratchcpp; + +TEST(CompilerConstantTest, Constructors) +{ + { + CompilerConstant v(Compiler::StaticType::Number, 5); + ASSERT_EQ(v.type(), Compiler::StaticType::Number); + ASSERT_EQ(v.value(), 5); + } + + { + CompilerConstant v(Compiler::StaticType::String, "test"); + ASSERT_EQ(v.type(), Compiler::StaticType::String); + ASSERT_EQ(v.value(), "test"); + } + + { + CompilerConstant v(Compiler::StaticType::Unknown, true); + ASSERT_EQ(v.type(), Compiler::StaticType::Unknown); + ASSERT_EQ(v.value(), true); + } +} + +TEST(CompilerConstantTest, IsConst) +{ + CompilerConstant v(Compiler::StaticType::Unknown, Value()); + ASSERT_TRUE(v.isConst()); +} diff --git a/test/dev/compiler/compilervalue_test.cpp b/test/dev/compiler/compilervalue_test.cpp new file mode 100644 index 00000000..a5256ba1 --- /dev/null +++ b/test/dev/compiler/compilervalue_test.cpp @@ -0,0 +1,42 @@ +#include +#include + +using namespace libscratchcpp; + +TEST(CompilerValueTest, Constructors) +{ + { + CompilerValue v(Compiler::StaticType::Number); + ASSERT_EQ(v.type(), Compiler::StaticType::Number); + } + + { + CompilerValue v(Compiler::StaticType::String); + ASSERT_EQ(v.type(), Compiler::StaticType::String); + } + + { + CompilerValue v(Compiler::StaticType::Unknown); + ASSERT_EQ(v.type(), Compiler::StaticType::Unknown); + } +} + +TEST(CompilerValueTest, Type) +{ + CompilerValue v(Compiler::StaticType::Unknown); + + v.setType(Compiler::StaticType::String); + ASSERT_EQ(v.type(), Compiler::StaticType::String); + + v.setType(Compiler::StaticType::Bool); + ASSERT_EQ(v.type(), Compiler::StaticType::Bool); + + v.setType(Compiler::StaticType::Unknown); + ASSERT_EQ(v.type(), Compiler::StaticType::Unknown); +} + +TEST(CompilerValueTest, IsConst) +{ + CompilerValue v(Compiler::StaticType::Unknown); + ASSERT_FALSE(v.isConst()); +} diff --git a/test/dev/llvm/llvmcodebuilder_test.cpp b/test/dev/llvm/llvmcodebuilder_test.cpp index 747a63f5..07746d3d 100644 --- a/test/dev/llvm/llvmcodebuilder_test.cpp +++ b/test/dev/llvm/llvmcodebuilder_test.cpp @@ -19,6 +19,37 @@ using ::testing::Eq; class LLVMCodeBuilderTest : public testing::Test { public: + enum class OpType + { + Add, + Sub, + Mul, + Div, + CmpEQ, + CmpGT, + CmpLT, + And, + Or, + Not, + Mod, + Round, + Abs, + Floor, + Ceil, + Sqrt, + Sin, + Cos, + Tan, + Asin, + Acos, + Atan, + Ln, + Log10, + Exp, + Exp10 + + }; + void SetUp() override { test_function(nullptr, nullptr, nullptr, nullptr); // force dependency @@ -27,27 +58,252 @@ class LLVMCodeBuilderTest : public testing::Test void createBuilder(Target *target, bool warp) { m_builder = std::make_unique(target, "test", warp); } void createBuilder(bool warp) { createBuilder(nullptr, warp); } - void callConstFuncForType(ValueType type) + CompilerValue *callConstFuncForType(ValueType type, CompilerValue *arg) { switch (type) { case ValueType::Number: - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - break; + return m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { arg }); case ValueType::Bool: - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - break; + return m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { arg }); case ValueType::String: - m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }); - break; + return m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { arg }); + + default: + EXPECT_TRUE(false); + return nullptr; + } + } + + CompilerValue *addOp(OpType type, CompilerValue *arg1, CompilerValue *arg2) + { + switch (type) { + case OpType::Add: + return m_builder->createAdd(arg1, arg2); + + case OpType::Sub: + return m_builder->createSub(arg1, arg2); + + case OpType::Mul: + return m_builder->createMul(arg1, arg2); + + case OpType::Div: + return m_builder->createDiv(arg1, arg2); + + case OpType::CmpEQ: + return m_builder->createCmpEQ(arg1, arg2); + + case OpType::CmpGT: + return m_builder->createCmpGT(arg1, arg2); + + case OpType::CmpLT: + return m_builder->createCmpLT(arg1, arg2); + + case OpType::And: + return m_builder->createAnd(arg1, arg2); + + case OpType::Or: + return m_builder->createOr(arg1, arg2); + + case OpType::Mod: + return m_builder->createMod(arg1, arg2); + + default: + EXPECT_TRUE(false); + return nullptr; + } + } + + CompilerValue *addOp(OpType type, CompilerValue *arg) + { + switch (type) { + case OpType::Not: + return m_builder->createNot(arg); + + case OpType::Round: + return m_builder->createRound(arg); + + case OpType::Abs: + return m_builder->createAbs(arg); + + case OpType::Floor: + return m_builder->createFloor(arg); + + case OpType::Ceil: + return m_builder->createCeil(arg); + + case OpType::Sqrt: + return m_builder->createSqrt(arg); + + case OpType::Sin: + return m_builder->createSin(arg); + + case OpType::Cos: + return m_builder->createCos(arg); + + case OpType::Tan: + return m_builder->createTan(arg); + + case OpType::Asin: + return m_builder->createAsin(arg); + + case OpType::Acos: + return m_builder->createAcos(arg); + + case OpType::Atan: + return m_builder->createAtan(arg); + + case OpType::Ln: + return m_builder->createLn(arg); + + case OpType::Log10: + return m_builder->createLog10(arg); + + case OpType::Exp: + return m_builder->createExp(arg); + + case OpType::Exp10: + return m_builder->createExp10(arg); + + default: + EXPECT_TRUE(false); + return nullptr; + } + } + + Value doOp(OpType type, const Value &v1, const Value &v2) + { + switch (type) { + case OpType::Add: + return v1 + v2; + + case OpType::Sub: + return v1 - v2; + + case OpType::Mul: + return v1 * v2; + + case OpType::Div: + return v1 / v2; + + case OpType::CmpEQ: + return v1 == v2; + + case OpType::CmpGT: + return v1 > v2; + + case OpType::CmpLT: + return v1 < v2; + + case OpType::And: + return v1.toBool() && v2.toBool(); + + case OpType::Or: + return v1.toBool() || v2.toBool(); + + case OpType::Mod: + return v1 % v2; default: - FAIL(); - break; + EXPECT_TRUE(false); + return Value(); } } + Value doOp(OpType type, const Value &v) + { + switch (type) { + case OpType::Not: + return !v.toBool(); + + default: + EXPECT_TRUE(false); + return Value(); + } + } + + void runOpTest(OpType type, const Value &v1, const Value &v2) + { + createBuilder(true); + + CompilerValue *arg1 = m_builder->addConstValue(v1); + CompilerValue *arg2 = m_builder->addConstValue(v2); + CompilerValue *ret = addOp(type, arg1, arg2); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); + + arg1 = m_builder->addConstValue(v1); + arg1 = callConstFuncForType(v1.type(), arg1); + arg2 = m_builder->addConstValue(v2); + arg2 = callConstFuncForType(v2.type(), arg2); + ret = addOp(type, arg1, arg2); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); + + std::string str = doOp(type, v1, v2).toString() + '\n'; + std::string expected = str + str; + + auto code = m_builder->finalize(); + auto ctx = code->createExecutionContext(&m_target); + + testing::internal::CaptureStdout(); + code->run(ctx.get()); + const std::string quotes1 = v1.isString() ? "\"" : ""; + const std::string quotes2 = v2.isString() ? "\"" : ""; + ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; + }; + + void runOpTest(OpType type, const Value &v) + { + createBuilder(true); + + CompilerValue *arg = m_builder->addConstValue(v); + CompilerValue *ret = addOp(type, arg); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); + + arg = m_builder->addConstValue(v); + arg = callConstFuncForType(v.type(), arg); + ret = addOp(type, arg); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { ret }); + + std::string str = doOp(type, v).toString() + '\n'; + std::string expected = str + str; + + auto code = m_builder->finalize(); + auto ctx = code->createExecutionContext(&m_target); + + testing::internal::CaptureStdout(); + code->run(ctx.get()); + const std::string quotes = v.isString() ? "\"" : ""; + ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "NOT: " << quotes << v.toString() << quotes; + }; + + void runUnaryNumOpTest(OpType type, const Value &v, double expectedResult) + { + createBuilder(true); + + CompilerValue *arg = m_builder->addConstValue(v); + CompilerValue *ret = addOp(type, arg); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { ret }); + + arg = m_builder->addConstValue(v); + arg = callConstFuncForType(v.type(), arg); + ret = addOp(type, arg); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { ret }); + + std::stringstream stream; + stream << expectedResult; + std::string str = stream.str() + '\n'; + std::string expected = str + str; + + auto code = m_builder->finalize(); + auto ctx = code->createExecutionContext(&m_target); + + testing::internal::CaptureStdout(); + code->run(ctx.get()); + const std::string quotes = v.isString() ? "\"" : ""; + ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes << v.toString() << quotes; + }; + std::unique_ptr m_builder; TargetMock m_target; // NOTE: isStage() is used for call expectations }; @@ -58,22 +314,26 @@ TEST_F(LLVMCodeBuilderTest, FunctionCalls) for (bool warp : warpList) { createBuilder(warp); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); - - m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue("1"); - m_builder->addFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->addConstValue("2"); - m_builder->addConstValue("3"); - m_builder->addFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }); - - m_builder->addConstValue("test"); - m_builder->addConstValue("4"); - m_builder->addConstValue("5"); - m_builder->addFunctionCall("test_function_3_args_ret", Compiler::StaticType::String, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); + + CompilerValue *v = m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {}); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); + + v = m_builder->addConstValue("1"); + v = m_builder->addFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }, { v }); + CompilerValue *v1 = m_builder->addConstValue("2"); + CompilerValue *v2 = m_builder->addConstValue("3"); + m_builder->addFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, { v, v1, v2 }); + + v = m_builder->addConstValue("test"); + v1 = m_builder->addConstValue("4"); + v2 = m_builder->addConstValue("5"); + v = m_builder->addFunctionCall( + "test_function_3_args_ret", + Compiler::StaticType::String, + { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, + { v, v1, v2 }); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&m_target); @@ -98,25 +358,25 @@ TEST_F(LLVMCodeBuilderTest, ConstCasting) { createBuilder(true); - m_builder->addConstValue(5.2); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - m_builder->addConstValue("-24.156"); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); + CompilerValue *v = m_builder->addConstValue(5.2); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); + v = m_builder->addConstValue("-24.156"); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - m_builder->addConstValue(true); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue(true); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue(0); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - m_builder->addConstValue("false"); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue("false"); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - m_builder->addConstValue("123"); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("123"); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("hello world"); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("hello world"); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&m_target); @@ -140,69 +400,69 @@ TEST_F(LLVMCodeBuilderTest, RawValueCasting) createBuilder(true); // Number -> number - m_builder->addConstValue(5.2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); + CompilerValue *v = m_builder->addConstValue(5.2); + v = callConstFuncForType(ValueType::Number, v); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); // Number -> bool - m_builder->addConstValue(-24.156); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue(-24.156); + v = callConstFuncForType(ValueType::Number, v); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue(0); + v = callConstFuncForType(ValueType::Number, v); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); // Number -> string - m_builder->addConstValue(59.8); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(59.8); + v = callConstFuncForType(ValueType::Number, v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); // Bool -> number - m_builder->addConstValue(true); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); + v = m_builder->addConstValue(true); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); - m_builder->addConstValue(false); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); + v = m_builder->addConstValue(false); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); // Bool -> bool - m_builder->addConstValue(true); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue(true); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - m_builder->addConstValue(false); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue(false); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); // Bool -> string - m_builder->addConstValue(true); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(true); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(false); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(false); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); // String -> number - m_builder->addConstValue("5.2"); - m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); + v = m_builder->addConstValue("5.2"); + v = callConstFuncForType(ValueType::String, v); + m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v }); // String -> bool - m_builder->addConstValue("abc"); - m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue("abc"); + v = callConstFuncForType(ValueType::String, v); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); - m_builder->addConstValue("false"); - m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }); + v = m_builder->addConstValue("false"); + v = callConstFuncForType(ValueType::String, v); + m_builder->addFunctionCall("test_print_bool", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { v }); // String -> string - m_builder->addConstValue("hello world"); - m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("hello world"); + v = callConstFuncForType(ValueType::String, v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&m_target); @@ -230,1557 +490,835 @@ TEST_F(LLVMCodeBuilderTest, RawValueCasting) TEST_F(LLVMCodeBuilderTest, Add) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, Value v2) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createAdd(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addConstValue(v2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createAdd(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = (v1 + v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(50, 25); - addOpTest(-500, 25); - addOpTest(-500, -25); - addOpTest("2.54", "6.28"); - addOpTest(2.54, "-6.28"); - addOpTest(true, true); - addOpTest("Infinity", "Infinity"); - addOpTest("Infinity", "-Infinity"); - addOpTest("-Infinity", "Infinity"); - addOpTest("-Infinity", "-Infinity"); - addOpTest(1, "NaN"); - addOpTest("NaN", 1); + runOpTest(OpType::Add, 50, 25); + runOpTest(OpType::Add, -500, 25); + runOpTest(OpType::Add, -500, -25); + runOpTest(OpType::Add, "2.54", "6.28"); + runOpTest(OpType::Add, 2.54, "-6.28"); + runOpTest(OpType::Add, true, true); + runOpTest(OpType::Add, "Infinity", "Infinity"); + runOpTest(OpType::Add, "Infinity", "-Infinity"); + runOpTest(OpType::Add, "-Infinity", "Infinity"); + runOpTest(OpType::Add, "-Infinity", "-Infinity"); + runOpTest(OpType::Add, 1, "NaN"); + runOpTest(OpType::Add, "NaN", 1); } TEST_F(LLVMCodeBuilderTest, Subtract) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, Value v2) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createSub(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addConstValue(v2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createSub(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = (v1 - v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(50, 25); - addOpTest(-500, 25); - addOpTest(-500, -25); - addOpTest("2.54", "6.28"); - addOpTest(2.54, "-6.28"); - addOpTest(true, true); - addOpTest("Infinity", "Infinity"); - addOpTest("Infinity", "-Infinity"); - addOpTest("-Infinity", "Infinity"); - addOpTest("-Infinity", "-Infinity"); - addOpTest(1, "NaN"); - addOpTest("NaN", 1); + runOpTest(OpType::Sub, 50, 25); + runOpTest(OpType::Sub, -500, 25); + runOpTest(OpType::Sub, -500, -25); + runOpTest(OpType::Sub, "2.54", "6.28"); + runOpTest(OpType::Sub, 2.54, "-6.28"); + runOpTest(OpType::Sub, true, true); + runOpTest(OpType::Sub, "Infinity", "Infinity"); + runOpTest(OpType::Sub, "Infinity", "-Infinity"); + runOpTest(OpType::Sub, "-Infinity", "Infinity"); + runOpTest(OpType::Sub, "-Infinity", "-Infinity"); + runOpTest(OpType::Sub, 1, "NaN"); + runOpTest(OpType::Sub, "NaN", 1); } TEST_F(LLVMCodeBuilderTest, Multiply) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, Value v2) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createMul(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addConstValue(v2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createMul(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = (v1 * v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(50, 2); - addOpTest(-500, 25); - addOpTest("-500", -25); - addOpTest("2.54", "6.28"); - addOpTest(true, true); - addOpTest("Infinity", "Infinity"); - addOpTest("Infinity", 0); - addOpTest("Infinity", 2); - addOpTest("Infinity", -2); - addOpTest("Infinity", "-Infinity"); - addOpTest("-Infinity", "Infinity"); - addOpTest("-Infinity", 0); - addOpTest("-Infinity", 2); - addOpTest("-Infinity", -2); - addOpTest("-Infinity", "-Infinity"); - addOpTest(1, "NaN"); - addOpTest("NaN", 1); + runOpTest(OpType::Mul, 50, 2); + runOpTest(OpType::Mul, -500, 25); + runOpTest(OpType::Mul, "-500", -25); + runOpTest(OpType::Mul, "2.54", "6.28"); + runOpTest(OpType::Mul, true, true); + runOpTest(OpType::Mul, "Infinity", "Infinity"); + runOpTest(OpType::Mul, "Infinity", 0); + runOpTest(OpType::Mul, "Infinity", 2); + runOpTest(OpType::Mul, "Infinity", -2); + runOpTest(OpType::Mul, "Infinity", "-Infinity"); + runOpTest(OpType::Mul, "-Infinity", "Infinity"); + runOpTest(OpType::Mul, "-Infinity", 0); + runOpTest(OpType::Mul, "-Infinity", 2); + runOpTest(OpType::Mul, "-Infinity", -2); + runOpTest(OpType::Mul, "-Infinity", "-Infinity"); + runOpTest(OpType::Mul, 1, "NaN"); + runOpTest(OpType::Mul, "NaN", 1); } TEST_F(LLVMCodeBuilderTest, Divide) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, Value v2) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createDiv(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addConstValue(v2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createDiv(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = (v1 / v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(50, 2); - addOpTest(-500, 25); - addOpTest("-500", -25); - addOpTest("3.5", "2.5"); - addOpTest(true, true); - addOpTest("Infinity", "Infinity"); - addOpTest("Infinity", 0); - addOpTest("Infinity", 2); - addOpTest("Infinity", -2); - addOpTest("Infinity", "-Infinity"); - addOpTest("-Infinity", "Infinity"); - addOpTest("-Infinity", 0); - addOpTest("-Infinity", 2); - addOpTest("-Infinity", -2); - addOpTest("-Infinity", "-Infinity"); - addOpTest(0, "Infinity"); - addOpTest(2, "Infinity"); - addOpTest(-2, "Infinity"); - addOpTest(0, "-Infinity"); - addOpTest(2, "-Infinity"); - addOpTest(-2, "-Infinity"); - addOpTest(1, "NaN"); - addOpTest("NaN", 1); - addOpTest(5, 0); - addOpTest(-5, 0); - addOpTest(0, 0); + runOpTest(OpType::Div, 50, 2); + runOpTest(OpType::Div, -500, 25); + runOpTest(OpType::Div, "-500", -25); + runOpTest(OpType::Div, "3.5", "2.5"); + runOpTest(OpType::Div, true, true); + runOpTest(OpType::Div, "Infinity", "Infinity"); + runOpTest(OpType::Div, "Infinity", 0); + runOpTest(OpType::Div, "Infinity", 2); + runOpTest(OpType::Div, "Infinity", -2); + runOpTest(OpType::Div, "Infinity", "-Infinity"); + runOpTest(OpType::Div, "-Infinity", "Infinity"); + runOpTest(OpType::Div, "-Infinity", 0); + runOpTest(OpType::Div, "-Infinity", 2); + runOpTest(OpType::Div, "-Infinity", -2); + runOpTest(OpType::Div, "-Infinity", "-Infinity"); + runOpTest(OpType::Div, 0, "Infinity"); + runOpTest(OpType::Div, 2, "Infinity"); + runOpTest(OpType::Div, -2, "Infinity"); + runOpTest(OpType::Div, 0, "-Infinity"); + runOpTest(OpType::Div, 2, "-Infinity"); + runOpTest(OpType::Div, -2, "-Infinity"); + runOpTest(OpType::Div, 1, "NaN"); + runOpTest(OpType::Div, "NaN", 1); + runOpTest(OpType::Div, 5, 0); + runOpTest(OpType::Div, -5, 0); + runOpTest(OpType::Div, 0, 0); } TEST_F(LLVMCodeBuilderTest, EqualComparison) { - auto addOpTest = [this](Value v1, Value v2) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createCmpEQ(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - callConstFuncForType(v1.type()); - m_builder->addConstValue(v2); - callConstFuncForType(v2.type()); - m_builder->createCmpEQ(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = Value(v1 == v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(10, 10); - addOpTest(10, 8); - addOpTest(8, 10); - - addOpTest(-4.25, -4.25); - addOpTest(-4.25, 5.312); - addOpTest(5.312, -4.25); - - addOpTest(true, true); - addOpTest(true, false); - addOpTest(false, true); - - addOpTest(1, true); - addOpTest(1, false); - - addOpTest("abC def", "abC def"); - addOpTest("abC def", "abc dEf"); - addOpTest("abC def", "ghi Jkl"); - addOpTest("abC def", "hello world"); - - addOpTest(" ", ""); - addOpTest(" ", "0"); - addOpTest(" ", 0); - addOpTest(0, " "); - addOpTest("", "0"); - addOpTest("", 0); - addOpTest(0, ""); - addOpTest("0", 0); - addOpTest(0, "0"); - - addOpTest(5.25, "5.25"); - addOpTest("5.25", 5.25); - addOpTest(5.25, " 5.25"); - addOpTest(" 5.25", 5.25); - addOpTest(5.25, "5.25 "); - addOpTest("5.25 ", 5.25); - addOpTest(5.25, " 5.25 "); - addOpTest(" 5.25 ", 5.25); - addOpTest(5.25, "5.26"); - addOpTest("5.26", 5.25); - addOpTest("5.25", "5.26"); - addOpTest(5, "5 "); - addOpTest("5 ", 5); - addOpTest(0, "1"); - addOpTest("1", 0); - addOpTest(0, "test"); - addOpTest("test", 0); + runOpTest(OpType::CmpEQ, 10, 10); + runOpTest(OpType::CmpEQ, 10, 8); + runOpTest(OpType::CmpEQ, 8, 10); + + runOpTest(OpType::CmpEQ, -4.25, -4.25); + runOpTest(OpType::CmpEQ, -4.25, 5.312); + runOpTest(OpType::CmpEQ, 5.312, -4.25); + + runOpTest(OpType::CmpEQ, true, true); + runOpTest(OpType::CmpEQ, true, false); + runOpTest(OpType::CmpEQ, false, true); + + runOpTest(OpType::CmpEQ, 1, true); + runOpTest(OpType::CmpEQ, 1, false); + + runOpTest(OpType::CmpEQ, "abC def", "abC def"); + runOpTest(OpType::CmpEQ, "abC def", "abc dEf"); + runOpTest(OpType::CmpEQ, "abC def", "ghi Jkl"); + runOpTest(OpType::CmpEQ, "abC def", "hello world"); + + runOpTest(OpType::CmpEQ, " ", ""); + runOpTest(OpType::CmpEQ, " ", "0"); + runOpTest(OpType::CmpEQ, " ", 0); + runOpTest(OpType::CmpEQ, 0, " "); + runOpTest(OpType::CmpEQ, "", "0"); + runOpTest(OpType::CmpEQ, "", 0); + runOpTest(OpType::CmpEQ, 0, ""); + runOpTest(OpType::CmpEQ, "0", 0); + runOpTest(OpType::CmpEQ, 0, "0"); + + runOpTest(OpType::CmpEQ, 5.25, "5.25"); + runOpTest(OpType::CmpEQ, "5.25", 5.25); + runOpTest(OpType::CmpEQ, 5.25, " 5.25"); + runOpTest(OpType::CmpEQ, " 5.25", 5.25); + runOpTest(OpType::CmpEQ, 5.25, "5.25 "); + runOpTest(OpType::CmpEQ, "5.25 ", 5.25); + runOpTest(OpType::CmpEQ, 5.25, " 5.25 "); + runOpTest(OpType::CmpEQ, " 5.25 ", 5.25); + runOpTest(OpType::CmpEQ, 5.25, "5.26"); + runOpTest(OpType::CmpEQ, "5.26", 5.25); + runOpTest(OpType::CmpEQ, "5.25", "5.26"); + runOpTest(OpType::CmpEQ, 5, "5 "); + runOpTest(OpType::CmpEQ, "5 ", 5); + runOpTest(OpType::CmpEQ, 0, "1"); + runOpTest(OpType::CmpEQ, "1", 0); + runOpTest(OpType::CmpEQ, 0, "test"); + runOpTest(OpType::CmpEQ, "test", 0); static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(inf, inf); - addOpTest(-inf, -inf); - addOpTest(nan, nan); - addOpTest(inf, -inf); - addOpTest(-inf, inf); - addOpTest(inf, nan); - addOpTest(nan, inf); - addOpTest(-inf, nan); - addOpTest(nan, -inf); - - addOpTest(5, inf); - addOpTest(5, -inf); - addOpTest(5, nan); - addOpTest(0, nan); - - addOpTest(true, "true"); - addOpTest("true", true); - addOpTest(false, "false"); - addOpTest("false", false); - addOpTest(false, "true"); - addOpTest("true", false); - addOpTest(true, "false"); - addOpTest("false", true); - addOpTest(true, "TRUE"); - addOpTest("TRUE", true); - addOpTest(false, "FALSE"); - addOpTest("FALSE", false); - - addOpTest(true, "00001"); - addOpTest("00001", true); - addOpTest(true, "00000"); - addOpTest("00000", true); - addOpTest(false, "00000"); - addOpTest("00000", false); - - addOpTest("true", 1); - addOpTest(1, "true"); - addOpTest("true", 0); - addOpTest(0, "true"); - addOpTest("false", 0); - addOpTest(0, "false"); - addOpTest("false", 1); - addOpTest(1, "false"); - - addOpTest("true", "TRUE"); - addOpTest("true", "FALSE"); - addOpTest("false", "FALSE"); - addOpTest("false", "TRUE"); - - addOpTest(true, inf); - addOpTest(true, -inf); - addOpTest(true, nan); - addOpTest(false, inf); - addOpTest(false, -inf); - addOpTest(false, nan); - - addOpTest("Infinity", inf); - addOpTest("Infinity", -inf); - addOpTest("Infinity", nan); - addOpTest("infinity", inf); - addOpTest("infinity", -inf); - addOpTest("infinity", nan); - addOpTest("-Infinity", inf); - addOpTest("-Infinity", -inf); - addOpTest("-Infinity", nan); - addOpTest("-infinity", inf); - addOpTest("-infinity", -inf); - addOpTest("-infinity", nan); - addOpTest("NaN", inf); - addOpTest("NaN", -inf); - addOpTest("NaN", nan); - addOpTest("nan", inf); - addOpTest("nan", -inf); - addOpTest("nan", nan); - - addOpTest(inf, "abc"); - addOpTest(inf, " "); - addOpTest(inf, ""); - addOpTest(inf, "0"); - addOpTest(-inf, "abc"); - addOpTest(-inf, " "); - addOpTest(-inf, ""); - addOpTest(-inf, "0"); - addOpTest(nan, "abc"); - addOpTest(nan, " "); - addOpTest(nan, ""); - addOpTest(nan, "0"); + runOpTest(OpType::CmpEQ, inf, inf); + runOpTest(OpType::CmpEQ, -inf, -inf); + runOpTest(OpType::CmpEQ, nan, nan); + runOpTest(OpType::CmpEQ, inf, -inf); + runOpTest(OpType::CmpEQ, -inf, inf); + runOpTest(OpType::CmpEQ, inf, nan); + runOpTest(OpType::CmpEQ, nan, inf); + runOpTest(OpType::CmpEQ, -inf, nan); + runOpTest(OpType::CmpEQ, nan, -inf); + + runOpTest(OpType::CmpEQ, 5, inf); + runOpTest(OpType::CmpEQ, 5, -inf); + runOpTest(OpType::CmpEQ, 5, nan); + runOpTest(OpType::CmpEQ, 0, nan); + + runOpTest(OpType::CmpEQ, true, "true"); + runOpTest(OpType::CmpEQ, "true", true); + runOpTest(OpType::CmpEQ, false, "false"); + runOpTest(OpType::CmpEQ, "false", false); + runOpTest(OpType::CmpEQ, false, "true"); + runOpTest(OpType::CmpEQ, "true", false); + runOpTest(OpType::CmpEQ, true, "false"); + runOpTest(OpType::CmpEQ, "false", true); + runOpTest(OpType::CmpEQ, true, "TRUE"); + runOpTest(OpType::CmpEQ, "TRUE", true); + runOpTest(OpType::CmpEQ, false, "FALSE"); + runOpTest(OpType::CmpEQ, "FALSE", false); + + runOpTest(OpType::CmpEQ, true, "00001"); + runOpTest(OpType::CmpEQ, "00001", true); + runOpTest(OpType::CmpEQ, true, "00000"); + runOpTest(OpType::CmpEQ, "00000", true); + runOpTest(OpType::CmpEQ, false, "00000"); + runOpTest(OpType::CmpEQ, "00000", false); + + runOpTest(OpType::CmpEQ, "true", 1); + runOpTest(OpType::CmpEQ, 1, "true"); + runOpTest(OpType::CmpEQ, "true", 0); + runOpTest(OpType::CmpEQ, 0, "true"); + runOpTest(OpType::CmpEQ, "false", 0); + runOpTest(OpType::CmpEQ, 0, "false"); + runOpTest(OpType::CmpEQ, "false", 1); + runOpTest(OpType::CmpEQ, 1, "false"); + + runOpTest(OpType::CmpEQ, "true", "TRUE"); + runOpTest(OpType::CmpEQ, "true", "FALSE"); + runOpTest(OpType::CmpEQ, "false", "FALSE"); + runOpTest(OpType::CmpEQ, "false", "TRUE"); + + runOpTest(OpType::CmpEQ, true, inf); + runOpTest(OpType::CmpEQ, true, -inf); + runOpTest(OpType::CmpEQ, true, nan); + runOpTest(OpType::CmpEQ, false, inf); + runOpTest(OpType::CmpEQ, false, -inf); + runOpTest(OpType::CmpEQ, false, nan); + + runOpTest(OpType::CmpEQ, "Infinity", inf); + runOpTest(OpType::CmpEQ, "Infinity", -inf); + runOpTest(OpType::CmpEQ, "Infinity", nan); + runOpTest(OpType::CmpEQ, "infinity", inf); + runOpTest(OpType::CmpEQ, "infinity", -inf); + runOpTest(OpType::CmpEQ, "infinity", nan); + runOpTest(OpType::CmpEQ, "-Infinity", inf); + runOpTest(OpType::CmpEQ, "-Infinity", -inf); + runOpTest(OpType::CmpEQ, "-Infinity", nan); + runOpTest(OpType::CmpEQ, "-infinity", inf); + runOpTest(OpType::CmpEQ, "-infinity", -inf); + runOpTest(OpType::CmpEQ, "-infinity", nan); + runOpTest(OpType::CmpEQ, "NaN", inf); + runOpTest(OpType::CmpEQ, "NaN", -inf); + runOpTest(OpType::CmpEQ, "NaN", nan); + runOpTest(OpType::CmpEQ, "nan", inf); + runOpTest(OpType::CmpEQ, "nan", -inf); + runOpTest(OpType::CmpEQ, "nan", nan); + + runOpTest(OpType::CmpEQ, inf, "abc"); + runOpTest(OpType::CmpEQ, inf, " "); + runOpTest(OpType::CmpEQ, inf, ""); + runOpTest(OpType::CmpEQ, inf, "0"); + runOpTest(OpType::CmpEQ, -inf, "abc"); + runOpTest(OpType::CmpEQ, -inf, " "); + runOpTest(OpType::CmpEQ, -inf, ""); + runOpTest(OpType::CmpEQ, -inf, "0"); + runOpTest(OpType::CmpEQ, nan, "abc"); + runOpTest(OpType::CmpEQ, nan, " "); + runOpTest(OpType::CmpEQ, nan, ""); + runOpTest(OpType::CmpEQ, nan, "0"); } TEST_F(LLVMCodeBuilderTest, GreaterAndLowerThanComparison) { - auto addOpTest = [this](Value v1, Value v2) { - // GT - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createCmpGT(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - callConstFuncForType(v1.type()); - m_builder->addConstValue(v2); - callConstFuncForType(v2.type()); - m_builder->createCmpGT(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = Value(v1 > v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "GT: " << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - - // LT - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createCmpLT(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - callConstFuncForType(v1.type()); - m_builder->addConstValue(v2); - callConstFuncForType(v2.type()); - m_builder->createCmpLT(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - str = Value(v1 < v2).toString() + '\n'; - expected = str + str; - - code = m_builder->finalize(); - ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "LT: " << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(10, 10); - addOpTest(10, 8); - addOpTest(8, 10); - - addOpTest(-4.25, -4.25); - addOpTest(-4.25, 5.312); - addOpTest(5.312, -4.25); - - addOpTest(true, true); - addOpTest(true, false); - addOpTest(false, true); - - addOpTest(1, true); - addOpTest(1, false); - - addOpTest("abC def", "abC def"); - addOpTest("abC def", "abc dEf"); - addOpTest("abC def", "ghi Jkl"); - addOpTest("ghi Jkl", "abC def"); - addOpTest("abC def", "hello world"); - - addOpTest(" ", ""); - addOpTest(" ", "0"); - addOpTest(" ", 0); - addOpTest(0, " "); - addOpTest("", "0"); - addOpTest("", 0); - addOpTest(0, ""); - addOpTest("0", 0); - addOpTest(0, "0"); - - addOpTest(5.25, "5.25"); - addOpTest("5.25", 5.25); - addOpTest(5.25, " 5.25"); - addOpTest(" 5.25", 5.25); - addOpTest(5.25, "5.25 "); - addOpTest("5.25 ", 5.25); - addOpTest(5.25, " 5.25 "); - addOpTest(" 5.25 ", 5.25); - addOpTest(5.25, "5.26"); - addOpTest("5.26", 5.25); - addOpTest("5.25", "5.26"); - addOpTest(5, "5 "); - addOpTest("5 ", 5); - addOpTest(0, "1"); - addOpTest("1", 0); - addOpTest(0, "test"); - addOpTest("test", 0); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - addOpTest(inf, inf); - addOpTest(-inf, -inf); - addOpTest(nan, nan); - addOpTest(inf, -inf); - addOpTest(-inf, inf); - addOpTest(inf, nan); - addOpTest(nan, inf); - addOpTest(-inf, nan); - addOpTest(nan, -inf); - - addOpTest(5, inf); - addOpTest(inf, 5); - addOpTest(5, -inf); - addOpTest(-inf, 5); - addOpTest(5, nan); - addOpTest(nan, 5); - addOpTest(0, nan); - addOpTest(nan, 0); - - addOpTest(true, "true"); - addOpTest("true", true); - addOpTest(false, "false"); - addOpTest("false", false); - addOpTest(false, "true"); - addOpTest("true", false); - addOpTest(true, "false"); - addOpTest("false", true); - addOpTest(true, "TRUE"); - addOpTest("TRUE", true); - addOpTest(false, "FALSE"); - addOpTest("FALSE", false); - - addOpTest(true, "00001"); - addOpTest("00001", true); - addOpTest(true, "00000"); - addOpTest("00000", true); - addOpTest(false, "00000"); - addOpTest("00000", false); - - addOpTest("true", 1); - addOpTest(1, "true"); - addOpTest("true", 0); - addOpTest(0, "true"); - addOpTest("false", 0); - addOpTest(0, "false"); - addOpTest("false", 1); - addOpTest(1, "false"); - - addOpTest("true", "TRUE"); - addOpTest("true", "FALSE"); - addOpTest("false", "FALSE"); - addOpTest("false", "TRUE"); - - addOpTest(true, inf); - addOpTest(inf, true); - addOpTest(true, -inf); - addOpTest(-inf, true); - addOpTest(true, nan); - addOpTest(nan, true); - addOpTest(false, inf); - addOpTest(inf, false); - addOpTest(false, -inf); - addOpTest(-inf, false); - addOpTest(false, nan); - addOpTest(nan, false); - - addOpTest("Infinity", inf); - addOpTest("Infinity", -inf); - addOpTest("Infinity", nan); - addOpTest("infinity", inf); - addOpTest("infinity", -inf); - addOpTest("infinity", nan); - addOpTest("-Infinity", inf); - addOpTest("-Infinity", -inf); - addOpTest("-Infinity", nan); - addOpTest("-infinity", inf); - addOpTest("-infinity", -inf); - addOpTest("-infinity", nan); - addOpTest("NaN", inf); - addOpTest("NaN", -inf); - addOpTest("NaN", nan); - addOpTest("nan", inf); - addOpTest("nan", -inf); - addOpTest("nan", nan); - - addOpTest(inf, "abc"); - addOpTest(inf, " "); - addOpTest(inf, ""); - addOpTest(inf, "0"); - addOpTest(-inf, "abc"); - addOpTest(-inf, " "); - addOpTest(-inf, ""); - addOpTest(-inf, "0"); - addOpTest(nan, "abc"); - addOpTest(nan, " "); - addOpTest(nan, ""); - addOpTest(nan, "0"); + std::vector opTypes = { OpType::CmpGT, OpType::CmpLT }; + + for (OpType type : opTypes) { + runOpTest(type, 10, 10); + runOpTest(type, 10, 8); + runOpTest(type, 8, 10); + + runOpTest(type, -4.25, -4.25); + runOpTest(type, -4.25, 5.312); + runOpTest(type, 5.312, -4.25); + + runOpTest(type, true, true); + runOpTest(type, true, false); + runOpTest(type, false, true); + + runOpTest(type, 1, true); + runOpTest(type, 1, false); + + runOpTest(type, "abC def", "abC def"); + runOpTest(type, "abC def", "abc dEf"); + runOpTest(type, "abC def", "ghi Jkl"); + runOpTest(type, "ghi Jkl", "abC def"); + runOpTest(type, "abC def", "hello world"); + + runOpTest(type, " ", ""); + runOpTest(type, " ", "0"); + runOpTest(type, " ", 0); + runOpTest(type, 0, " "); + runOpTest(type, "", "0"); + runOpTest(type, "", 0); + runOpTest(type, 0, ""); + runOpTest(type, "0", 0); + runOpTest(type, 0, "0"); + + runOpTest(type, 5.25, "5.25"); + runOpTest(type, "5.25", 5.25); + runOpTest(type, 5.25, " 5.25"); + runOpTest(type, " 5.25", 5.25); + runOpTest(type, 5.25, "5.25 "); + runOpTest(type, "5.25 ", 5.25); + runOpTest(type, 5.25, " 5.25 "); + runOpTest(type, " 5.25 ", 5.25); + runOpTest(type, 5.25, "5.26"); + runOpTest(type, "5.26", 5.25); + runOpTest(type, "5.25", "5.26"); + runOpTest(type, 5, "5 "); + runOpTest(type, "5 ", 5); + runOpTest(type, 0, "1"); + runOpTest(type, "1", 0); + runOpTest(type, 0, "test"); + runOpTest(type, "test", 0); + + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + + runOpTest(type, inf, inf); + runOpTest(type, -inf, -inf); + runOpTest(type, nan, nan); + runOpTest(type, inf, -inf); + runOpTest(type, -inf, inf); + runOpTest(type, inf, nan); + runOpTest(type, nan, inf); + runOpTest(type, -inf, nan); + runOpTest(type, nan, -inf); + + runOpTest(type, 5, inf); + runOpTest(type, inf, 5); + runOpTest(type, 5, -inf); + runOpTest(type, -inf, 5); + runOpTest(type, 5, nan); + runOpTest(type, nan, 5); + runOpTest(type, 0, nan); + runOpTest(type, nan, 0); + + runOpTest(type, true, "true"); + runOpTest(type, "true", true); + runOpTest(type, false, "false"); + runOpTest(type, "false", false); + runOpTest(type, false, "true"); + runOpTest(type, "true", false); + runOpTest(type, true, "false"); + runOpTest(type, "false", true); + runOpTest(type, true, "TRUE"); + runOpTest(type, "TRUE", true); + runOpTest(type, false, "FALSE"); + runOpTest(type, "FALSE", false); + + runOpTest(type, true, "00001"); + runOpTest(type, "00001", true); + runOpTest(type, true, "00000"); + runOpTest(type, "00000", true); + runOpTest(type, false, "00000"); + runOpTest(type, "00000", false); + + runOpTest(type, "true", 1); + runOpTest(type, 1, "true"); + runOpTest(type, "true", 0); + runOpTest(type, 0, "true"); + runOpTest(type, "false", 0); + runOpTest(type, 0, "false"); + runOpTest(type, "false", 1); + runOpTest(type, 1, "false"); + + runOpTest(type, "true", "TRUE"); + runOpTest(type, "true", "FALSE"); + runOpTest(type, "false", "FALSE"); + runOpTest(type, "false", "TRUE"); + + runOpTest(type, true, inf); + runOpTest(type, inf, true); + runOpTest(type, true, -inf); + runOpTest(type, -inf, true); + runOpTest(type, true, nan); + runOpTest(type, nan, true); + runOpTest(type, false, inf); + runOpTest(type, inf, false); + runOpTest(type, false, -inf); + runOpTest(type, -inf, false); + runOpTest(type, false, nan); + runOpTest(type, nan, false); + + runOpTest(type, "Infinity", inf); + runOpTest(type, "Infinity", -inf); + runOpTest(type, "Infinity", nan); + runOpTest(type, "infinity", inf); + runOpTest(type, "infinity", -inf); + runOpTest(type, "infinity", nan); + runOpTest(type, "-Infinity", inf); + runOpTest(type, "-Infinity", -inf); + runOpTest(type, "-Infinity", nan); + runOpTest(type, "-infinity", inf); + runOpTest(type, "-infinity", -inf); + runOpTest(type, "-infinity", nan); + runOpTest(type, "NaN", inf); + runOpTest(type, "NaN", -inf); + runOpTest(type, "NaN", nan); + runOpTest(type, "nan", inf); + runOpTest(type, "nan", -inf); + runOpTest(type, "nan", nan); + + runOpTest(type, inf, "abc"); + runOpTest(type, inf, " "); + runOpTest(type, inf, ""); + runOpTest(type, inf, "0"); + runOpTest(type, -inf, "abc"); + runOpTest(type, -inf, " "); + runOpTest(type, -inf, ""); + runOpTest(type, -inf, "0"); + runOpTest(type, nan, "abc"); + runOpTest(type, nan, " "); + runOpTest(type, nan, ""); + runOpTest(type, nan, "0"); + } } TEST_F(LLVMCodeBuilderTest, AndOr) { - auto addOpTest = [this](Value v1, Value v2) { - // And - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createAnd(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - callConstFuncForType(v1.type()); - m_builder->addConstValue(v2); - callConstFuncForType(v2.type()); - m_builder->createAnd(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = Value(v1.toBool() && v2.toBool()).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "AND: " << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - - // Or - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createOr(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - callConstFuncForType(v1.type()); - m_builder->addConstValue(v2); - callConstFuncForType(v2.type()); - m_builder->createOr(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - str = Value(v1.toBool() || v2.toBool()).toString() + '\n'; - expected = str + str; - - code = m_builder->finalize(); - ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "OR: " << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(10, 8); - addOpTest(-4.25, -4.25); - addOpTest(-4.25, 5.312); - - addOpTest(true, true); - addOpTest(true, false); - addOpTest(false, true); - - addOpTest(1, true); - addOpTest(1, false); - - addOpTest("abc", "def"); - addOpTest("true", "true"); - addOpTest("true", "false"); - addOpTest("false", "true"); - addOpTest("false", "false"); - - addOpTest(5.25, "5.25"); - addOpTest("5.25", 5.25); - addOpTest(0, "1"); - addOpTest("1", 0); - addOpTest(0, "test"); - addOpTest("test", 0); - - static const double inf = std::numeric_limits::infinity(); - static const double nan = std::numeric_limits::quiet_NaN(); - - addOpTest(inf, inf); - addOpTest(-inf, -inf); - addOpTest(nan, nan); - addOpTest(inf, -inf); - addOpTest(-inf, inf); - addOpTest(inf, nan); - addOpTest(nan, inf); - addOpTest(-inf, nan); - addOpTest(nan, -inf); - - addOpTest(true, "true"); - addOpTest("true", true); - addOpTest(false, "false"); - addOpTest("false", false); - addOpTest(false, "true"); - addOpTest("true", false); - addOpTest(true, "false"); - addOpTest("false", true); - addOpTest(true, "TRUE"); - addOpTest("TRUE", true); - addOpTest(false, "FALSE"); - addOpTest("FALSE", false); - - addOpTest(true, "00001"); - addOpTest("00001", true); - addOpTest(true, "00000"); - addOpTest("00000", true); - addOpTest(false, "00000"); - addOpTest("00000", false); - - addOpTest("true", 1); - addOpTest(1, "true"); - addOpTest("true", 0); - addOpTest(0, "true"); - addOpTest("false", 0); - addOpTest(0, "false"); - addOpTest("false", 1); - addOpTest(1, "false"); - - addOpTest("true", "TRUE"); - addOpTest("true", "FALSE"); - addOpTest("false", "FALSE"); - addOpTest("false", "TRUE"); - - addOpTest(true, inf); - addOpTest(inf, true); - addOpTest(true, -inf); - addOpTest(-inf, true); - addOpTest(true, nan); - addOpTest(nan, true); - addOpTest(false, inf); - addOpTest(inf, false); - addOpTest(false, -inf); - addOpTest(-inf, false); - addOpTest(false, nan); - addOpTest(nan, false); - - addOpTest("Infinity", inf); - addOpTest("Infinity", -inf); - addOpTest("Infinity", nan); - addOpTest("infinity", inf); - addOpTest("infinity", -inf); - addOpTest("infinity", nan); - addOpTest("-Infinity", inf); - addOpTest("-Infinity", -inf); - addOpTest("-Infinity", nan); - addOpTest("-infinity", inf); - addOpTest("-infinity", -inf); - addOpTest("-infinity", nan); - addOpTest("NaN", inf); - addOpTest("NaN", -inf); - addOpTest("NaN", nan); - addOpTest("nan", inf); - addOpTest("nan", -inf); - addOpTest("nan", nan); + std::vector opTypes = { OpType::And, OpType::Or }; + + for (OpType type : opTypes) { + runOpTest(type, 10, 8); + runOpTest(type, -4.25, -4.25); + runOpTest(type, -4.25, 5.312); + + runOpTest(type, true, true); + runOpTest(type, true, false); + runOpTest(type, false, true); + + runOpTest(type, 1, true); + runOpTest(type, 1, false); + + runOpTest(type, "abc", "def"); + runOpTest(type, "true", "true"); + runOpTest(type, "true", "false"); + runOpTest(type, "false", "true"); + runOpTest(type, "false", "false"); + + runOpTest(type, 5.25, "5.25"); + runOpTest(type, "5.25", 5.25); + runOpTest(type, 0, "1"); + runOpTest(type, "1", 0); + runOpTest(type, 0, "test"); + runOpTest(type, "test", 0); + + static const double inf = std::numeric_limits::infinity(); + static const double nan = std::numeric_limits::quiet_NaN(); + + runOpTest(type, inf, inf); + runOpTest(type, -inf, -inf); + runOpTest(type, nan, nan); + runOpTest(type, inf, -inf); + runOpTest(type, -inf, inf); + runOpTest(type, inf, nan); + runOpTest(type, nan, inf); + runOpTest(type, -inf, nan); + runOpTest(type, nan, -inf); + + runOpTest(type, true, "true"); + runOpTest(type, "true", true); + runOpTest(type, false, "false"); + runOpTest(type, "false", false); + runOpTest(type, false, "true"); + runOpTest(type, "true", false); + runOpTest(type, true, "false"); + runOpTest(type, "false", true); + runOpTest(type, true, "TRUE"); + runOpTest(type, "TRUE", true); + runOpTest(type, false, "FALSE"); + runOpTest(type, "FALSE", false); + + runOpTest(type, true, "00001"); + runOpTest(type, "00001", true); + runOpTest(type, true, "00000"); + runOpTest(type, "00000", true); + runOpTest(type, false, "00000"); + runOpTest(type, "00000", false); + + runOpTest(type, "true", 1); + runOpTest(type, 1, "true"); + runOpTest(type, "true", 0); + runOpTest(type, 0, "true"); + runOpTest(type, "false", 0); + runOpTest(type, 0, "false"); + runOpTest(type, "false", 1); + runOpTest(type, 1, "false"); + + runOpTest(type, "true", "TRUE"); + runOpTest(type, "true", "FALSE"); + runOpTest(type, "false", "FALSE"); + runOpTest(type, "false", "TRUE"); + + runOpTest(type, true, inf); + runOpTest(type, inf, true); + runOpTest(type, true, -inf); + runOpTest(type, -inf, true); + runOpTest(type, true, nan); + runOpTest(type, nan, true); + runOpTest(type, false, inf); + runOpTest(type, inf, false); + runOpTest(type, false, -inf); + runOpTest(type, -inf, false); + runOpTest(type, false, nan); + runOpTest(type, nan, false); + + runOpTest(type, "Infinity", inf); + runOpTest(type, "Infinity", -inf); + runOpTest(type, "Infinity", nan); + runOpTest(type, "infinity", inf); + runOpTest(type, "infinity", -inf); + runOpTest(type, "infinity", nan); + runOpTest(type, "-Infinity", inf); + runOpTest(type, "-Infinity", -inf); + runOpTest(type, "-Infinity", nan); + runOpTest(type, "-infinity", inf); + runOpTest(type, "-infinity", -inf); + runOpTest(type, "-infinity", nan); + runOpTest(type, "NaN", inf); + runOpTest(type, "NaN", -inf); + runOpTest(type, "NaN", nan); + runOpTest(type, "nan", inf); + runOpTest(type, "nan", -inf); + runOpTest(type, "nan", nan); + } } TEST_F(LLVMCodeBuilderTest, Not) { - auto addOpTest = [this](Value v) { - createBuilder(true); - - m_builder->addConstValue(v); - m_builder->createNot(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v); - callConstFuncForType(v.type()); - m_builder->createNot(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + runOpTest(OpType::Not, 10); + runOpTest(OpType::Not, -4.25); + runOpTest(OpType::Not, 5.312); + runOpTest(OpType::Not, 1); + runOpTest(OpType::Not, 0); - std::string str = Value(!v.toBool()).toString() + '\n'; - std::string expected = str + str; + runOpTest(OpType::Not, true); + runOpTest(OpType::Not, false); - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes = v.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "NOT: " << quotes << v.toString() << quotes; - }; - - addOpTest(10); - addOpTest(-4.25); - addOpTest(5.312); - addOpTest(1); - addOpTest(0); - - addOpTest(true); - addOpTest(false); - - addOpTest("abc"); - addOpTest("5.25"); - addOpTest("0"); + runOpTest(OpType::Not, "abc"); + runOpTest(OpType::Not, "5.25"); + runOpTest(OpType::Not, "0"); static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(inf); - addOpTest(-inf); - addOpTest(nan); + runOpTest(OpType::Not, inf); + runOpTest(OpType::Not, -inf); + runOpTest(OpType::Not, nan); - addOpTest("true"); - addOpTest("false"); - addOpTest("TRUE"); - addOpTest("FALSE"); + runOpTest(OpType::Not, "true"); + runOpTest(OpType::Not, "false"); + runOpTest(OpType::Not, "TRUE"); + runOpTest(OpType::Not, "FALSE"); - addOpTest("00001"); - addOpTest("00000"); + runOpTest(OpType::Not, "00001"); + runOpTest(OpType::Not, "00000"); - addOpTest("Infinity"); - addOpTest("infinity"); - addOpTest("-Infinity"); - addOpTest("-infinity"); - addOpTest("NaN"); - addOpTest("nan"); + runOpTest(OpType::Not, "Infinity"); + runOpTest(OpType::Not, "infinity"); + runOpTest(OpType::Not, "-Infinity"); + runOpTest(OpType::Not, "-infinity"); + runOpTest(OpType::Not, "NaN"); + runOpTest(OpType::Not, "nan"); } TEST_F(LLVMCodeBuilderTest, Mod) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, Value v2) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->addConstValue(v2); - m_builder->createMod(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->addConstValue(v2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createMod(); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); - - std::string str = (v1 % v2).toString() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - const std::string quotes2 = v2.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2; - }; - - addOpTest(4, 3); - addOpTest(3, 3); - addOpTest(2, 3); - addOpTest(1, 3); - addOpTest(0, 3); - addOpTest(-1, 3); - addOpTest(-2, 3); - addOpTest(-3, 3); - addOpTest(-4, 3); - addOpTest(4.75, 2); - addOpTest(-4.75, 2); - addOpTest(-4.75, -2); - addOpTest(4.75, -2); - addOpTest(5, 0); - addOpTest(-5, 0); - addOpTest(-2.5, "Infinity"); - addOpTest(-1.2, "-Infinity"); - addOpTest(2.5, "Infinity"); - addOpTest(1.2, "-Infinity"); - addOpTest("Infinity", 2); - addOpTest("-Infinity", 2); - addOpTest("Infinity", -2); - addOpTest("-Infinity", -2); - addOpTest(3, "NaN"); - addOpTest(-3, "NaN"); - addOpTest("NaN", 5); - addOpTest("NaN", -5); + runOpTest(OpType::Mod, 4, 3); + runOpTest(OpType::Mod, 3, 3); + runOpTest(OpType::Mod, 2, 3); + runOpTest(OpType::Mod, 1, 3); + runOpTest(OpType::Mod, 0, 3); + runOpTest(OpType::Mod, -1, 3); + runOpTest(OpType::Mod, -2, 3); + runOpTest(OpType::Mod, -3, 3); + runOpTest(OpType::Mod, -4, 3); + runOpTest(OpType::Mod, 4.75, 2); + runOpTest(OpType::Mod, -4.75, 2); + runOpTest(OpType::Mod, -4.75, -2); + runOpTest(OpType::Mod, 4.75, -2); + runOpTest(OpType::Mod, 5, 0); + runOpTest(OpType::Mod, -5, 0); + runOpTest(OpType::Mod, -2.5, "Infinity"); + runOpTest(OpType::Mod, -1.2, "-Infinity"); + runOpTest(OpType::Mod, 2.5, "Infinity"); + runOpTest(OpType::Mod, 1.2, "-Infinity"); + runOpTest(OpType::Mod, "Infinity", 2); + runOpTest(OpType::Mod, "-Infinity", 2); + runOpTest(OpType::Mod, "Infinity", -2); + runOpTest(OpType::Mod, "-Infinity", -2); + runOpTest(OpType::Mod, 3, "NaN"); + runOpTest(OpType::Mod, -3, "NaN"); + runOpTest(OpType::Mod, "NaN", 5); + runOpTest(OpType::Mod, "NaN", -5); } TEST_F(LLVMCodeBuilderTest, Round) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createRound(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createRound(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(4.0, 4.0); - addOpTest(3.2, 3.0); - addOpTest(3.5, 4.0); - addOpTest(3.6, 4.0); - addOpTest(-2.4, -2.0); - addOpTest(-2.5, -2.0); - addOpTest(-2.6, -3.0); - addOpTest(-0.4, -0.0); - addOpTest(-0.5, -0.0); - addOpTest(-0.51, -1.0); - addOpTest(inf, inf); - addOpTest(-inf, -inf); - addOpTest(nan, 0); + runUnaryNumOpTest(OpType::Round, 4.0, 4.0); + runUnaryNumOpTest(OpType::Round, 3.2, 3.0); + runUnaryNumOpTest(OpType::Round, 3.5, 4.0); + runUnaryNumOpTest(OpType::Round, 3.6, 4.0); + runUnaryNumOpTest(OpType::Round, -2.4, -2.0); + runUnaryNumOpTest(OpType::Round, -2.5, -2.0); + runUnaryNumOpTest(OpType::Round, -2.6, -3.0); + runUnaryNumOpTest(OpType::Round, -0.4, -0.0); + runUnaryNumOpTest(OpType::Round, -0.5, -0.0); + runUnaryNumOpTest(OpType::Round, -0.51, -1.0); + runUnaryNumOpTest(OpType::Round, inf, inf); + runUnaryNumOpTest(OpType::Round, -inf, -inf); + runUnaryNumOpTest(OpType::Round, nan, 0); } TEST_F(LLVMCodeBuilderTest, Abs) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createAbs(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createAbs(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(4.0, 4.0); - addOpTest(3.2, 3.2); - addOpTest(-2.0, 2.0); - addOpTest(-2.5, 2.5); - addOpTest(-2.6, 2.6); - addOpTest(0.0, 0.0); - addOpTest(-0.0, 0.0); - addOpTest(inf, inf); - addOpTest(-inf, inf); - addOpTest(nan, 0); + runUnaryNumOpTest(OpType::Abs, 4.0, 4.0); + runUnaryNumOpTest(OpType::Abs, 3.2, 3.2); + runUnaryNumOpTest(OpType::Abs, -2.0, 2.0); + runUnaryNumOpTest(OpType::Abs, -2.5, 2.5); + runUnaryNumOpTest(OpType::Abs, -2.6, 2.6); + runUnaryNumOpTest(OpType::Abs, 0.0, 0.0); + runUnaryNumOpTest(OpType::Abs, -0.0, 0.0); + runUnaryNumOpTest(OpType::Abs, inf, inf); + runUnaryNumOpTest(OpType::Abs, -inf, inf); + runUnaryNumOpTest(OpType::Abs, nan, 0); } TEST_F(LLVMCodeBuilderTest, Floor) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createFloor(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createFloor(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(4.0, 4.0); - addOpTest(3.2, 3.0); - addOpTest(3.5, 3.0); - addOpTest(3.6, 3.0); - addOpTest(0.0, 0.0); - addOpTest(-0.0, -0.0); - addOpTest(-2.4, -3.0); - addOpTest(-2.5, -3.0); - addOpTest(-2.6, -3.0); - addOpTest(-0.4, -1.0); - addOpTest(-0.5, -1.0); - addOpTest(-0.51, -1.0); - addOpTest(inf, inf); - addOpTest(-inf, -inf); - addOpTest(nan, 0); + runUnaryNumOpTest(OpType::Floor, 4.0, 4.0); + runUnaryNumOpTest(OpType::Floor, 3.2, 3.0); + runUnaryNumOpTest(OpType::Floor, 3.5, 3.0); + runUnaryNumOpTest(OpType::Floor, 3.6, 3.0); + runUnaryNumOpTest(OpType::Floor, 0.0, 0.0); + runUnaryNumOpTest(OpType::Floor, -0.0, -0.0); + runUnaryNumOpTest(OpType::Floor, -2.4, -3.0); + runUnaryNumOpTest(OpType::Floor, -2.5, -3.0); + runUnaryNumOpTest(OpType::Floor, -2.6, -3.0); + runUnaryNumOpTest(OpType::Floor, -0.4, -1.0); + runUnaryNumOpTest(OpType::Floor, -0.5, -1.0); + runUnaryNumOpTest(OpType::Floor, -0.51, -1.0); + runUnaryNumOpTest(OpType::Floor, inf, inf); + runUnaryNumOpTest(OpType::Floor, -inf, -inf); + runUnaryNumOpTest(OpType::Floor, nan, 0); } TEST_F(LLVMCodeBuilderTest, Ceil) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createCeil(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createCeil(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(8.0, 8.0); - addOpTest(3.2, 4.0); - addOpTest(3.5, 4.0); - addOpTest(3.6, 4.0); - addOpTest(0.4, 1.0); - addOpTest(0.0, 0.0); - addOpTest(-0.0, -0.0); - addOpTest(-2.4, -2.0); - addOpTest(-2.5, -2.0); - addOpTest(-2.6, -2.0); - addOpTest(-0.4, -0.0); - addOpTest(-0.5, -0.0); - addOpTest(-0.51, -0.0); - addOpTest(inf, inf); - addOpTest(-inf, -inf); - addOpTest(nan, 0); + runUnaryNumOpTest(OpType::Ceil, 8.0, 8.0); + runUnaryNumOpTest(OpType::Ceil, 3.2, 4.0); + runUnaryNumOpTest(OpType::Ceil, 3.5, 4.0); + runUnaryNumOpTest(OpType::Ceil, 3.6, 4.0); + runUnaryNumOpTest(OpType::Ceil, 0.4, 1.0); + runUnaryNumOpTest(OpType::Ceil, 0.0, 0.0); + runUnaryNumOpTest(OpType::Ceil, -0.0, -0.0); + runUnaryNumOpTest(OpType::Ceil, -2.4, -2.0); + runUnaryNumOpTest(OpType::Ceil, -2.5, -2.0); + runUnaryNumOpTest(OpType::Ceil, -2.6, -2.0); + runUnaryNumOpTest(OpType::Ceil, -0.4, -0.0); + runUnaryNumOpTest(OpType::Ceil, -0.5, -0.0); + runUnaryNumOpTest(OpType::Ceil, -0.51, -0.0); + runUnaryNumOpTest(OpType::Ceil, inf, inf); + runUnaryNumOpTest(OpType::Ceil, -inf, -inf); + runUnaryNumOpTest(OpType::Ceil, nan, 0); } TEST_F(LLVMCodeBuilderTest, Sqrt) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createSqrt(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createSqrt(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(16.0, 4.0); - addOpTest(0.04, 0.2); - addOpTest(0.0, 0.0); - addOpTest(-0.0, 0.0); - addOpTest(-4.0, -nan); // negative NaN shouldn't be a problem - addOpTest(inf, inf); - addOpTest(-inf, -nan); - addOpTest(nan, 0); + runUnaryNumOpTest(OpType::Sqrt, 16.0, 4.0); + runUnaryNumOpTest(OpType::Sqrt, 0.04, 0.2); + runUnaryNumOpTest(OpType::Sqrt, 0.0, 0.0); + runUnaryNumOpTest(OpType::Sqrt, -0.0, 0.0); + runUnaryNumOpTest(OpType::Sqrt, -4.0, -nan); // negative NaN shouldn't be a problem + runUnaryNumOpTest(OpType::Sqrt, inf, inf); + runUnaryNumOpTest(OpType::Sqrt, -inf, -nan); + runUnaryNumOpTest(OpType::Sqrt, nan, 0); } TEST_F(LLVMCodeBuilderTest, Sin) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createSin(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createSin(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(30.0, 0.5); - addOpTest(90.0, 1.0); - addOpTest(2.8e-9, 0.0); - addOpTest(2.9e-9, 1e-10); - addOpTest(570.0, -0.5); - addOpTest(-30.0, -0.5); - addOpTest(-90.0, -1.0); - addOpTest(0.0, 0.0); - addOpTest(-0.0, 0.0); - addOpTest(inf, -nan); // negative NaN shouldn't be a problem - addOpTest(-inf, -nan); - addOpTest(nan, 0); + runUnaryNumOpTest(OpType::Sin, 30.0, 0.5); + runUnaryNumOpTest(OpType::Sin, 90.0, 1.0); + runUnaryNumOpTest(OpType::Sin, 2.8e-9, 0.0); + runUnaryNumOpTest(OpType::Sin, 2.9e-9, 1e-10); + runUnaryNumOpTest(OpType::Sin, 570.0, -0.5); + runUnaryNumOpTest(OpType::Sin, -30.0, -0.5); + runUnaryNumOpTest(OpType::Sin, -90.0, -1.0); + runUnaryNumOpTest(OpType::Sin, 0.0, 0.0); + runUnaryNumOpTest(OpType::Sin, -0.0, 0.0); + runUnaryNumOpTest(OpType::Sin, inf, -nan); // negative NaN shouldn't be a problem + runUnaryNumOpTest(OpType::Sin, -inf, -nan); + runUnaryNumOpTest(OpType::Sin, nan, 0); } TEST_F(LLVMCodeBuilderTest, Cos) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createCos(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createCos(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(60.0, 0.5); - addOpTest(90.0, 0.0); - addOpTest(600.0, -0.5); - addOpTest(89.9999999971352, 1e-10); - addOpTest(89.999999999, 0.0); - addOpTest(-60.0, 0.5); - addOpTest(-90.0, 0.0); - addOpTest(0.0, 1.0); - addOpTest(-0.0, 1.0); - addOpTest(inf, -nan); // negative NaN shouldn't be a problem - addOpTest(-inf, -nan); - addOpTest(nan, 1.0); + runUnaryNumOpTest(OpType::Cos, 60.0, 0.5); + runUnaryNumOpTest(OpType::Cos, 90.0, 0.0); + runUnaryNumOpTest(OpType::Cos, 600.0, -0.5); + runUnaryNumOpTest(OpType::Cos, 89.9999999971352, 1e-10); + runUnaryNumOpTest(OpType::Cos, 89.999999999, 0.0); + runUnaryNumOpTest(OpType::Cos, -60.0, 0.5); + runUnaryNumOpTest(OpType::Cos, -90.0, 0.0); + runUnaryNumOpTest(OpType::Cos, 0.0, 1.0); + runUnaryNumOpTest(OpType::Cos, -0.0, 1.0); + runUnaryNumOpTest(OpType::Cos, inf, -nan); // negative NaN shouldn't be a problem + runUnaryNumOpTest(OpType::Cos, -inf, -nan); + runUnaryNumOpTest(OpType::Cos, nan, 1.0); } TEST_F(LLVMCodeBuilderTest, Tan) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createTan(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createTan(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(45.0, 1.0); - addOpTest(90.0, inf); - addOpTest(270.0, -inf); - addOpTest(450.0, inf); - addOpTest(-90.0, -inf); - addOpTest(-270.0, inf); - addOpTest(-450.0, -inf); - addOpTest(180.0, 0.0); - addOpTest(-180.0, 0.0); - addOpTest(2.87e-9, 1e-10); - addOpTest(2.8647e-9, 0.0); - addOpTest(0.0, 0.0); - addOpTest(-0.0, 0.0); - addOpTest(inf, -nan); // negative NaN shouldn't be a problem - addOpTest(-inf, -nan); - addOpTest(nan, 0.0); + runUnaryNumOpTest(OpType::Tan, 45.0, 1.0); + runUnaryNumOpTest(OpType::Tan, 90.0, inf); + runUnaryNumOpTest(OpType::Tan, 270.0, -inf); + runUnaryNumOpTest(OpType::Tan, 450.0, inf); + runUnaryNumOpTest(OpType::Tan, -90.0, -inf); + runUnaryNumOpTest(OpType::Tan, -270.0, inf); + runUnaryNumOpTest(OpType::Tan, -450.0, -inf); + runUnaryNumOpTest(OpType::Tan, 180.0, 0.0); + runUnaryNumOpTest(OpType::Tan, -180.0, 0.0); + runUnaryNumOpTest(OpType::Tan, 2.87e-9, 1e-10); + runUnaryNumOpTest(OpType::Tan, 2.8647e-9, 0.0); + runUnaryNumOpTest(OpType::Tan, 0.0, 0.0); + runUnaryNumOpTest(OpType::Tan, -0.0, 0.0); + runUnaryNumOpTest(OpType::Tan, inf, -nan); // negative NaN shouldn't be a problem + runUnaryNumOpTest(OpType::Tan, -inf, -nan); + runUnaryNumOpTest(OpType::Tan, nan, 0.0); } TEST_F(LLVMCodeBuilderTest, Asin) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createAsin(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createAsin(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(1.0, 90.0); - addOpTest(0.5, 30.0); - addOpTest(0.0, 0.0); - addOpTest(-0.0, 0.0); - addOpTest(-0.5, -30.0); - addOpTest(-1.0, -90.0); - addOpTest(1.1, nan); - addOpTest(-1.2, nan); - addOpTest(inf, nan); - addOpTest(-inf, nan); - addOpTest(nan, 0.0); + runUnaryNumOpTest(OpType::Asin, 1.0, 90.0); + runUnaryNumOpTest(OpType::Asin, 0.5, 30.0); + runUnaryNumOpTest(OpType::Asin, 0.0, 0.0); + runUnaryNumOpTest(OpType::Asin, -0.0, 0.0); + runUnaryNumOpTest(OpType::Asin, -0.5, -30.0); + runUnaryNumOpTest(OpType::Asin, -1.0, -90.0); + runUnaryNumOpTest(OpType::Asin, 1.1, nan); + runUnaryNumOpTest(OpType::Asin, -1.2, nan); + runUnaryNumOpTest(OpType::Asin, inf, nan); + runUnaryNumOpTest(OpType::Asin, -inf, nan); + runUnaryNumOpTest(OpType::Asin, nan, 0.0); } TEST_F(LLVMCodeBuilderTest, Acos) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createAcos(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createAcos(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(1.0, 0.0); - addOpTest(0.5, 60.0); - addOpTest(0.0, 90.0); - addOpTest(-0.0, 90.0); - addOpTest(-0.5, 120.0); - addOpTest(-1.0, 180.0); - addOpTest(1.1, nan); - addOpTest(-1.2, nan); - addOpTest(inf, nan); - addOpTest(-inf, nan); - addOpTest(nan, 90.0); + runUnaryNumOpTest(OpType::Acos, 1.0, 0.0); + runUnaryNumOpTest(OpType::Acos, 0.5, 60.0); + runUnaryNumOpTest(OpType::Acos, 0.0, 90.0); + runUnaryNumOpTest(OpType::Acos, -0.0, 90.0); + runUnaryNumOpTest(OpType::Acos, -0.5, 120.0); + runUnaryNumOpTest(OpType::Acos, -1.0, 180.0); + runUnaryNumOpTest(OpType::Acos, 1.1, nan); + runUnaryNumOpTest(OpType::Acos, -1.2, nan); + runUnaryNumOpTest(OpType::Acos, inf, nan); + runUnaryNumOpTest(OpType::Acos, -inf, nan); + runUnaryNumOpTest(OpType::Acos, nan, 90.0); } TEST_F(LLVMCodeBuilderTest, Atan) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createAtan(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createAtan(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(1.0, 45.0); - addOpTest(0.0, 0.0); - addOpTest(-0.0, -0.0); - addOpTest(-1.0, -45.0); - addOpTest(inf, 90.0); - addOpTest(-inf, -90.0); - addOpTest(nan, 0.0); + runUnaryNumOpTest(OpType::Atan, 1.0, 45.0); + runUnaryNumOpTest(OpType::Atan, 0.0, 0.0); + runUnaryNumOpTest(OpType::Atan, -0.0, -0.0); + runUnaryNumOpTest(OpType::Atan, -1.0, -45.0); + runUnaryNumOpTest(OpType::Atan, inf, 90.0); + runUnaryNumOpTest(OpType::Atan, -inf, -90.0); + runUnaryNumOpTest(OpType::Atan, nan, 0.0); } TEST_F(LLVMCodeBuilderTest, Ln) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createLn(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createLn(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(std::exp(1.0), 1.0); - addOpTest(std::exp(2.0), 2.0); - addOpTest(std::exp(0.3), 0.3); - addOpTest(1.0, 0.0); - addOpTest(0.0, -inf); - addOpTest(-0.0, -inf); - addOpTest(-0.7, -nan); // negative NaN shouldn't be a problem - addOpTest(inf, inf); - addOpTest(-inf, -nan); - addOpTest(nan, -inf); + runUnaryNumOpTest(OpType::Ln, std::exp(1.0), 1.0); + runUnaryNumOpTest(OpType::Ln, std::exp(2.0), 2.0); + runUnaryNumOpTest(OpType::Ln, std::exp(0.3), 0.3); + runUnaryNumOpTest(OpType::Ln, 1.0, 0.0); + runUnaryNumOpTest(OpType::Ln, 0.0, -inf); + runUnaryNumOpTest(OpType::Ln, -0.0, -inf); + runUnaryNumOpTest(OpType::Ln, -0.7, -nan); // negative NaN shouldn't be a problem + runUnaryNumOpTest(OpType::Ln, inf, inf); + runUnaryNumOpTest(OpType::Ln, -inf, -nan); + runUnaryNumOpTest(OpType::Ln, nan, -inf); } TEST_F(LLVMCodeBuilderTest, Log10) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createLog10(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createLog10(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(10.0, 1.0); - addOpTest(1000.0, 3.0); - addOpTest(0.01, -2.0); - addOpTest(0.0, -inf); - addOpTest(-0.0, -inf); - addOpTest(-0.7, nan); - addOpTest(inf, inf); - addOpTest(-inf, nan); - addOpTest(nan, -inf); + runUnaryNumOpTest(OpType::Log10, 10.0, 1.0); + runUnaryNumOpTest(OpType::Log10, 1000.0, 3.0); + runUnaryNumOpTest(OpType::Log10, 0.01, -2.0); + runUnaryNumOpTest(OpType::Log10, 0.0, -inf); + runUnaryNumOpTest(OpType::Log10, -0.0, -inf); + runUnaryNumOpTest(OpType::Log10, -0.7, nan); + runUnaryNumOpTest(OpType::Log10, inf, inf); + runUnaryNumOpTest(OpType::Log10, -inf, nan); + runUnaryNumOpTest(OpType::Log10, nan, -inf); } TEST_F(LLVMCodeBuilderTest, Exp) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createExp(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createExp(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(1.0, std::exp(1.0)); - addOpTest(0.5, std::exp(0.5)); - addOpTest(0.0, 1.0); - addOpTest(-0.0, 1.0); - addOpTest(-0.7, std::exp(-0.7)); - addOpTest(inf, inf); - addOpTest(-inf, 0.0); - addOpTest(nan, 1.0); + runUnaryNumOpTest(OpType::Exp, 1.0, std::exp(1.0)); + runUnaryNumOpTest(OpType::Exp, 0.5, std::exp(0.5)); + runUnaryNumOpTest(OpType::Exp, 0.0, 1.0); + runUnaryNumOpTest(OpType::Exp, -0.0, 1.0); + runUnaryNumOpTest(OpType::Exp, -0.7, std::exp(-0.7)); + runUnaryNumOpTest(OpType::Exp, inf, inf); + runUnaryNumOpTest(OpType::Exp, -inf, 0.0); + runUnaryNumOpTest(OpType::Exp, nan, 1.0); } TEST_F(LLVMCodeBuilderTest, Exp10) { - std::string expected; - - auto addOpTest = [this, &expected](Value v1, double expectedResult) { - createBuilder(true); - - m_builder->addConstValue(v1); - m_builder->createExp10(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - m_builder->addConstValue(v1); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createExp10(); - m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }); - - std::stringstream stream; - stream << expectedResult; - std::string str = stream.str() + '\n'; - std::string expected = str + str; - - auto code = m_builder->finalize(); - auto ctx = code->createExecutionContext(&m_target); - - testing::internal::CaptureStdout(); - code->run(ctx.get()); - const std::string quotes1 = v1.isString() ? "\"" : ""; - ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1; - }; - static const double inf = std::numeric_limits::infinity(); static const double nan = std::numeric_limits::quiet_NaN(); - addOpTest(1.0, 10.0); - addOpTest(3.0, 1000.0); - addOpTest(0.0, 1.0); - addOpTest(-0.0, 1.0); - addOpTest(-1.0, 0.1); - addOpTest(-5.0, 0.00001); - addOpTest(inf, inf); - addOpTest(-inf, 0.0); - addOpTest(nan, 1.0); + runUnaryNumOpTest(OpType::Exp10, 1.0, 10.0); + runUnaryNumOpTest(OpType::Exp10, 3.0, 1000.0); + runUnaryNumOpTest(OpType::Exp10, 0.0, 1.0); + runUnaryNumOpTest(OpType::Exp10, -0.0, 1.0); + runUnaryNumOpTest(OpType::Exp10, -1.0, 0.1); + runUnaryNumOpTest(OpType::Exp10, -5.0, 0.00001); + runUnaryNumOpTest(OpType::Exp10, inf, inf); + runUnaryNumOpTest(OpType::Exp10, -inf, 0.0); + runUnaryNumOpTest(OpType::Exp10, nan, 1.0); } TEST_F(LLVMCodeBuilderTest, WriteVariable) @@ -1807,29 +1345,29 @@ TEST_F(LLVMCodeBuilderTest, WriteVariable) createBuilder(&sprite, true); - m_builder->addConstValue(5); - m_builder->createVariableWrite(globalVar1.get()); + CompilerValue *v = m_builder->addConstValue(5); + m_builder->createVariableWrite(globalVar1.get(), v); - m_builder->addConstValue(-23.5); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->createVariableWrite(globalVar2.get()); + v = m_builder->addConstValue(-23.5); + v = callConstFuncForType(ValueType::Number, v); + m_builder->createVariableWrite(globalVar2.get(), v); - m_builder->addConstValue("test"); - m_builder->createVariableWrite(globalVar3.get()); + v = m_builder->addConstValue("test"); + m_builder->createVariableWrite(globalVar3.get(), v); - m_builder->addConstValue("abc"); - m_builder->createVariableWrite(localVar1.get()); + v = m_builder->addConstValue("abc"); + m_builder->createVariableWrite(localVar1.get(), v); - m_builder->addConstValue("hello world"); - m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->createVariableWrite(localVar1.get()); + v = m_builder->addConstValue("hello world"); + v = callConstFuncForType(ValueType::String, v); + m_builder->createVariableWrite(localVar1.get(), v); - m_builder->addConstValue(false); - m_builder->createVariableWrite(localVar2.get()); + v = m_builder->addConstValue(false); + m_builder->createVariableWrite(localVar2.get(), v); - m_builder->addConstValue(true); - m_builder->addFunctionCall("test_const_bool", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->createVariableWrite(localVar3.get()); + v = m_builder->addConstValue(true); + v = callConstFuncForType(ValueType::Bool, v); + m_builder->createVariableWrite(localVar3.get(), v); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&sprite); @@ -1867,23 +1405,23 @@ TEST_F(LLVMCodeBuilderTest, ReadVariable) createBuilder(&sprite, true); - m_builder->addVariableValue(globalVar1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addVariableValue(globalVar1.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(globalVar2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar2.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(globalVar3.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar3.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar1.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar2.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar3.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar3.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); std::string expected; expected += globalVar1->value().toString() + '\n'; @@ -2002,11 +1540,11 @@ TEST_F(LLVMCodeBuilderTest, RemoveFromList) createBuilder(&sprite, true); - m_builder->addConstValue(1); - m_builder->createListRemove(globalList.get()); + CompilerValue *v = m_builder->addConstValue(1); + m_builder->createListRemove(globalList.get(), v); - m_builder->addConstValue(3); - m_builder->createListRemove(localList.get()); + v = m_builder->addConstValue(3); + m_builder->createListRemove(localList.get(), v); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&sprite); @@ -2044,25 +1582,25 @@ TEST_F(LLVMCodeBuilderTest, AppendToList) createBuilder(&sprite, true); - m_builder->addConstValue(1); - m_builder->createListAppend(globalList.get()); + CompilerValue *v = m_builder->addConstValue(1); + m_builder->createListAppend(globalList.get(), v); - m_builder->addConstValue("test"); - m_builder->createListAppend(globalList.get()); + v = m_builder->addConstValue("test"); + m_builder->createListAppend(globalList.get(), v); - m_builder->addConstValue(3); - m_builder->createListAppend(localList.get()); + v = m_builder->addConstValue(3); + m_builder->createListAppend(localList.get(), v); m_builder->createListClear(localList.get()); - m_builder->addConstValue(true); - m_builder->createListAppend(localList.get()); + v = m_builder->addConstValue(true); + m_builder->createListAppend(localList.get(), v); - m_builder->addConstValue(false); - m_builder->createListAppend(localList.get()); + v = m_builder->addConstValue(false); + m_builder->createListAppend(localList.get(), v); - m_builder->addConstValue("hello world"); - m_builder->createListAppend(localList.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(localList.get(), v); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&sprite); @@ -2100,31 +1638,31 @@ TEST_F(LLVMCodeBuilderTest, InsertToList) createBuilder(&sprite, true); - m_builder->addConstValue(2); - m_builder->addConstValue(1); - m_builder->createListInsert(globalList.get()); + CompilerValue *v1 = m_builder->addConstValue(2); + CompilerValue *v2 = m_builder->addConstValue(1); + m_builder->createListInsert(globalList.get(), v1, v2); - m_builder->addConstValue(3); - m_builder->addConstValue("test"); - m_builder->createListInsert(globalList.get()); + v1 = m_builder->addConstValue(3); + v2 = m_builder->addConstValue("test"); + m_builder->createListInsert(globalList.get(), v1, v2); - m_builder->addConstValue(0); - m_builder->addConstValue(3); - m_builder->createListInsert(localList.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(3); + m_builder->createListInsert(localList.get(), v1, v2); m_builder->createListClear(localList.get()); - m_builder->addConstValue(0); - m_builder->addConstValue(true); - m_builder->createListInsert(localList.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(true); + m_builder->createListInsert(localList.get(), v1, v2); - m_builder->addConstValue(0); - m_builder->addConstValue(false); - m_builder->createListInsert(localList.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(false); + m_builder->createListInsert(localList.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue("hello world"); - m_builder->createListInsert(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue("hello world"); + m_builder->createListInsert(localList.get(), v1, v2); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&sprite); @@ -2162,25 +1700,25 @@ TEST_F(LLVMCodeBuilderTest, ListReplace) createBuilder(&sprite, true); - m_builder->addConstValue(2); - m_builder->addConstValue(1); - m_builder->createListReplace(globalList.get()); + CompilerValue *v1 = m_builder->addConstValue(2); + CompilerValue *v2 = m_builder->addConstValue(1); + m_builder->createListReplace(globalList.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue("test"); - m_builder->createListReplace(globalList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue("test"); + m_builder->createListReplace(globalList.get(), v1, v2); - m_builder->addConstValue(0); - m_builder->addConstValue(3); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(3); + m_builder->createListReplace(localList.get(), v1, v2); - m_builder->addConstValue(2); - m_builder->addConstValue(true); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(2); + v2 = m_builder->addConstValue(true); + m_builder->createListReplace(localList.get(), v1, v2); - m_builder->addConstValue(3); - m_builder->addConstValue("hello world"); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(3); + v2 = m_builder->addConstValue("hello world"); + m_builder->createListReplace(localList.get(), v1, v2); auto code = m_builder->finalize(); auto ctx = code->createExecutionContext(&sprite); @@ -2218,29 +1756,29 @@ TEST_F(LLVMCodeBuilderTest, GetListItem) createBuilder(&sprite, true); - m_builder->addConstValue(2); - m_builder->addListItem(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addConstValue(2); + v = m_builder->addListItem(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addConstValue("test"); - m_builder->createListReplace(globalList.get()); + CompilerValue *v1 = m_builder->addConstValue(1); + CompilerValue *v2 = m_builder->addConstValue("test"); + m_builder->createListReplace(globalList.get(), v1, v2); - m_builder->addConstValue(0); - m_builder->addListItem(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(0); + v = m_builder->addListItem(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItem(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(0); + v = m_builder->addListItem(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(2); - m_builder->addListItem(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + v = m_builder->addListItem(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(3); - m_builder->addListItem(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(3); + v = m_builder->addListItem(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); static const std::string expected = "3\n" @@ -2284,11 +1822,11 @@ TEST_F(LLVMCodeBuilderTest, GetListSize) createBuilder(&sprite, true); - m_builder->addListSize(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addListSize(globalList.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addListSize(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListSize(localList.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); static const std::string expected = "3\n" @@ -2329,49 +1867,49 @@ TEST_F(LLVMCodeBuilderTest, GetListItemIndex) createBuilder(&sprite, true); - m_builder->addConstValue(2); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addConstValue(2); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(1); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(0); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addConstValue("test"); - m_builder->createListReplace(globalList.get()); + CompilerValue *v1 = m_builder->addConstValue(1); + CompilerValue *v2 = m_builder->addConstValue("test"); + m_builder->createListReplace(globalList.get(), v1, v2); - m_builder->addConstValue(2); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(1); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("test"); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("test"); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("abc"); - m_builder->addListItemIndex(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("abc"); + v = m_builder->addListItemIndex(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("doLor"); - m_builder->addListItemIndex(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("doLor"); + v = m_builder->addListItemIndex(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(true); - m_builder->addListItemIndex(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(true); + v = m_builder->addListItemIndex(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("site"); - m_builder->addListItemIndex(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("site"); + v = m_builder->addListItemIndex(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); static const std::string expected = "1\n" @@ -2420,49 +1958,49 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem) createBuilder(&sprite, true); - m_builder->addConstValue(2); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addConstValue(2); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(1); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(0); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addConstValue("test"); - m_builder->createListReplace(globalList.get()); + CompilerValue *v1 = m_builder->addConstValue(1); + CompilerValue *v2 = m_builder->addConstValue("test"); + m_builder->createListReplace(globalList.get(), v1, v2); - m_builder->addConstValue(2); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(1); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("test"); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("test"); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("abc"); - m_builder->addListContains(globalList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("abc"); + v = m_builder->addListContains(globalList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("doLor"); - m_builder->addListContains(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("doLor"); + v = m_builder->addListContains(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(true); - m_builder->addListContains(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(true); + v = m_builder->addListContains(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue("site"); - m_builder->addListContains(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("site"); + v = m_builder->addListContains(localList.get(), v); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); static const std::string expected = "true\n" @@ -2489,24 +2027,28 @@ TEST_F(LLVMCodeBuilderTest, ListContainsItem) TEST_F(LLVMCodeBuilderTest, Yield) { auto build = [this]() { - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); - m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {}); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->yield(); - m_builder->addConstValue("1"); - m_builder->addFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }); - m_builder->addConstValue("2"); - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }); - - m_builder->addConstValue("test"); - m_builder->addConstValue("4"); - m_builder->addConstValue("5"); - m_builder->addFunctionCall("test_function_3_args_ret", Compiler::StaticType::String, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("1"); + v = m_builder->addFunctionCall("test_function_1_arg_ret", Compiler::StaticType::String, { Compiler::StaticType::String }, { v }); + CompilerValue *v1 = m_builder->addConstValue("2"); + CompilerValue *v2 = m_builder->addConstValue(3); + m_builder->addFunctionCall("test_function_3_args", Compiler::StaticType::Void, { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, { v, v1, v2 }); + + v = m_builder->addConstValue("test"); + v1 = m_builder->addConstValue("4"); + v2 = m_builder->addConstValue("5"); + v = m_builder->addFunctionCall( + "test_function_3_args_ret", + Compiler::StaticType::String, + { Compiler::StaticType::String, Compiler::StaticType::String, Compiler::StaticType::String }, + { v, v1, v2 }); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); }; // Without warp @@ -2576,19 +2118,19 @@ TEST_F(LLVMCodeBuilderTest, VariablesAfterSuspend) createBuilder(&sprite, false); - m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get()); + CompilerValue *v = m_builder->addConstValue(12.5); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(true); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(true); + m_builder->createVariableWrite(localVar.get(), v); m_builder->yield(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); std::string expected = "hello world\n" @@ -2634,67 +2176,44 @@ TEST_F(LLVMCodeBuilderTest, ListsAfterSuspend) m_builder->createListClear(localList1.get()); m_builder->createListClear(localList2.get()); - m_builder->addConstValue(1); - m_builder->createListAppend(globalList1.get()); - m_builder->addConstValue(2); - m_builder->createListAppend(globalList1.get()); - m_builder->addConstValue(3); - m_builder->createListAppend(globalList1.get()); - - m_builder->addConstValue(1); - m_builder->createListAppend(globalList2.get()); - m_builder->addConstValue(2); - m_builder->createListAppend(globalList2.get()); - m_builder->addConstValue(3); - m_builder->createListAppend(globalList2.get()); - - m_builder->addConstValue(1); - m_builder->addConstValue(12.5); - m_builder->createListReplace(globalList2.get()); - - m_builder->addConstValue(0); - m_builder->addConstValue("Lorem"); - m_builder->createListInsert(localList1.get()); - m_builder->addConstValue(0); - m_builder->addConstValue("ipsum"); - m_builder->createListInsert(localList1.get()); - - m_builder->addConstValue(0); - m_builder->addConstValue(true); - m_builder->createListInsert(localList2.get()); - m_builder->addConstValue(0); - m_builder->addConstValue(false); - m_builder->createListInsert(localList2.get()); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1)); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2)); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(3)); + + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue(1)); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue(2)); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue(3)); + + m_builder->createListReplace(globalList2.get(), m_builder->addConstValue(1), m_builder->addConstValue(12.5)); + + m_builder->createListInsert(localList1.get(), m_builder->addConstValue(0), m_builder->addConstValue("Lorem")); + m_builder->createListInsert(localList1.get(), m_builder->addConstValue(0), m_builder->addConstValue("ipsum")); + + m_builder->createListInsert(localList2.get(), m_builder->addConstValue(0), m_builder->addConstValue(true)); + m_builder->createListInsert(localList2.get(), m_builder->addConstValue(0), m_builder->addConstValue(false)); m_builder->yield(); - m_builder->addConstValue(1); - m_builder->addListItem(globalList1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(1)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(2); - m_builder->addListItem(globalList1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(2)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListItem(globalList2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItem(globalList2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItem(localList1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(localList1.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListItem(localList1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(localList1.get(), m_builder->addConstValue(1)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItem(localList2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(localList2.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); std::string expected = "2\n" @@ -2725,96 +2244,96 @@ TEST_F(LLVMCodeBuilderTest, IfStatement) createBuilder(true); // Without else branch (const condition) - m_builder->addConstValue("true"); - m_builder->beginIfStatement(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + CompilerValue *v = m_builder->addConstValue("true"); + m_builder->beginIfStatement(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endIf(); - m_builder->addConstValue("false"); - m_builder->beginIfStatement(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue("false"); + m_builder->beginIfStatement(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endIf(); // Without else branch (condition returned by function) - m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}); - m_builder->addConstValue("no_args_output"); - m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }); - m_builder->beginIfStatement(); - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v1 = m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {}); + CompilerValue *v2 = m_builder->addConstValue("no_args_output"); + v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 }); + m_builder->beginIfStatement(v); + v = m_builder->addConstValue(0); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endIf(); - m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}); - m_builder->addConstValue(""); - m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }); - m_builder->beginIfStatement(); - m_builder->addConstValue(1); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v1 = m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {}); + v2 = m_builder->addConstValue(""); + v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 }); + m_builder->beginIfStatement(v); + v = m_builder->addConstValue(1); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endIf(); // With else branch (const condition) - m_builder->addConstValue("true"); - m_builder->beginIfStatement(); - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("true"); + m_builder->beginIfStatement(v); + v = m_builder->addConstValue(2); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->beginElseBranch(); - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(3); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endIf(); - m_builder->addConstValue("false"); - m_builder->beginIfStatement(); - m_builder->addConstValue(4); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("false"); + m_builder->beginIfStatement(v); + v = m_builder->addConstValue(4); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->beginElseBranch(); - m_builder->addConstValue(5); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(5); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endIf(); // With else branch (condition returned by function) - m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}); - m_builder->addConstValue("no_args_output"); - m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }); - m_builder->beginIfStatement(); - m_builder->addConstValue(6); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v1 = m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {}); + v2 = m_builder->addConstValue("no_args_output"); + v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 }); + m_builder->beginIfStatement(v); + v = m_builder->addConstValue(6); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->beginElseBranch(); - m_builder->addConstValue(7); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(7); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endIf(); - m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}); - m_builder->addConstValue(""); - m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }); - m_builder->beginIfStatement(); - m_builder->addConstValue(8); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v1 = m_builder->addFunctionCall("test_function_no_args_ret", Compiler::StaticType::String, {}, {}); + v2 = m_builder->addConstValue(""); + v = m_builder->addFunctionCall("test_equals", Compiler::StaticType::Bool, { Compiler::StaticType::String, Compiler::StaticType::String }, { v1, v2 }); + m_builder->beginIfStatement(v); + v = m_builder->addConstValue(8); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->beginElseBranch(); - m_builder->addConstValue(9); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(9); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endIf(); // Nested 1 - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(0); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->beginElseBranch(); { - m_builder->addConstValue(1); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(1); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); m_builder->beginElseBranch(); { - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->endIf(); } @@ -2822,45 +2341,45 @@ TEST_F(LLVMCodeBuilderTest, IfStatement) } m_builder->beginElseBranch(); { - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(3); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->beginElseBranch(); { - m_builder->addConstValue(4); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(4); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->endIf(); } m_builder->endIf(); // Nested 2 - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(5); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(5); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->beginElseBranch(); { - m_builder->addConstValue(6); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(6); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->endIf(); } m_builder->beginElseBranch(); { - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(7); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(7); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->beginElseBranch(); m_builder->endIf(); @@ -2907,69 +2426,69 @@ TEST_F(LLVMCodeBuilderTest, IfStatementVariables) createBuilder(&sprite, true); - m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get()); + CompilerValue *v = m_builder->addConstValue(12.5); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(true); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(true); + m_builder->createVariableWrite(localVar.get(), v); - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue("hello world"); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createVariableWrite(globalVar.get(), v); } m_builder->endIf(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue(12.5); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue("hello world"); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(0); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(localVar.get(), v); } m_builder->endIf(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(true); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue(true); + m_builder->createVariableWrite(globalVar.get(), v); } m_builder->endIf(); - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(-8.2); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(-8.2); + m_builder->createVariableWrite(localVar.get(), v); } m_builder->endIf(); } m_builder->endIf(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); std::string expected = "hello world\n" @@ -3009,52 +2528,44 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists) m_builder->createListClear(globalList2.get()); m_builder->createListClear(localList.get()); - m_builder->addConstValue(1); - m_builder->createListAppend(globalList1.get()); - m_builder->addConstValue(2); - m_builder->createListAppend(globalList1.get()); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1)); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2)); - m_builder->addConstValue("hello"); - m_builder->createListAppend(globalList2.get()); - m_builder->addConstValue("world"); - m_builder->createListAppend(globalList2.get()); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello")); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world")); - m_builder->addConstValue(false); - m_builder->createListAppend(localList.get()); - m_builder->addConstValue(true); - m_builder->createListAppend(localList.get()); + m_builder->createListAppend(localList.get(), m_builder->addConstValue(false)); + m_builder->createListAppend(localList.get(), m_builder->addConstValue(true)); }; auto checkLists = [this, globalList1, globalList2, localList]() { - m_builder->addConstValue(0); - m_builder->addListItem(globalList1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListItem(globalList2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItem(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); }; // if (true) resetLists(); - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + CompilerValue *v, *v1, *v2; + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endIf(); @@ -3063,19 +2574,19 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists) // if (false) resetLists(); - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endIf(); @@ -3084,27 +2595,27 @@ TEST_F(LLVMCodeBuilderTest, IfStatementLists) // if (true) { if (true) { ... }; if (false) { ... } } resetLists(); - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(true); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(true); + m_builder->beginIfStatement(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); } m_builder->endIf(); - m_builder->addConstValue(false); - m_builder->beginIfStatement(); + v = m_builder->addConstValue(false); + m_builder->beginIfStatement(v); { - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endIf(); } @@ -3135,60 +2646,60 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop) createBuilder(true); // Const count - m_builder->addConstValue("-5"); - m_builder->beginRepeatLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + CompilerValue *v = m_builder->addConstValue("-5"); + m_builder->beginRepeatLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); - m_builder->addConstValue(0); - m_builder->beginRepeatLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(0); + m_builder->beginRepeatLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); - m_builder->addConstValue(3); - m_builder->beginRepeatLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(3); + m_builder->beginRepeatLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); - m_builder->addConstValue("2.4"); - m_builder->beginRepeatLoop(); - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("2.4"); + m_builder->beginRepeatLoop(v); + v = m_builder->addConstValue(0); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endLoop(); - m_builder->addConstValue("2.5"); - m_builder->beginRepeatLoop(); - m_builder->addConstValue(1); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue("2.5"); + m_builder->beginRepeatLoop(v); + v = m_builder->addConstValue(1); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->endLoop(); // Count returned by function - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }); - m_builder->beginRepeatLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(2); + v = callConstFuncForType(ValueType::Number, v); + m_builder->beginRepeatLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); // Nested - m_builder->addConstValue(2); - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(2); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue(2); - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(2); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue(1); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(1); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->endLoop(); - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(3); - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(3); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(3); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); } m_builder->endLoop(); } @@ -3229,9 +2740,9 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop) // Yield createBuilder(false); - m_builder->addConstValue(3); - m_builder->beginRepeatLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(3); + m_builder->beginRepeatLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); code = m_builder->finalize(); @@ -3256,8 +2767,8 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop) // No warp no-op loop createBuilder(false); - m_builder->addConstValue(0); // don't yield - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(0); // don't yield + m_builder->beginRepeatLoop(v); m_builder->endLoop(); code = m_builder->finalize(); @@ -3272,57 +2783,57 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop) // Const condition m_builder->beginLoopCondition(); - m_builder->addConstValue("false"); - m_builder->beginWhileLoop(); - m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}); + CompilerValue *v = m_builder->addConstValue("false"); + m_builder->beginWhileLoop(v); + m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); m_builder->beginLoopCondition(); - m_builder->addConstValue(false); - m_builder->beginWhileLoop(); - m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(false); + m_builder->beginWhileLoop(v); + m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); // Condition returned by function - m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {}); m_builder->beginLoopCondition(); - m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}); - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }); - m_builder->beginWhileLoop(); - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}); + CompilerValue *v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {}); + CompilerValue *v2 = m_builder->addConstValue(2); + v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 }); + m_builder->beginWhileLoop(v); + v = m_builder->addConstValue(0); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); + m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); // Nested - m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {}); m_builder->beginLoopCondition(); - m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}); - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }); - m_builder->beginWhileLoop(); + v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {}); + v2 = m_builder->addConstValue(3); + v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 }); + m_builder->beginWhileLoop(v); { m_builder->beginLoopCondition(); - m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}); - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }); - m_builder->beginWhileLoop(); + v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {}); + v2 = m_builder->addConstValue(3); + v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 }); + m_builder->beginWhileLoop(v); { - m_builder->addConstValue(1); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(1); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); + m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {}); } m_builder->endLoop(); - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->beginLoopCondition(); - m_builder->addConstValue(false); - m_builder->beginWhileLoop(); + v = m_builder->addConstValue(false); + m_builder->beginWhileLoop(v); { - m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {}); } m_builder->endLoop(); } @@ -3348,9 +2859,9 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop) createBuilder(false); m_builder->beginLoopCondition(); - m_builder->addConstValue(true); - m_builder->beginWhileLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(true); + m_builder->beginWhileLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); code = m_builder->finalize(); @@ -3374,60 +2885,60 @@ TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop) // Const condition m_builder->beginLoopCondition(); - m_builder->addConstValue("true"); - m_builder->beginRepeatUntilLoop(); - m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}); + CompilerValue *v = m_builder->addConstValue("true"); + m_builder->beginRepeatUntilLoop(v); + m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); m_builder->beginLoopCondition(); - m_builder->addConstValue(true); - m_builder->beginRepeatUntilLoop(); - m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(true); + m_builder->beginRepeatUntilLoop(v); + m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); // Condition returned by function - m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {}); m_builder->beginLoopCondition(); - m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}); - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->beginRepeatUntilLoop(); - m_builder->addConstValue(0); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}); + CompilerValue *v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {}); + CompilerValue *v2 = m_builder->addConstValue(2); + v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 }); + v = m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v }); + m_builder->beginRepeatUntilLoop(v); + v = m_builder->addConstValue(0); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); + m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); // Nested - m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_reset_counter", Compiler::StaticType::Void, {}, {}); m_builder->beginLoopCondition(); - m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}); - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->beginRepeatUntilLoop(); + v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {}); + v2 = m_builder->addConstValue(3); + v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 }); + v = m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v }); + m_builder->beginRepeatUntilLoop(v); { m_builder->beginLoopCondition(); - m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}); - m_builder->addConstValue(3); - m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }); - m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }); - m_builder->beginRepeatUntilLoop(); + v1 = m_builder->addFunctionCall("test_get_counter", Compiler::StaticType::Number, {}, {}); + v2 = m_builder->addConstValue(3); + v = m_builder->addFunctionCall("test_lower_than", Compiler::StaticType::Bool, { Compiler::StaticType::Number, Compiler::StaticType::Number }, { v1, v2 }); + v = m_builder->addFunctionCall("test_not", Compiler::StaticType::Bool, { Compiler::StaticType::Bool }, { v }); + m_builder->beginRepeatUntilLoop(v); { - m_builder->addConstValue(1); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); - m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(1); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); + m_builder->addFunctionCall("test_increment_counter", Compiler::StaticType::Void, {}, {}); } m_builder->endLoop(); - m_builder->addConstValue(2); - m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addConstValue(2); + m_builder->addFunctionCall("test_function_1_arg", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); m_builder->beginLoopCondition(); - m_builder->addConstValue(true); - m_builder->beginRepeatUntilLoop(); + v = m_builder->addConstValue(true); + m_builder->beginRepeatUntilLoop(v); { - m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}); + m_builder->addFunctionCall("test_unreachable", Compiler::StaticType::Void, {}, {}); } m_builder->endLoop(); } @@ -3453,9 +2964,9 @@ TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop) createBuilder(false); m_builder->beginLoopCondition(); - m_builder->addConstValue(false); - m_builder->beginRepeatUntilLoop(); - m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}); + v = m_builder->addConstValue(false); + m_builder->beginRepeatUntilLoop(v); + m_builder->addFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {}); m_builder->endLoop(); code = m_builder->finalize(); @@ -3493,101 +3004,101 @@ TEST_F(LLVMCodeBuilderTest, LoopVariables) createBuilder(&sprite, true); - m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get()); + CompilerValue *v = m_builder->addConstValue(12.5); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(true); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(true); + m_builder->createVariableWrite(localVar.get(), v); - m_builder->addConstValue(2); - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(2); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue("hello world"); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createVariableWrite(globalVar.get(), v); } m_builder->endLoop(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(12.5); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue(12.5); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(0); - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(0); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue("hello world"); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addConstValue(0); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(localVar.get(), v); } m_builder->endLoop(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->createVariableWrite(counter1.get()); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(counter1.get(), v); m_builder->beginLoopCondition(); - m_builder->addVariableValue(counter1.get()); - m_builder->addConstValue(5); - m_builder->createCmpLT(); - m_builder->beginWhileLoop(); + CompilerValue *v1 = m_builder->addVariableValue(counter1.get()); + CompilerValue *v2 = m_builder->addConstValue(5); + v = m_builder->createCmpLT(v1, v2); + m_builder->beginWhileLoop(v); { - m_builder->addConstValue(0); - m_builder->createVariableWrite(counter2.get()); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(counter2.get(), v); m_builder->beginLoopCondition(); - m_builder->addVariableValue(counter2.get()); - m_builder->addConstValue(3); - m_builder->createCmpEQ(); - m_builder->beginRepeatUntilLoop(); + v1 = m_builder->addVariableValue(counter2.get()); + v2 = m_builder->addConstValue(3); + v = m_builder->createCmpEQ(v1, v2); + m_builder->beginRepeatUntilLoop(v); { - m_builder->addConstValue(true); - m_builder->createVariableWrite(globalVar.get()); + v = m_builder->addConstValue(true); + m_builder->createVariableWrite(globalVar.get(), v); - m_builder->addVariableValue(counter2.get()); - m_builder->addConstValue(1); - m_builder->createAdd(); - m_builder->createVariableWrite(counter2.get()); + v1 = m_builder->addVariableValue(counter2.get()); + v2 = m_builder->addConstValue(1); + v = m_builder->createAdd(v1, v2); + m_builder->createVariableWrite(counter2.get(), v); } m_builder->endLoop(); m_builder->beginLoopCondition(); - m_builder->addConstValue(false); - m_builder->beginWhileLoop(); + v = m_builder->addConstValue(false); + m_builder->beginWhileLoop(v); { - m_builder->addConstValue(-8.2); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(-8.2); + m_builder->createVariableWrite(localVar.get(), v); } m_builder->endLoop(); - m_builder->addVariableValue(counter1.get()); - m_builder->addConstValue(1); - m_builder->createAdd(); - m_builder->createVariableWrite(counter1.get()); + v1 = m_builder->addVariableValue(counter1.get()); + v2 = m_builder->addConstValue(1); + v = m_builder->createAdd(v1, v2); + m_builder->createVariableWrite(counter1.get(), v); } m_builder->endLoop(); m_builder->beginLoopCondition(); - m_builder->addConstValue(true); - m_builder->beginRepeatUntilLoop(); + v = m_builder->addConstValue(true); + m_builder->beginRepeatUntilLoop(v); { - m_builder->addConstValue(-8.2); - m_builder->createVariableWrite(localVar.get()); + v = m_builder->addConstValue(-8.2); + m_builder->createVariableWrite(localVar.get(), v); } m_builder->endLoop(); - m_builder->addVariableValue(globalVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(globalVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addVariableValue(localVar.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addVariableValue(localVar.get()); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); std::string expected = "hello world\n" @@ -3632,52 +3143,44 @@ TEST_F(LLVMCodeBuilderTest, LoopLists) m_builder->createListClear(globalList2.get()); m_builder->createListClear(localList.get()); - m_builder->addConstValue(1); - m_builder->createListAppend(globalList1.get()); - m_builder->addConstValue(2); - m_builder->createListAppend(globalList1.get()); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(1)); + m_builder->createListAppend(globalList1.get(), m_builder->addConstValue(2)); - m_builder->addConstValue("hello"); - m_builder->createListAppend(globalList2.get()); - m_builder->addConstValue("world"); - m_builder->createListAppend(globalList2.get()); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("hello")); + m_builder->createListAppend(globalList2.get(), m_builder->addConstValue("world")); - m_builder->addConstValue(false); - m_builder->createListAppend(localList.get()); - m_builder->addConstValue(true); - m_builder->createListAppend(localList.get()); + m_builder->createListAppend(localList.get(), m_builder->addConstValue(false)); + m_builder->createListAppend(localList.get(), m_builder->addConstValue(true)); }; auto checkLists = [this, globalList1, globalList2, localList]() { - m_builder->addConstValue(0); - m_builder->addListItem(globalList1.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + CompilerValue *v = m_builder->addListItem(globalList1.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(1); - m_builder->addListItem(globalList2.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(globalList2.get(), m_builder->addConstValue(1)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); - m_builder->addConstValue(0); - m_builder->addListItem(localList.get()); - m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }); + v = m_builder->addListItem(localList.get(), m_builder->addConstValue(0)); + m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v }); }; // repeat (2) resetLists(); - m_builder->addConstValue(2); - m_builder->beginRepeatLoop(); + CompilerValue *v, *v1, *v2; + v = m_builder->addConstValue(2); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endLoop(); @@ -3686,19 +3189,19 @@ TEST_F(LLVMCodeBuilderTest, LoopLists) // repeat(0) resetLists(); - m_builder->addConstValue(0); - m_builder->beginRepeatLoop(); + v = m_builder->addConstValue(0); + m_builder->beginRepeatLoop(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endLoop(); @@ -3707,52 +3210,52 @@ TEST_F(LLVMCodeBuilderTest, LoopLists) // while (counter1 < 5) { ... until (counter2 == 3) {... counter2++ }; while (false) { ... }; counter1++ } resetLists(); - m_builder->addConstValue(0); - m_builder->createVariableWrite(counter1.get()); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(counter1.get(), v); m_builder->beginLoopCondition(); - m_builder->addVariableValue(counter1.get()); - m_builder->addConstValue(5); - m_builder->createCmpLT(); - m_builder->beginWhileLoop(); + v1 = m_builder->addVariableValue(counter1.get()); + v2 = m_builder->addConstValue(5); + v = m_builder->createCmpLT(v1, v2); + m_builder->beginWhileLoop(v); { - m_builder->addConstValue(0); - m_builder->createVariableWrite(counter2.get()); + v = m_builder->addConstValue(0); + m_builder->createVariableWrite(counter2.get(), v); m_builder->beginLoopCondition(); - m_builder->addVariableValue(counter2.get()); - m_builder->addConstValue(3); - m_builder->createCmpEQ(); - m_builder->beginRepeatUntilLoop(); + v1 = m_builder->addVariableValue(counter2.get()); + v2 = m_builder->addConstValue(3); + v = m_builder->createCmpEQ(v1, v2); + m_builder->beginRepeatUntilLoop(v); { - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); - - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); - - m_builder->addVariableValue(counter2.get()); - m_builder->addConstValue(1); - m_builder->createAdd(); - m_builder->createVariableWrite(counter2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); + + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); + + v1 = m_builder->addVariableValue(counter2.get()); + v2 = m_builder->addConstValue(1); + v = m_builder->createAdd(v1, v2); + m_builder->createVariableWrite(counter2.get(), v); } m_builder->endLoop(); m_builder->beginLoopCondition(); - m_builder->addConstValue(false); - m_builder->beginWhileLoop(); + v = m_builder->addConstValue(false); + m_builder->beginWhileLoop(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); } m_builder->endLoop(); - m_builder->addVariableValue(counter1.get()); - m_builder->addConstValue(1); - m_builder->createAdd(); - m_builder->createVariableWrite(counter1.get()); + v1 = m_builder->addVariableValue(counter1.get()); + v2 = m_builder->addConstValue(1); + v = m_builder->createAdd(v1, v2); + m_builder->createVariableWrite(counter1.get(), v); } m_builder->endLoop(); @@ -3762,19 +3265,19 @@ TEST_F(LLVMCodeBuilderTest, LoopLists) resetLists(); m_builder->beginLoopCondition(); - m_builder->addConstValue(true); - m_builder->beginRepeatUntilLoop(); + v = m_builder->addConstValue(true); + m_builder->beginRepeatUntilLoop(v); { - m_builder->addConstValue("hello world"); - m_builder->createListAppend(globalList1.get()); + v = m_builder->addConstValue("hello world"); + m_builder->createListAppend(globalList1.get(), v); - m_builder->addConstValue(0); - m_builder->addConstValue(8.5); - m_builder->createListInsert(globalList2.get()); + v1 = m_builder->addConstValue(0); + v2 = m_builder->addConstValue(8.5); + m_builder->createListInsert(globalList2.get(), v1, v2); - m_builder->addConstValue(1); - m_builder->addConstValue(-4.25); - m_builder->createListReplace(localList.get()); + v1 = m_builder->addConstValue(1); + v2 = m_builder->addConstValue(-4.25); + m_builder->createListReplace(localList.get(), v1, v2); } m_builder->endLoop(); diff --git a/test/mocks/codebuildermock.h b/test/mocks/codebuildermock.h index 4aa0daeb..fff7c33d 100644 --- a/test/mocks/codebuildermock.h +++ b/test/mocks/codebuildermock.h @@ -9,60 +9,60 @@ class CodeBuilderMock : public ICodeBuilder { public: MOCK_METHOD(std::shared_ptr, finalize, (), (override)); - MOCK_METHOD(void, addFunctionCall, (const std::string &, Compiler::StaticType, const std::vector &), (override)); - MOCK_METHOD(void, addConstValue, (const Value &), (override)); - MOCK_METHOD(void, addVariableValue, (Variable *), (override)); - MOCK_METHOD(void, addListContents, (List *), (override)); - MOCK_METHOD(void, addListItem, (List *), (override)); - MOCK_METHOD(void, addListItemIndex, (List *), (override)); - MOCK_METHOD(void, addListContains, (List *), (override)); - MOCK_METHOD(void, addListSize, (List *), (override)); + MOCK_METHOD(CompilerValue *, addFunctionCall, (const std::string &, Compiler::StaticType, const Compiler::ArgTypes &, const Compiler::Args &), (override)); + MOCK_METHOD(CompilerConstant *, addConstValue, (const Value &), (override)); + MOCK_METHOD(CompilerValue *, addVariableValue, (Variable *), (override)); + MOCK_METHOD(CompilerValue *, addListContents, (List *), (override)); + MOCK_METHOD(CompilerValue *, addListItem, (List *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, addListItemIndex, (List *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, addListContains, (List *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, addListSize, (List *), (override)); - MOCK_METHOD(void, createAdd, (), (override)); - MOCK_METHOD(void, createSub, (), (override)); - MOCK_METHOD(void, createMul, (), (override)); - MOCK_METHOD(void, createDiv, (), (override)); + MOCK_METHOD(CompilerValue *, createAdd, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createSub, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createMul, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createDiv, (CompilerValue *, CompilerValue *), (override)); - MOCK_METHOD(void, createCmpEQ, (), (override)); - MOCK_METHOD(void, createCmpGT, (), (override)); - MOCK_METHOD(void, createCmpLT, (), (override)); + MOCK_METHOD(CompilerValue *, createCmpEQ, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createCmpGT, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createCmpLT, (CompilerValue *, CompilerValue *), (override)); - MOCK_METHOD(void, createAnd, (), (override)); - MOCK_METHOD(void, createOr, (), (override)); - MOCK_METHOD(void, createNot, (), (override)); + MOCK_METHOD(CompilerValue *, createAnd, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createOr, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createNot, (CompilerValue *), (override)); - MOCK_METHOD(void, createMod, (), (override)); - MOCK_METHOD(void, createRound, (), (override)); - MOCK_METHOD(void, createAbs, (), (override)); - MOCK_METHOD(void, createFloor, (), (override)); - MOCK_METHOD(void, createCeil, (), (override)); - MOCK_METHOD(void, createSqrt, (), (override)); - MOCK_METHOD(void, createSin, (), (override)); - MOCK_METHOD(void, createCos, (), (override)); - MOCK_METHOD(void, createTan, (), (override)); - MOCK_METHOD(void, createAsin, (), (override)); - MOCK_METHOD(void, createAcos, (), (override)); - MOCK_METHOD(void, createAtan, (), (override)); - MOCK_METHOD(void, createLn, (), (override)); - MOCK_METHOD(void, createLog10, (), (override)); - MOCK_METHOD(void, createExp, (), (override)); - MOCK_METHOD(void, createExp10, (), (override)); + MOCK_METHOD(CompilerValue *, createMod, (CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createRound, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createAbs, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createFloor, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createCeil, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createSqrt, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createSin, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createCos, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createTan, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createAsin, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createAcos, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createAtan, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createLn, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createLog10, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createExp, (CompilerValue *), (override)); + MOCK_METHOD(CompilerValue *, createExp10, (CompilerValue *), (override)); - MOCK_METHOD(void, createVariableWrite, (Variable *), (override)); + MOCK_METHOD(void, createVariableWrite, (Variable *, CompilerValue *), (override)); MOCK_METHOD(void, createListClear, (List *), (override)); - MOCK_METHOD(void, createListRemove, (List *), (override)); - MOCK_METHOD(void, createListAppend, (List *), (override)); - MOCK_METHOD(void, createListInsert, (List *), (override)); - MOCK_METHOD(void, createListReplace, (List *), (override)); + MOCK_METHOD(void, createListRemove, (List *, CompilerValue *), (override)); + MOCK_METHOD(void, createListAppend, (List *, CompilerValue *), (override)); + MOCK_METHOD(void, createListInsert, (List *, CompilerValue *, CompilerValue *), (override)); + MOCK_METHOD(void, createListReplace, (List *, CompilerValue *, CompilerValue *), (override)); - MOCK_METHOD(void, beginIfStatement, (), (override)); + MOCK_METHOD(void, beginIfStatement, (CompilerValue *), (override)); MOCK_METHOD(void, beginElseBranch, (), (override)); MOCK_METHOD(void, endIf, (), (override)); - MOCK_METHOD(void, beginRepeatLoop, (), (override)); - MOCK_METHOD(void, beginWhileLoop, (), (override)); - MOCK_METHOD(void, beginRepeatUntilLoop, (), (override)); + MOCK_METHOD(void, beginRepeatLoop, (CompilerValue *), (override)); + MOCK_METHOD(void, beginWhileLoop, (CompilerValue *), (override)); + MOCK_METHOD(void, beginRepeatUntilLoop, (CompilerValue *), (override)); MOCK_METHOD(void, beginLoopCondition, (), (override)); MOCK_METHOD(void, endLoop, (), (override)); diff --git a/test/scratch_classes/block_test.cpp b/test/scratch_classes/block_test.cpp index 6317287f..ab7358b7 100644 --- a/test/scratch_classes/block_test.cpp +++ b/test/scratch_classes/block_test.cpp @@ -17,7 +17,11 @@ using namespace libscratchcpp; class BlockTestMock { public: +#ifdef USE_LLVM + MOCK_METHOD(CompilerValue *, compileTest, (Compiler *), ()); +#else MOCK_METHOD(void, compileTest, (Compiler *), ()); +#endif }; class BlockTest : public testing::Test @@ -25,11 +29,19 @@ class BlockTest : public testing::Test public: void SetUp() override { m_mockPtr = &m_mock; } +#ifdef USE_LLVM + static CompilerValue *compileTest(Compiler *compiler) + { + EXPECT_TRUE(m_mockPtr); + return m_mockPtr->compileTest(compiler); + } +#else static void compileTest(Compiler *compiler) { ASSERT_TRUE(m_mockPtr); m_mockPtr->compileTest(compiler); } +#endif // USE_LLVM static inline BlockTestMock *m_mockPtr = nullptr; BlockTestMock m_mock;