diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index a64d828699..d38a677722 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -1,6 +1,13 @@ add_library( decomp SHARED + + analysis/atomic_op_builder.cpp + analysis/cfg_builder.cpp + analysis/expression_build.cpp + analysis/reg_usage.cpp + analysis/variable_naming.cpp + data/game_count.cpp data/game_text.cpp data/StrFileReader.cpp @@ -22,17 +29,13 @@ add_library( IR/BasicOpBuilder.cpp IR/IR.cpp - IR2/atomic_op_builder.cpp IR2/AtomicOp.cpp IR2/AtomicOpForm.cpp IR2/AtomicOpTypeAnalysis.cpp - IR2/cfg_builder.cpp IR2/Env.cpp - IR2/expression_build.cpp IR2/Form.cpp + IR2/FormExpressionAnalysis.cpp IR2/FormStack.cpp - IR2/reg_usage.cpp - IR2/variable_naming.cpp ObjectFile/LinkedObjectFile.cpp ObjectFile/LinkedObjectFileCreation.cpp diff --git a/decompiler/Function/BasicBlocks.h b/decompiler/Function/BasicBlocks.h index fd185ccc11..c8ae14c62e 100644 --- a/decompiler/Function/BasicBlocks.h +++ b/decompiler/Function/BasicBlocks.h @@ -7,7 +7,7 @@ #include "decompiler/util/DecompilerTypeSystem.h" #include "decompiler/util/TP_Type.h" // for RegSet: -#include "decompiler/IR2/reg_usage.h" +#include "decompiler/analysis/reg_usage.h" namespace decompiler { class LinkedObjectFile; @@ -29,15 +29,6 @@ struct BasicBlock { int succ_ft = -1; int succ_branch = -1; - std::vector live, dead; - RegSet use, defs; - RegSet input, output; - - bool op_has_reg_live_out(int basic_op_idx, Register reg) { - auto& lv = live.at(basic_op_idx - start_basic_op); - return lv.find(reg) != lv.end(); - } - BasicBlock(int _start_word, int _end_word) : start_word(_start_word), end_word(_end_word) {} }; diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index 1c7f4ffc40..a8e303e99c 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -8,7 +8,7 @@ #include #include #include -#include "decompiler/IR2/atomic_op_builder.h" +#include "decompiler/analysis/atomic_op_builder.h" #include "decompiler/Disasm/Instruction.h" #include "decompiler/Disasm/Register.h" #include "BasicBlocks.h" diff --git a/decompiler/Function/TypeAnalysis.cpp b/decompiler/Function/TypeAnalysis.cpp index d38fdbf0f8..04fc842305 100644 --- a/decompiler/Function/TypeAnalysis.cpp +++ b/decompiler/Function/TypeAnalysis.cpp @@ -104,7 +104,7 @@ bool Function::run_type_analysis_ir2(const TypeSpec& my_type, } catch (std::runtime_error& e) { fmt::print("Type prop fail on {}: {}\n", guessed_name.to_string(), e.what()); warnings += ";; Type prop attempted and failed.\n"; - ir2.env.set_types(block_init_types, op_types); + ir2.env.set_types(block_init_types, op_types, *ir2.atomic_ops); return false; } @@ -137,7 +137,7 @@ bool Function::run_type_analysis_ir2(const TypeSpec& my_type, my_type.last_arg().print()); } - ir2.env.set_types(block_init_types, op_types); + ir2.env.set_types(block_init_types, op_types, *ir2.atomic_ops); return true; } diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 0de72297d1..bb82fee00a 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -18,7 +18,7 @@ ConditionElement* IR2_Condition::get_as_form(FormPool& pool) const { } FormElement* SetVarOp::get_as_form(FormPool& pool) const { - auto source = pool.alloc_single_element_form(nullptr, m_src); + auto source = pool.alloc_single_element_form(nullptr, m_src, m_my_idx); return pool.alloc_element(m_dst, source, is_sequence_point()); } @@ -36,7 +36,7 @@ FormElement* StoreOp::get_as_form(FormPool& pool) const { } FormElement* LoadVarOp::get_as_form(FormPool& pool) const { - auto source = pool.alloc_single_element_form(nullptr, m_src); + auto source = pool.alloc_single_element_form(nullptr, m_src, m_my_idx); auto load = pool.alloc_single_element_form(nullptr, source, m_size, m_kind); return pool.alloc_element(m_dst, load, true); } diff --git a/decompiler/IR2/Env.cpp b/decompiler/IR2/Env.cpp index a76ae31d19..cd965c5baa 100644 --- a/decompiler/IR2/Env.cpp +++ b/decompiler/IR2/Env.cpp @@ -3,6 +3,7 @@ #include #include "Env.h" #include "Form.h" +#include "decompiler/analysis/atomic_op_builder.h" namespace decompiler { std::string Env::get_variable_name(Register reg, int atomic_idx, VariableMode mode) const { @@ -13,9 +14,28 @@ std::string Env::get_variable_name(Register reg, int atomic_idx, VariableMode mo * Update the Env with the result of the type analysis pass. */ void Env::set_types(const std::vector& block_init_types, - const std::vector& op_end_types) { + const std::vector& op_end_types, + const FunctionAtomicOps& atomic_ops) { m_block_init_types = block_init_types; m_op_end_types = op_end_types; + + // cache the init types (this ends up being faster) + m_op_init_types.resize(op_end_types.size(), nullptr); + for (int block_idx = 0; block_idx < int(m_block_init_types.size()); block_idx++) { + int first_op = atomic_ops.block_id_to_first_atomic_op.at(block_idx); + int end_op = atomic_ops.block_id_to_end_atomic_op.at(block_idx); + if (end_op > first_op) { + m_op_init_types.at(first_op) = &m_block_init_types.at(block_idx); + for (int op_idx = first_op; op_idx < (end_op - 1); op_idx++) { + m_op_init_types.at(op_idx + 1) = &m_op_end_types.at(op_idx); + } + } + } + + for (auto x : m_op_init_types) { + assert(x); + } + m_has_types = true; } diff --git a/decompiler/IR2/Env.h b/decompiler/IR2/Env.h index 42117650b3..d2095ec0a9 100644 --- a/decompiler/IR2/Env.h +++ b/decompiler/IR2/Env.h @@ -6,11 +6,12 @@ #include "decompiler/util/TP_Type.h" #include "decompiler/Disasm/Register.h" #include "decompiler/IR2/IR2_common.h" -#include "decompiler/IR2/reg_usage.h" +#include "decompiler/analysis/reg_usage.h" namespace decompiler { class LinkedObjectFile; class Form; +struct FunctionAtomicOps; struct VariableNames { struct VarInfo { @@ -68,6 +69,11 @@ class Env { return m_op_end_types.at(atomic_op_id); } + const TypeState& get_types_before_op(int atomic_op_id) const { + assert(m_has_types); + return *m_op_init_types.at(atomic_op_id); + } + /*! * Get the types in registers at the beginning of this basic block, before any operations * have occurred. @@ -78,7 +84,8 @@ class Env { } void set_types(const std::vector& block_init_types, - const std::vector& op_end_types); + const std::vector& op_end_types, + const FunctionAtomicOps& atomic_ops); void set_local_vars(const VariableNames& names) { m_var_names = names; @@ -102,5 +109,6 @@ class Env { bool m_has_types = false; std::vector m_block_init_types; std::vector m_op_end_types; + std::vector m_op_init_types; }; } // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index 5d16b1048b..1fea898b40 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -28,7 +28,7 @@ std::string FormElement::to_string(const Env& env) const { return to_form(env).print(); } -void FormElement::push_to_stack(const Env& env, FormStack&) { +void FormElement::push_to_stack(const Env& env, FormPool&, FormStack&) { throw std::runtime_error("push_to_stack not implemented for " + to_string(env)); } @@ -83,7 +83,8 @@ void Form::collect_vars(VariableSet& vars) const { // SimpleExpressionElement ///////////////////////////// -SimpleExpressionElement::SimpleExpressionElement(SimpleExpression expr) : m_expr(std::move(expr)) {} +SimpleExpressionElement::SimpleExpressionElement(SimpleExpression expr, int my_idx) + : m_expr(std::move(expr)), m_my_idx(my_idx) {} goos::Object SimpleExpressionElement::to_form(const Env& env) const { return m_expr.to_form(env.file->labels, &env); @@ -761,4 +762,125 @@ void ConditionalMoveFalseElement::collect_vars(VariableSet& vars) const { vars.insert(dest); source->collect_vars(vars); } + +///////////////////////////// +// GenericElement +///////////////////////////// + +GenericOperator GenericOperator::make_fixed(FixedOperatorKind kind) { + GenericOperator op; + op.m_kind = Kind::FIXED_OPERATOR; + op.m_fixed_kind = kind; + return op; +} + +void GenericOperator::collect_vars(VariableSet&) const { + switch (m_kind) { + case Kind::FIXED_OPERATOR: + return; + default: + assert(false); + } +} + +goos::Object GenericOperator::to_form(const Env&) const { + switch (m_kind) { + case Kind::FIXED_OPERATOR: + return pretty_print::to_symbol(fixed_operator_to_string(m_fixed_kind)); + default: + assert(false); + } +} + +void GenericOperator::apply(const std::function&) { + switch (m_kind) { + case Kind::FIXED_OPERATOR: + break; + default: + assert(false); + } +} + +void GenericOperator::apply_form(const std::function&) { + switch (m_kind) { + case Kind::FIXED_OPERATOR: + break; + default: + assert(false); + } +} + +std::string fixed_operator_to_string(FixedOperatorKind kind) { + switch (kind) { + case FixedOperatorKind::GPR_TO_FPR: + return "gpr->fpr"; + case FixedOperatorKind::DIVISION: + return "/"; + case FixedOperatorKind::ADDITION: + return "+"; + default: + assert(false); + } +} + +GenericElement::GenericElement(GenericOperator op) : m_head(op) {} +GenericElement::GenericElement(GenericOperator op, Form* arg) : m_head(op), m_elts({arg}) {} +GenericElement::GenericElement(GenericOperator op, Form* arg0, Form* arg1) + : m_head(op), m_elts({arg0, arg1}) {} +GenericElement::GenericElement(GenericOperator op, std::vector forms) + : m_head(op), m_elts(std::move(forms)) {} + +goos::Object GenericElement::to_form(const Env& env) const { + std::vector result; + result.push_back(m_head.to_form(env)); + for (auto x : m_elts) { + result.push_back(x->to_form(env)); + } + return pretty_print::build_list(result); +} + +void GenericElement::apply(const std::function& f) { + f(this); + m_head.apply(f); + for (auto x : m_elts) { + x->apply(f); + } +} + +void GenericElement::apply_form(const std::function& f) { + m_head.apply_form(f); + for (auto x : m_elts) { + x->apply_form(f); + } +} + +void GenericElement::collect_vars(VariableSet& vars) const { + m_head.collect_vars(vars); + for (auto x : m_elts) { + x->collect_vars(vars); + } +} + +///////////////////////////// +// CastElement +///////////////////////////// + +CastElement::CastElement(TypeSpec type, Form* source) : m_type(std::move(type)), m_source(source) {} + +goos::Object CastElement::to_form(const Env& env) const { + return pretty_print::build_list("the-as", m_type.print(), m_source->to_form(env)); +} + +void CastElement::apply(const std::function& f) { + f(this); + m_source->apply(f); +} + +void CastElement::apply_form(const std::function& f) { + m_source->apply_form(f); +} + +void CastElement::collect_vars(VariableSet& vars) const { + m_source->collect_vars(vars); +} } // namespace decompiler diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 8980d83330..3f6b58a299 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -30,7 +30,11 @@ class FormElement { std::string to_string(const Env& env) const; // push the result of this operation to the operation stack - virtual void push_to_stack(const Env& env, FormStack& stack); + virtual void push_to_stack(const Env& env, FormPool& pool, FormStack& stack); + virtual void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); protected: friend class Form; @@ -42,18 +46,45 @@ class FormElement { */ class SimpleExpressionElement : public FormElement { public: - explicit SimpleExpressionElement(SimpleExpression expr); + explicit SimpleExpressionElement(SimpleExpression expr, int my_idx); goos::Object to_form(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& f) override; bool is_sequence_point() const override; void collect_vars(VariableSet& vars) const override; + // void push_to_stack(const Env& env, FormStack& stack) override; + void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) override; + + void update_from_stack_identity(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); + void update_from_stack_gpr_to_fpr(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); + void update_from_stack_fpr_to_gpr(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); + void update_from_stack_div_s(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); + void update_from_stack_add_i(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); const SimpleExpression& expr() const { return m_expr; } private: SimpleExpression m_expr; + int m_my_idx; }; /*! @@ -90,6 +121,10 @@ class LoadSourceElement : public FormElement { int size() const { return m_size; } LoadVarOp::Kind kind() const { return m_kind; } const Form* location() const { return m_addr; } + virtual void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result); private: Form* m_addr = nullptr; @@ -108,6 +143,7 @@ class SimpleAtomElement : public FormElement { void apply(const std::function& f) override; void apply_form(const std::function& f) override; void collect_vars(VariableSet& vars) const override; + // void push_to_stack(const Env& env, FormStack& stack) override; private: SimpleAtom m_atom; @@ -124,6 +160,7 @@ class SetVarElement : public FormElement { void apply_form(const std::function& f) override; bool is_sequence_point() const override; void collect_vars(VariableSet& vars) const override; + void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; const Variable& dst() const { return m_dst; } const Form* src() const { return m_src; } @@ -464,36 +501,56 @@ class ConditionalMoveFalseElement : public FormElement { void collect_vars(VariableSet& vars) const override; }; -///*! -// * A GenericOperator is the head of a GenericElement. -// * It is used for the final output. -// */ -// class GenericOperator { -// public: -// enum class Kind { -// FIXED_FUNCTION_CALL, -// VAR_FUNCTION_CALL, -// FIXED_OPERATOR -// }; -// -// private: -// // if we're a VAR_FUNCTION_CALL, this should contain the expression to get the function -// Form* m_function_val; -// -// //std::string -// -//}; -// -// class GenericElement : public FormElement { -// public: -// goos::Object to_form(const Env& env) const override; -// void apply(const std::function& f) override; -// void apply_form(const std::function& f) override; -// void collect_vars(VariableSet& vars) const override; -// private: -// GenericOperator m_head; -// std::vector m_elts; -//}; +std::string fixed_operator_to_string(FixedOperatorKind kind); + +/*! + * A GenericOperator is the head of a GenericElement. + * It is used for the final output. + */ +class GenericOperator { + public: + enum class Kind { FIXED_OPERATOR, INVALID }; + + static GenericOperator make_fixed(FixedOperatorKind kind); + void collect_vars(VariableSet& vars) const; + goos::Object to_form(const Env& env) const; + void apply(const std::function& f); + void apply_form(const std::function& f); + + private: + Kind m_kind = Kind::INVALID; + FixedOperatorKind m_fixed_kind = FixedOperatorKind::INVALID; +}; + +class GenericElement : public FormElement { + public: + explicit GenericElement(GenericOperator op); + GenericElement(GenericOperator op, Form* arg); + GenericElement(GenericOperator op, Form* arg0, Form* arg1); + GenericElement(GenericOperator op, std::vector forms); + + goos::Object to_form(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(VariableSet& vars) const override; + + private: + GenericOperator m_head; + std::vector m_elts; +}; + +class CastElement : public FormElement { + public: + explicit CastElement(TypeSpec type, Form* source); + goos::Object to_form(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(VariableSet& vars) const override; + + private: + TypeSpec m_type; + Form* m_source = nullptr; +}; /*! * A Form is a wrapper around one or more FormElements. @@ -559,6 +616,8 @@ class Form { void apply_form(const std::function& f); void collect_vars(VariableSet& vars) const; + void update_children_from_stack(const Env& env, FormPool& pool, FormStack& stack); + FormElement* parent_element = nullptr; private: diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp new file mode 100644 index 0000000000..ec72dc6c80 --- /dev/null +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -0,0 +1,214 @@ +#include "Form.h" +#include "FormStack.h" + +namespace decompiler { + +namespace { + +void update_var_from_stack_helper(int my_idx, + Variable input, + const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + auto& ri = env.reg_use().op.at(my_idx); + if (ri.consumes.find(input.reg()) != ri.consumes.end()) { + // is consumed. + auto stack_val = stack.pop_reg(input); + if (stack_val) { + for (auto x : stack_val->elts()) { + result->push_back(x); + } + return; + } + } + auto elt = + pool.alloc_element(SimpleAtom::make_var(input).as_expr(), my_idx); + result->push_back(elt); +} + +Form* update_var_from_stack_to_form(int my_idx, + Variable input, + const Env& env, + FormPool& pool, + FormStack& stack) { + std::vector elts; + update_var_from_stack_helper(my_idx, input, env, pool, stack, &elts); + return pool.alloc_sequence_form(nullptr, elts); +} + +bool is_float_type(const Env& env, int my_idx, Variable var) { + auto type = env.get_types_before_op(my_idx).get(var.reg()).typespec(); + return type == TypeSpec("float"); +} + +bool is_int_type(const Env& env, int my_idx, Variable var) { + auto type = env.get_types_before_op(my_idx).get(var.reg()).typespec(); + return type == TypeSpec("int"); +} + +bool is_uint_type(const Env& env, int my_idx, Variable var) { + auto type = env.get_types_before_op(my_idx).get(var.reg()).typespec(); + return type == TypeSpec("uint"); +} +} // namespace + +void Form::update_children_from_stack(const Env& env, FormPool& pool, FormStack& stack) { + std::vector new_elts; + for (auto& elt : m_elements) { + elt->update_from_stack(env, pool, stack, &new_elts); + } + m_elements = new_elts; +} + +void FormElement::update_from_stack(const Env& env, + FormPool&, + FormStack&, + std::vector*) { + throw std::runtime_error(fmt::format("update_from_stack NYI for {}", to_string(env))); +} + +void LoadSourceElement::update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + m_addr->update_children_from_stack(env, pool, stack); + result->push_back(this); +} + +void SimpleExpressionElement::update_from_stack_identity(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + auto& arg = m_expr.get_arg(0); + if (arg.is_var()) { + update_var_from_stack_helper(m_my_idx, arg.var(), env, pool, stack, result); + } else if (arg.is_static_addr()) { + // for now, do nothing. + result->push_back(this); + } else { + throw std::runtime_error( + fmt::format("SimpleExpressionElement::update_from_stack NYI for {}", to_string(env))); + } +} + +void SimpleExpressionElement::update_from_stack_gpr_to_fpr(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + auto src = m_expr.get_arg(0); + auto src_type = env.get_types_before_op(m_my_idx).get(src.var().reg()); + if (src_type.typespec() == TypeSpec("float")) { + // set ourself to identity. + m_expr = src.as_expr(); + // then go again. + update_from_stack(env, pool, stack, result); + } else { + throw std::runtime_error(fmt::format("GPR -> FPR applied to a {}", src_type.print())); + } +} + +void SimpleExpressionElement::update_from_stack_fpr_to_gpr(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + auto src = m_expr.get_arg(0); + auto src_type = env.get_types_before_op(m_my_idx).get(src.var().reg()); + if (src_type.typespec() == TypeSpec("float")) { + // set ourself to identity. + m_expr = src.as_expr(); + // then go again. + update_from_stack(env, pool, stack, result); + } else { + throw std::runtime_error(fmt::format("FPR -> GPR applied to a {}", src_type.print())); + } +} + +void SimpleExpressionElement::update_from_stack_div_s(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + if (is_float_type(env, m_my_idx, m_expr.get_arg(0).var()) && + is_float_type(env, m_my_idx, m_expr.get_arg(1).var())) { + // todo - check the order here + auto arg0 = update_var_from_stack_to_form(m_my_idx, m_expr.get_arg(0).var(), env, pool, stack); + auto arg1 = update_var_from_stack_to_form(m_my_idx, m_expr.get_arg(1).var(), env, pool, stack); + auto new_form = pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::DIVISION), arg0, arg1); + result->push_back(new_form); + } else { + throw std::runtime_error(fmt::format("Floating point division attempted on invalid types.")); + } +} + +void SimpleExpressionElement::update_from_stack_add_i(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var()); + auto arg0_u = is_uint_type(env, m_my_idx, m_expr.get_arg(0).var()); + auto arg1_i = is_int_type(env, m_my_idx, m_expr.get_arg(1).var()); + auto arg1_u = is_uint_type(env, m_my_idx, m_expr.get_arg(1).var()); + + auto arg0 = update_var_from_stack_to_form(m_my_idx, m_expr.get_arg(0).var(), env, pool, stack); + auto arg1 = update_var_from_stack_to_form(m_my_idx, m_expr.get_arg(1).var(), env, pool, stack); + + if ((arg0_i && arg1_i) || (arg0_u && arg1_u)) { + auto new_form = pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::ADDITION), arg0, arg1); + result->push_back(new_form); + } else { + auto cast = pool.alloc_single_element_form( + nullptr, TypeSpec(arg0_i ? "int" : "uint"), arg1); + auto new_form = pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::ADDITION), arg0, cast); + result->push_back(new_form); + } +} + +void SimpleExpressionElement::update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result) { + switch (m_expr.kind()) { + case SimpleExpression::Kind::IDENTITY: + update_from_stack_identity(env, pool, stack, result); + break; + case SimpleExpression::Kind::GPR_TO_FPR: + update_from_stack_gpr_to_fpr(env, pool, stack, result); + break; + case SimpleExpression::Kind::FPR_TO_GPR: + update_from_stack_fpr_to_gpr(env, pool, stack, result); + break; + case SimpleExpression::Kind::DIV_S: + update_from_stack_div_s(env, pool, stack, result); + break; + case SimpleExpression::Kind::ADD: + update_from_stack_add_i(env, pool, stack, result); + break; + default: + throw std::runtime_error( + fmt::format("SimpleExpressionElement::update_from_stack NYI for {}", to_string(env))); + } +} + +/////////////////// +// SetVarElement +/////////////////// + +void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + m_src->update_children_from_stack(env, pool, stack); + if (m_src->is_single_element()) { + auto src_as_se = dynamic_cast(m_src->back()); + if (src_as_se) { + if (src_as_se->expr().kind() == SimpleExpression::Kind::IDENTITY && + src_as_se->expr().get_arg(0).is_var()) { + stack.push_value_to_reg(m_dst, m_src, false); + return; + } + } + } + + stack.push_value_to_reg(m_dst, m_src, true); +} +} // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index ecabb02b59..09cc5185fe 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -53,7 +53,7 @@ Form* FormStack::pop_reg(const Variable& var) { for (size_t i = m_stack.size(); i-- > 0;) { auto& entry = m_stack.at(i); if (entry.active) { - if (entry.destination == var) { + if (entry.destination->reg() == var.reg()) { entry.active = false; assert(entry.source); return entry.source; @@ -88,4 +88,24 @@ std::vector FormStack::rewrite(FormPool& pool) { } return result; } + +std::vector FormStack::rewrite_to_get_reg(FormPool& pool, Register reg) { + // first, rewrite as normal. + auto default_result = rewrite(pool); + + // try a few different ways to "naturally" rewrite this so the value of the form is the + // value in the given register. + + auto last_op_as_set = dynamic_cast(default_result.back()); + if (last_op_as_set && last_op_as_set->dst().reg() == reg) { + default_result.pop_back(); + for (auto form : last_op_as_set->src()->elts()) { + form->parent_form = nullptr; // will get set later, this makes it obvious if I forget. + default_result.push_back(form); + } + return default_result; + } else { + throw std::runtime_error(fmt::format("Couldn't rewrite form to get result")); + } +} } // namespace decompiler \ No newline at end of file diff --git a/decompiler/IR2/FormStack.h b/decompiler/IR2/FormStack.h index fa03a2bd1f..8ae699818f 100644 --- a/decompiler/IR2/FormStack.h +++ b/decompiler/IR2/FormStack.h @@ -18,6 +18,7 @@ class FormStack { Form* pop_reg(const Variable& var); bool is_single_expression(); std::vector rewrite(FormPool& pool); + std::vector rewrite_to_get_reg(FormPool& pool, Register reg); std::string print(const Env& env); private: diff --git a/decompiler/IR2/IR2_common.h b/decompiler/IR2/IR2_common.h index 2604676b17..06848459fb 100644 --- a/decompiler/IR2/IR2_common.h +++ b/decompiler/IR2/IR2_common.h @@ -85,4 +85,6 @@ class Variable { }; using VariableSet = std::unordered_set; + +enum class FixedOperatorKind { GPR_TO_FPR, DIVISION, ADDITION, INVALID }; } // namespace decompiler diff --git a/decompiler/IR2/expression_build.cpp b/decompiler/IR2/expression_build.cpp deleted file mode 100644 index 43f1a4c363..0000000000 --- a/decompiler/IR2/expression_build.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "expression_build.h" -#include "decompiler/Function/Function.h" -#include "decompiler/IR2/Form.h" -#include "decompiler/IR2/FormStack.h" - -namespace decompiler { -bool convert_to_expressions(Form* top_level_form, FormPool& pool, const Function& f) { - assert(top_level_form); - - try { - top_level_form->apply_form([&](Form* form) { - FormStack stack; - for (auto& entry : form->elts()) { - entry->push_to_stack(f.ir2.env, stack); - } - auto new_entries = stack.rewrite(pool); - form->clear(); - for (auto x : new_entries) { - form->push_back(x); - } - }); - } catch (std::exception& e) { - return false; - } - return true; -} -} // namespace decompiler diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 07f72ccffa..9dc8c11fa3 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -8,10 +8,10 @@ #include "common/util/Timer.h" #include "common/util/FileUtil.h" #include "decompiler/Function/TypeInspector.h" -#include "decompiler/IR2/reg_usage.h" -#include "decompiler/IR2/variable_naming.h" -#include "decompiler/IR2/cfg_builder.h" -#include "decompiler/IR2/expression_build.h" +#include "decompiler/analysis/reg_usage.h" +#include "decompiler/analysis/variable_naming.h" +#include "decompiler/analysis/cfg_builder.h" +#include "decompiler/analysis/expression_build.h" #include "common/goos/PrettyPrinter.h" namespace decompiler { @@ -270,6 +270,7 @@ void ObjectFileDB::ir2_type_analysis_pass() { non_asm_functions++; TypeSpec ts; if (lookup_function_type(func.guessed_name, data.to_unique_name(), &ts)) { + func.type = ts; attempted_functions++; // try type analysis here. auto hints = get_config().type_hints_by_function_by_idx[func.guessed_name.to_string()]; diff --git a/decompiler/IR2/atomic_op_builder.cpp b/decompiler/analysis/atomic_op_builder.cpp similarity index 100% rename from decompiler/IR2/atomic_op_builder.cpp rename to decompiler/analysis/atomic_op_builder.cpp diff --git a/decompiler/IR2/atomic_op_builder.h b/decompiler/analysis/atomic_op_builder.h similarity index 97% rename from decompiler/IR2/atomic_op_builder.h rename to decompiler/analysis/atomic_op_builder.h index d1cab6927c..7826da1e2e 100644 --- a/decompiler/IR2/atomic_op_builder.h +++ b/decompiler/analysis/atomic_op_builder.h @@ -1,6 +1,6 @@ #pragma once #include -#include "AtomicOp.h" +#include "decompiler/IR2/AtomicOp.h" namespace decompiler { class Function; diff --git a/decompiler/IR2/cfg_builder.cpp b/decompiler/analysis/cfg_builder.cpp similarity index 100% rename from decompiler/IR2/cfg_builder.cpp rename to decompiler/analysis/cfg_builder.cpp diff --git a/decompiler/IR2/cfg_builder.h b/decompiler/analysis/cfg_builder.h similarity index 100% rename from decompiler/IR2/cfg_builder.h rename to decompiler/analysis/cfg_builder.h diff --git a/decompiler/analysis/expression_build.cpp b/decompiler/analysis/expression_build.cpp new file mode 100644 index 0000000000..44978ed8fb --- /dev/null +++ b/decompiler/analysis/expression_build.cpp @@ -0,0 +1,54 @@ +#include "expression_build.h" +#include "decompiler/Function/Function.h" +#include "decompiler/IR2/Form.h" +#include "decompiler/IR2/FormStack.h" + +namespace decompiler { +bool convert_to_expressions(Form* top_level_form, FormPool& pool, const Function& f) { + assert(top_level_form); + + try { + // top_level_form->apply_form([&](Form* form) { + // if (form == top_level_form || !form->is_single_element()) { + // FormStack stack; + // for (auto& entry : form->elts()) { + // fmt::print("push {} to stack\n", entry->to_form(f.ir2.env).print()); + // entry->push_to_stack(f.ir2.env, pool, stack); + // } + // std::vector new_entries; + // if (form == top_level_form && f.type.last_arg() != TypeSpec("none")) { + // new_entries = stack.rewrite_to_get_reg(pool, Register(Reg::GPR, Reg::V0)); + // } else { + // new_entries = stack.rewrite(pool); + // } + // assert(!new_entries.empty()); + // form->clear(); + // for (auto x : new_entries) { + // form->push_back(x); + // } + // } + // }); + + FormStack stack; + for (auto& entry : top_level_form->elts()) { + fmt::print("push {} to stack\n", entry->to_form(f.ir2.env).print()); + entry->push_to_stack(f.ir2.env, pool, stack); + } + std::vector new_entries; + if (f.type.last_arg() != TypeSpec("none")) { + new_entries = stack.rewrite_to_get_reg(pool, Register(Reg::GPR, Reg::V0)); + } else { + new_entries = stack.rewrite(pool); + } + assert(!new_entries.empty()); + top_level_form->clear(); + for (auto x : new_entries) { + top_level_form->push_back(x); + } + } catch (std::exception& e) { + lg::warn("Expression building failed: {}", e.what()); + return false; + } + return true; +} +} // namespace decompiler diff --git a/decompiler/IR2/expression_build.h b/decompiler/analysis/expression_build.h similarity index 100% rename from decompiler/IR2/expression_build.h rename to decompiler/analysis/expression_build.h diff --git a/decompiler/IR2/reg_usage.cpp b/decompiler/analysis/reg_usage.cpp similarity index 100% rename from decompiler/IR2/reg_usage.cpp rename to decompiler/analysis/reg_usage.cpp diff --git a/decompiler/IR2/reg_usage.h b/decompiler/analysis/reg_usage.h similarity index 100% rename from decompiler/IR2/reg_usage.h rename to decompiler/analysis/reg_usage.h diff --git a/decompiler/IR2/variable_naming.cpp b/decompiler/analysis/variable_naming.cpp similarity index 100% rename from decompiler/IR2/variable_naming.cpp rename to decompiler/analysis/variable_naming.cpp diff --git a/decompiler/IR2/variable_naming.h b/decompiler/analysis/variable_naming.h similarity index 100% rename from decompiler/IR2/variable_naming.h rename to decompiler/analysis/variable_naming.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3061db2daf..5a40bbe02c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,8 +18,10 @@ add_executable(goalc-test test_pretty_print.cpp test_zydis.cpp goalc/test_goal_kernel.cpp + decompiler/FormRegressionTest.cpp decompiler/test_AtomicOpBuilder.cpp - decompiler/test_FormRegression.cpp + decompiler/test_FormBeforeExpressions.cpp + decompiler/test_FormExpressionBuild.cpp decompiler/test_InstructionParser.cpp ${GOALC_TEST_FRAMEWORK_SOURCES} ${GOALC_TEST_CASES}) diff --git a/test/decompiler/FormRegressionTest.cpp b/test/decompiler/FormRegressionTest.cpp new file mode 100644 index 0000000000..97df6a2b8d --- /dev/null +++ b/test/decompiler/FormRegressionTest.cpp @@ -0,0 +1,158 @@ +#include "FormRegressionTest.h" + +#include "decompiler/analysis/variable_naming.h" +#include "decompiler/analysis/reg_usage.h" +#include "decompiler/analysis/cfg_builder.h" +#include "decompiler/analysis/expression_build.h" +#include "common/goos/PrettyPrinter.h" + +using namespace decompiler; + +void FormRegressionTest::SetUpTestCase() { + parser = std::make_unique(); + dts = std::make_unique(); + dts->parse_type_defs({"decompiler", "config", "all-types.gc"}); +} + +void FormRegressionTest::TearDownTestCase() { + parser.reset(); + dts.reset(); + parser.reset(); +} + +void FormRegressionTest::TestData::add_string_at_label(const std::string& label_name, + const std::string& data) { + // first, align segment 1: + while (file.words_by_seg.at(1).size() % 4) { + file.words_by_seg.at(1).push_back(LinkedWord(0)); + } + + // add string type tag: + LinkedWord type_tag(0); + type_tag.kind = LinkedWord::Kind::TYPE_PTR; + type_tag.symbol_name = "string"; + file.words_by_seg.at(1).push_back(type_tag); + int string_start = 4 * int(file.words_by_seg.at(1).size()); + + // add size + file.words_by_seg.at(1).push_back(LinkedWord(int(data.length()))); + + // add string: + std::vector bytes; + bytes.resize(((data.size() + 1 + 3) / 4) * 4); + for (size_t i = 0; i < data.size(); i++) { + bytes[i] = data[i]; + } + for (size_t i = 0; i < bytes.size() / 4; i++) { + auto word = ((uint32_t*)bytes.data())[i]; + file.words_by_seg.at(1).push_back(LinkedWord(word)); + } + for (int i = 0; i < 3; i++) { + file.words_by_seg.at(1).push_back(LinkedWord(0)); + } + // will be already null terminated. + + for (auto& label : file.labels) { + if (label.name == label_name) { + label.target_segment = 1; + label.offset = string_start; + return; + } + } + + EXPECT_TRUE(false); +} + +std::unique_ptr FormRegressionTest::make_function( + const std::string& code, + const TypeSpec& function_type, + bool do_expressions, + bool allow_pairs, + const std::string& method_name, + const std::vector>& strings) { + dts->type_prop_settings.locked = true; + dts->type_prop_settings.reset(); + dts->type_prop_settings.allow_pair = allow_pairs; + dts->type_prop_settings.current_method_type = method_name; + auto program = parser->parse_program(code); + // printf("prg:\n%s\n\n", program.print().c_str()); + auto test = std::make_unique(program.instructions.size()); + test->file.words_by_seg.resize(3); + test->file.labels = program.labels; + test->func.ir2.env.file = &test->file; + test->func.instructions = program.instructions; + test->func.guessed_name.set_as_global("test-function"); + test->func.type = function_type; + + for (auto& str : strings) { + test->add_string_at_label(str.first, str.second); + } + + test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func); + test->func.analyze_prologue(test->file); + test->func.cfg = build_cfg(test->file, 0, test->func); + EXPECT_TRUE(test->func.cfg->is_fully_resolved()); + + auto ops = convert_function_to_atomic_ops(test->func, program.labels); + test->func.ir2.atomic_ops = std::make_shared(std::move(ops)); + test->func.ir2.atomic_ops_succeeded = true; + + EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, {})); + + test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func)); + + auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(), + *test->func.ir2.atomic_ops, *dts); + if (result.has_value()) { + test->func.ir2.env.set_local_vars(*result); + } else { + EXPECT_TRUE(false); + } + + build_initial_forms(test->func); + EXPECT_TRUE(test->func.ir2.top_form); + + // for now, just test that this can at least be called. + VariableSet vars; + test->func.ir2.top_form->collect_vars(vars); + + if (do_expressions) { + bool success = + convert_to_expressions(test->func.ir2.top_form, test->func.ir2.form_pool, test->func); + + EXPECT_TRUE(success); + if (!success) { + return nullptr; + } + } + + return test; +} + +void FormRegressionTest::test(const std::string& code, + const std::string& type, + const std::string& expected, + bool do_expressions, + bool allow_pairs, + const std::string& method_name, + const std::vector>& strings) { + auto ts = dts->parse_type_spec(type); + auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings); + ASSERT_TRUE(test); + auto expected_form = + pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car; + auto actual_form = + pretty_print::get_pretty_printer_reader() + .read_from_string(test->func.ir2.top_form->to_form(test->func.ir2.env).print(), false) + .as_pair() + ->car; + if (expected_form != actual_form) { + printf("Got:\n%s\n\nExpected\n%s\n", actual_form.print().c_str(), + expected_form.print().c_str()); + } + + EXPECT_TRUE(expected_form == actual_form); +} + +std::unique_ptr FormRegressionTest::parser; +std::unique_ptr FormRegressionTest::dts; \ No newline at end of file diff --git a/test/decompiler/FormRegressionTest.h b/test/decompiler/FormRegressionTest.h new file mode 100644 index 0000000000..4e229886f0 --- /dev/null +++ b/test/decompiler/FormRegressionTest.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include "gtest/gtest.h" +#include "decompiler/Disasm/InstructionParser.h" +#include "decompiler/util/DecompilerTypeSystem.h" +#include "decompiler/Function/Function.h" +#include "decompiler/ObjectFile/LinkedObjectFile.h" + +class FormRegressionTest : public ::testing::Test { + protected: + static std::unique_ptr parser; + static std::unique_ptr dts; + + static void SetUpTestCase(); + static void TearDownTestCase(); + + struct TestData { + explicit TestData(int instrs) : func(0, instrs) {} + decompiler::Function func; + decompiler::LinkedObjectFile file; + + void add_string_at_label(const std::string& label_name, const std::string& data); + }; + + std::unique_ptr make_function( + const std::string& code, + const TypeSpec& function_type, + bool do_expressions, + bool allow_pairs = false, + const std::string& method_name = "", + const std::vector>& strings = {}); + + void test(const std::string& code, + const std::string& type, + const std::string& expected, + bool do_expressions, + bool allow_pairs = false, + const std::string& method_name = "", + const std::vector>& strings = {}); + + void test_no_expr(const std::string& code, + const std::string& type, + const std::string& expected, + bool allow_pairs = false, + const std::string& method_name = "", + const std::vector>& strings = {}) { + test(code, type, expected, false, allow_pairs, method_name, strings); + } + + void test_with_expr(const std::string& code, + const std::string& type, + const std::string& expected, + bool allow_pairs = false, + const std::string& method_name = "", + const std::vector>& strings = {}) { + test(code, type, expected, true, allow_pairs, method_name, strings); + } +}; \ No newline at end of file diff --git a/test/decompiler/test_AtomicOpBuilder.cpp b/test/decompiler/test_AtomicOpBuilder.cpp index eeb8fb6c84..2ca6b8c6e3 100644 --- a/test/decompiler/test_AtomicOpBuilder.cpp +++ b/test/decompiler/test_AtomicOpBuilder.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include "decompiler/IR2/AtomicOp.h" -#include "decompiler/IR2/atomic_op_builder.h" +#include "decompiler/analysis/atomic_op_builder.h" #include "decompiler/Disasm/InstructionParser.h" #include "third-party/fmt/core.h" #include "third-party/fmt/format.h" diff --git a/test/decompiler/test_FormRegression.cpp b/test/decompiler/test_FormBeforeExpressions.cpp similarity index 76% rename from test/decompiler/test_FormRegression.cpp rename to test/decompiler/test_FormBeforeExpressions.cpp index 7ab30a4c1f..848d305a21 100644 --- a/test/decompiler/test_FormRegression.cpp +++ b/test/decompiler/test_FormBeforeExpressions.cpp @@ -1,162 +1,9 @@ -#include #include "gtest/gtest.h" -#include "decompiler/Disasm/InstructionParser.h" -#include "decompiler/Disasm/DecompilerLabel.h" -#include "decompiler/Function/Function.h" -#include "decompiler/ObjectFile/ObjectFileDB.h" -#include "decompiler/IR2/variable_naming.h" -#include "decompiler/IR2/cfg_builder.h" -#include "common/goos/PrettyPrinter.h" +#include "FormRegressionTest.h" using namespace decompiler; -class DecompilerRegressionTest : public ::testing::Test { - protected: - static std::unique_ptr parser; - static std::unique_ptr dts; - - static void SetUpTestCase() { - parser = std::make_unique(); - dts = std::make_unique(); - dts->parse_type_defs({"decompiler", "config", "all-types.gc"}); - } - - static void TearDownTestCase() { - parser.reset(); - dts.reset(); - parser.reset(); - } - - struct TestData { - explicit TestData(int instrs) : func(0, instrs) {} - Function func; - LinkedObjectFile file; - - void add_string_at_label(const std::string& label_name, const std::string& data) { - // first, align segment 1: - while (file.words_by_seg.at(1).size() % 4) { - file.words_by_seg.at(1).push_back(LinkedWord(0)); - } - - // add string type tag: - LinkedWord type_tag(0); - type_tag.kind = LinkedWord::Kind::TYPE_PTR; - type_tag.symbol_name = "string"; - file.words_by_seg.at(1).push_back(type_tag); - int string_start = 4 * int(file.words_by_seg.at(1).size()); - - // add size - file.words_by_seg.at(1).push_back(LinkedWord(int(data.length()))); - - // add string: - std::vector bytes; - bytes.resize(((data.size() + 1 + 3) / 4) * 4); - for (size_t i = 0; i < data.size(); i++) { - bytes[i] = data[i]; - } - for (size_t i = 0; i < bytes.size() / 4; i++) { - auto word = ((uint32_t*)bytes.data())[i]; - file.words_by_seg.at(1).push_back(LinkedWord(word)); - } - for (int i = 0; i < 3; i++) { - file.words_by_seg.at(1).push_back(LinkedWord(0)); - } - // will be already null terminated. - - for (auto& label : file.labels) { - if (label.name == label_name) { - label.target_segment = 1; - label.offset = string_start; - return; - } - } - - EXPECT_TRUE(false); - } - }; - - std::unique_ptr make_function( - const std::string& code, - const TypeSpec& function_type, - bool allow_pairs = false, - const std::string& method_name = "", - const std::vector>& strings = {}) { - dts->type_prop_settings.locked = true; - dts->type_prop_settings.reset(); - dts->type_prop_settings.allow_pair = allow_pairs; - dts->type_prop_settings.current_method_type = method_name; - auto program = parser->parse_program(code); - // printf("prg:\n%s\n\n", program.print().c_str()); - auto test = std::make_unique(program.instructions.size()); - test->file.words_by_seg.resize(3); - test->file.labels = program.labels; - test->func.ir2.env.file = &test->file; - test->func.instructions = program.instructions; - test->func.guessed_name.set_as_global("test-function"); - - for (auto& str : strings) { - test->add_string_at_label(str.first, str.second); - } - - test->func.basic_blocks = find_blocks_in_function(test->file, 0, test->func); - test->func.analyze_prologue(test->file); - test->func.cfg = build_cfg(test->file, 0, test->func); - EXPECT_TRUE(test->func.cfg->is_fully_resolved()); - - auto ops = convert_function_to_atomic_ops(test->func, program.labels); - test->func.ir2.atomic_ops = std::make_shared(std::move(ops)); - test->func.ir2.atomic_ops_succeeded = true; - - EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, {})); - - test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func)); - - auto result = run_variable_renaming(test->func, test->func.ir2.env.reg_use(), - *test->func.ir2.atomic_ops, *dts); - if (result.has_value()) { - test->func.ir2.env.set_local_vars(*result); - } else { - EXPECT_TRUE(false); - } - - build_initial_forms(test->func); - EXPECT_TRUE(test->func.ir2.top_form); - - // for now, just test that this can at least be called. - VariableSet vars; - test->func.ir2.top_form->collect_vars(vars); - - return test; - } - - void test(const std::string& code, - const std::string& type, - const std::string& expected, - bool allow_pairs = false, - const std::string& method_name = "", - const std::vector>& strings = {}) { - auto ts = dts->parse_type_spec(type); - auto test = make_function(code, ts, allow_pairs, method_name, strings); - auto expected_form = - pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car; - auto actual_form = - pretty_print::get_pretty_printer_reader() - .read_from_string(test->func.ir2.top_form->to_form(test->func.ir2.env).print(), false) - .as_pair() - ->car; - if (expected_form != actual_form) { - printf("Got:\n%s\n\nExpected\n%s\n", actual_form.print().c_str(), - expected_form.print().c_str()); - } - - EXPECT_TRUE(expected_form == actual_form); - } -}; - -std::unique_ptr DecompilerRegressionTest::parser; -std::unique_ptr DecompilerRegressionTest::dts; - -TEST_F(DecompilerRegressionTest, StringTest) { +TEST_F(FormRegressionTest, StringTest) { std::string func = " sll r0, r0, 0\n" "L100:\n" @@ -164,7 +11,7 @@ TEST_F(DecompilerRegressionTest, StringTest) { "L101:\n" " jr ra\n" " daddu sp, sp, r0"; - auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, "", + auto test = make_function(func, TypeSpec("function", {TypeSpec("none")}), false, false, "", {{"L100", "testing-string"}, {"L101", "testing-string-2"}}); EXPECT_EQ(test->file.get_goal_string_by_label(test->file.get_label_by_name("L100")), @@ -173,7 +20,7 @@ TEST_F(DecompilerRegressionTest, StringTest) { "testing-string-2"); } -TEST_F(DecompilerRegressionTest, SimplestTest) { +TEST_F(FormRegressionTest, SimplestTest) { std::string func = " sll r0, r0, 0\n" " or v0, a0, r0\n" @@ -181,10 +28,10 @@ TEST_F(DecompilerRegressionTest, SimplestTest) { " daddu sp, sp, r0"; std::string type = "(function object object)"; std::string expected = "(set! v0-0 a0-0)"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, FloatingPointBasic) { +TEST_F(FormRegressionTest, FloatingPointBasic) { std::string func = " sll r0, r0, 0\n" "L345:\n" @@ -206,10 +53,10 @@ TEST_F(DecompilerRegressionTest, FloatingPointBasic) { " (set! f0-1 (/.s f0-0 f1-0))\n" " (set! v0-0 (fpr->gpr f0-1))\n" " )"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, Op3) { +TEST_F(FormRegressionTest, Op3) { std::string func = " sll r0, r0, 0\n" "L308:\n" @@ -218,10 +65,10 @@ TEST_F(DecompilerRegressionTest, Op3) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(set! v0-0 (*.si a0-0 a1-0))"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, Division) { +TEST_F(FormRegressionTest, Division) { std::string func = " sll r0, r0, 0\n" "L307:\n" @@ -231,10 +78,10 @@ TEST_F(DecompilerRegressionTest, Division) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(set! v0-0 (/.si a0-0 a1-0))"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, Ash) { +TEST_F(FormRegressionTest, Ash) { std::string func = " sll r0, r0, 0\n" "L305:\n" @@ -251,10 +98,10 @@ TEST_F(DecompilerRegressionTest, Ash) { " sll r0, r0, 0"; std::string type = "(function int int int)"; std::string expected = "(begin (set! v1-0 a0-0) (set! v0-0 (ash.si v1-0 a1-0)))"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, Abs) { +TEST_F(FormRegressionTest, Abs) { std::string func = " sll r0, r0, 0\n" "L301:\n" @@ -267,10 +114,10 @@ TEST_F(DecompilerRegressionTest, Abs) { " daddu sp, sp, r0"; std::string type = "(function int int)"; std::string expected = "(begin (set! v0-0 a0-0) (set! v0-1 (abs v0-0)))"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, Min) { +TEST_F(FormRegressionTest, Min) { std::string func = " sll r0, r0, 0\n" " or v0, a0, r0\n" @@ -281,10 +128,10 @@ TEST_F(DecompilerRegressionTest, Min) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(begin (set! v0-0 a0-0) (set! v1-0 a1-0) (set! v0-1 (min.si v0-0 v1-0)))"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, Max) { +TEST_F(FormRegressionTest, Max) { std::string func = " sll r0, r0, 0\n" "L299:\n" @@ -296,10 +143,10 @@ TEST_F(DecompilerRegressionTest, Max) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(begin (set! v0-0 a0-0) (set! v1-0 a1-0) (set! v0-1 (max.si v0-0 v1-0)))"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, FormatString) { +TEST_F(FormRegressionTest, FormatString) { std::string func = " sll r0, r0, 0\n" "L343:\n" @@ -336,10 +183,10 @@ TEST_F(DecompilerRegressionTest, FormatString) { " (set! v0-0 (call! a0-1 a1-0 a2-0))\n" // #t, "~f", the float " (set! v0-1 gp-0)\n" " )"; - test(func, type, expected, false, "", {{"L343", "~f"}}); + test_no_expr(func, type, expected, false, "", {{"L343", "~f"}}); } -TEST_F(DecompilerRegressionTest, WhileLoop) { +TEST_F(FormRegressionTest, WhileLoop) { std::string func = " sll r0, r0, 0\n" "L285:\n" @@ -378,11 +225,11 @@ TEST_F(DecompilerRegressionTest, WhileLoop) { " )\n" " (set! v0-1 '#f)\n" " )"; - test(func, type, expected); + test_no_expr(func, type, expected); } // Note - this test looks weird because or's aren't fully processed at this point. -TEST_F(DecompilerRegressionTest, Or) { +TEST_F(FormRegressionTest, Or) { std::string func = " sll r0, r0, 0\n" "L280:\n" @@ -443,10 +290,10 @@ TEST_F(DecompilerRegressionTest, Or) { " )\n" " (set! v0-1 '#f)\n" " )"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, DynamicMethodAccess) { +TEST_F(FormRegressionTest, DynamicMethodAccess) { std::string func = " sll r0, r0, 0\n" @@ -520,10 +367,10 @@ TEST_F(DecompilerRegressionTest, DynamicMethodAccess) { " )\n" " (set! v1-5 '#f)\n" " )"; - test(func, type, expected); + test_no_expr(func, type, expected); } -TEST_F(DecompilerRegressionTest, SimpleLoopMergeCheck) { +TEST_F(FormRegressionTest, SimpleLoopMergeCheck) { std::string func = " sll r0, r0, 0\n" @@ -563,10 +410,10 @@ TEST_F(DecompilerRegressionTest, SimpleLoopMergeCheck) { " (set! v1-2 '#f)\n" " (set! v0-0 (l.w (+ a0-0 -2)))\n" " )"; - test(func, type, expected, true); + test_no_expr(func, type, expected, true); } -TEST_F(DecompilerRegressionTest, And) { +TEST_F(FormRegressionTest, And) { std::string func = " sll r0, r0, 0\n" @@ -632,10 +479,10 @@ TEST_F(DecompilerRegressionTest, And) { " (set! v1-2 '#f)\n" // while's false, I think. " )\n" " )"; - test(func, type, expected, true); + test_no_expr(func, type, expected, true); } -TEST_F(DecompilerRegressionTest, FunctionCall) { +TEST_F(FormRegressionTest, FunctionCall) { // nmember std::string func = " sll r0, r0, 0\n" @@ -715,10 +562,10 @@ TEST_F(DecompilerRegressionTest, FunctionCall) { " )\n" " (set! v0-2 gp-0)\n" // not empty, so return the result " )"; // the (set! v0 #f) from the if is added later. - test(func, type, expected, true); + test_no_expr(func, type, expected, true); } -TEST_F(DecompilerRegressionTest, NestedAndOr) { +TEST_F(FormRegressionTest, NestedAndOr) { std::string func = " sll r0, r0, 0\n" @@ -886,10 +733,10 @@ TEST_F(DecompilerRegressionTest, NestedAndOr) { " (set! v1-12 '#f)\n" " (set! v0-1 gp-0)\n" " )"; - test(func, type, expected, true); + test_no_expr(func, type, expected, true); } -TEST_F(DecompilerRegressionTest, NewMethod) { +TEST_F(FormRegressionTest, NewMethod) { // inline-array-class new std::string func = " sll r0, r0, 0\n" @@ -941,10 +788,10 @@ TEST_F(DecompilerRegressionTest, NewMethod) { " (s.w! v0-0 gp-0)\n" // store size " (s.w! (+ v0-0 4) gp-0)\n" " )"; - test(func, type, expected, false, "inline-array-class"); + test_no_expr(func, type, expected, false, "inline-array-class"); } -TEST_F(DecompilerRegressionTest, Recursive) { +TEST_F(FormRegressionTest, Recursive) { std::string func = " sll r0, r0, 0\n" @@ -985,10 +832,10 @@ TEST_F(DecompilerRegressionTest, Recursive) { " (set! v0-2 (*.si gp-0 v0-1))\n" // not quite a tail call... " )\n" " )"; - test(func, type, expected, false); + test_no_expr(func, type, expected, false); } -TEST_F(DecompilerRegressionTest, TypeOf) { +TEST_F(FormRegressionTest, TypeOf) { std::string func = " sll r0, r0, 0\n" @@ -1020,5 +867,5 @@ TEST_F(DecompilerRegressionTest, TypeOf) { " (set! t9-0 (l.wu (+ v1-1 24)))\n" // print method. " (set! v0-0 (call! a0-0))\n" " )"; - test(func, type, expected, false); + test_no_expr(func, type, expected, false); } \ No newline at end of file diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp new file mode 100644 index 0000000000..617bc196d1 --- /dev/null +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -0,0 +1,80 @@ +#include "gtest/gtest.h" +#include "FormRegressionTest.h" + +using namespace decompiler; + +TEST_F(FormRegressionTest, ExprIdentity) { + std::string func = + " sll r0, r0, 0\n" + " or v0, a0, r0\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function object object)"; + std::string expected = "a0-0"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, ExprFloatingPoint) { + std::string func = + " sll r0, r0, 0\n" + "L345:\n" + " daddiu sp, sp, -16\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " lwc1 f0, L345(fp)\n" + " mtc1 f1, a0\n" + " div.s f0, f0, f1\n" + " mfc1 v0, f0\n" + " ld fp, 8(sp)\n" + " jr ra\n" + " daddiu sp, sp, 16"; + std::string type = "(function float float)"; + std::string expected = "(/ (l.f L345) a0-0)"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, AdditionSigned) { + std::string func = + " sll r0, r0, 0\n" + " daddu v0, a0, a1\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function int int int)"; + std::string expected = "(+ a0-0 a1-0)"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, AdditionUnSigned) { + std::string func = + " sll r0, r0, 0\n" + " daddu v0, a0, a1\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function uint uint uint)"; + std::string expected = "(+ a0-0 a1-0)"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, AdditionMixed1) { + std::string func = + " sll r0, r0, 0\n" + " daddu v0, a0, a1\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function int uint int)"; + std::string expected = "(+ a0-0 (the-as int a1-0))"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, AdditionMixed2) { + std::string func = + " sll r0, r0, 0\n" + " daddu v0, a0, a1\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function uint int uint)"; + std::string expected = "(+ a0-0 (the-as uint a1-0))"; + test_with_expr(func, type, expected); +} + +// TODO - test the additions, but with the wrong return types. \ No newline at end of file diff --git a/test/goalc/all_goalc_template_tests.cpp b/test/goalc/all_goalc_template_tests.cpp index bcf93470e8..80cab99196 100644 --- a/test/goalc/all_goalc_template_tests.cpp +++ b/test/goalc/all_goalc_template_tests.cpp @@ -2,15 +2,5 @@ #include "test_collections.cpp" #include "test_compiler.cpp" #include "test_control_statements.cpp" -#include "test_float.cpp" -#include "test_functions.cpp" -#include "test_library.cpp" -#include "test_logic.cpp" -#include "test_loop_recur.cpp" -#include "test_macros.cpp" -#include "test_methods.cpp" -#include "test_pointers.cpp" -#include "test_strings.cpp" -#include "test_symbols.cpp" #include "test_variables.cpp" #include "test_with_game.cpp" diff --git a/test/goalc/source_templates/float/float-function.static.gc b/test/goalc/source_templates/arithmetic/float-function.static.gc similarity index 100% rename from test/goalc/source_templates/float/float-function.static.gc rename to test/goalc/source_templates/arithmetic/float-function.static.gc diff --git a/test/goalc/source_templates/float/float-in-symbol.static.gc b/test/goalc/source_templates/arithmetic/float-in-symbol.static.gc similarity index 100% rename from test/goalc/source_templates/float/float-in-symbol.static.gc rename to test/goalc/source_templates/arithmetic/float-in-symbol.static.gc diff --git a/test/goalc/source_templates/float/float-max.static.gc b/test/goalc/source_templates/arithmetic/float-max.static.gc similarity index 100% rename from test/goalc/source_templates/float/float-max.static.gc rename to test/goalc/source_templates/arithmetic/float-max.static.gc diff --git a/test/goalc/source_templates/float/float-min.static.gc b/test/goalc/source_templates/arithmetic/float-min.static.gc similarity index 100% rename from test/goalc/source_templates/float/float-min.static.gc rename to test/goalc/source_templates/arithmetic/float-min.static.gc diff --git a/test/goalc/source_templates/float/float-pow.static.gc b/test/goalc/source_templates/arithmetic/float-pow.static.gc similarity index 100% rename from test/goalc/source_templates/float/float-pow.static.gc rename to test/goalc/source_templates/arithmetic/float-pow.static.gc diff --git a/test/goalc/source_templates/float/float-product.static.gc b/test/goalc/source_templates/arithmetic/float-product.static.gc similarity index 100% rename from test/goalc/source_templates/float/float-product.static.gc rename to test/goalc/source_templates/arithmetic/float-product.static.gc diff --git a/test/goalc/source_templates/float/float.static.gc b/test/goalc/source_templates/arithmetic/float.static.gc similarity index 100% rename from test/goalc/source_templates/float/float.static.gc rename to test/goalc/source_templates/arithmetic/float.static.gc diff --git a/test/goalc/source_templates/float/function-return-float-constant.static.gc b/test/goalc/source_templates/arithmetic/function-return-float-constant.static.gc similarity index 100% rename from test/goalc/source_templates/float/function-return-float-constant.static.gc rename to test/goalc/source_templates/arithmetic/function-return-float-constant.static.gc diff --git a/test/goalc/source_templates/logic/logand.static.gc b/test/goalc/source_templates/arithmetic/logand.static.gc similarity index 100% rename from test/goalc/source_templates/logic/logand.static.gc rename to test/goalc/source_templates/arithmetic/logand.static.gc diff --git a/test/goalc/source_templates/logic/logior.static.gc b/test/goalc/source_templates/arithmetic/logior.static.gc similarity index 100% rename from test/goalc/source_templates/logic/logior.static.gc rename to test/goalc/source_templates/arithmetic/logior.static.gc diff --git a/test/goalc/source_templates/logic/logxor.static.gc b/test/goalc/source_templates/arithmetic/logxor.static.gc similarity index 100% rename from test/goalc/source_templates/logic/logxor.static.gc rename to test/goalc/source_templates/arithmetic/logxor.static.gc diff --git a/test/goalc/source_templates/float/nested-float-functions.static.gc b/test/goalc/source_templates/arithmetic/nested-float-functions.static.gc similarity index 100% rename from test/goalc/source_templates/float/nested-float-functions.static.gc rename to test/goalc/source_templates/arithmetic/nested-float-functions.static.gc diff --git a/test/goalc/source_templates/logic/signed-int-compare.static.gc b/test/goalc/source_templates/arithmetic/signed-int-compare.static.gc similarity index 100% rename from test/goalc/source_templates/logic/signed-int-compare.static.gc rename to test/goalc/source_templates/arithmetic/signed-int-compare.static.gc diff --git a/test/goalc/source_templates/library/align16-1.static.gc b/test/goalc/source_templates/control-statements/align16-1.static.gc similarity index 100% rename from test/goalc/source_templates/library/align16-1.static.gc rename to test/goalc/source_templates/control-statements/align16-1.static.gc diff --git a/test/goalc/source_templates/library/align16-2.static.gc b/test/goalc/source_templates/control-statements/align16-2.static.gc similarity index 100% rename from test/goalc/source_templates/library/align16-2.static.gc rename to test/goalc/source_templates/control-statements/align16-2.static.gc diff --git a/test/goalc/source_templates/functions/declare-inline.static.gc b/test/goalc/source_templates/control-statements/declare-inline.static.gc similarity index 100% rename from test/goalc/source_templates/functions/declare-inline.static.gc rename to test/goalc/source_templates/control-statements/declare-inline.static.gc diff --git a/test/goalc/source_templates/macros/defsmacro-defgmacro.static.gc b/test/goalc/source_templates/control-statements/defsmacro-defgmacro.static.gc similarity index 100% rename from test/goalc/source_templates/macros/defsmacro-defgmacro.static.gc rename to test/goalc/source_templates/control-statements/defsmacro-defgmacro.static.gc diff --git a/test/goalc/source_templates/functions/defun-return-constant.static.gc b/test/goalc/source_templates/control-statements/defun-return-constant.static.gc similarity index 100% rename from test/goalc/source_templates/functions/defun-return-constant.static.gc rename to test/goalc/source_templates/control-statements/defun-return-constant.static.gc diff --git a/test/goalc/source_templates/functions/defun-return-symbol.static.gc b/test/goalc/source_templates/control-statements/defun-return-symbol.static.gc similarity index 100% rename from test/goalc/source_templates/functions/defun-return-symbol.static.gc rename to test/goalc/source_templates/control-statements/defun-return-symbol.static.gc diff --git a/test/goalc/source_templates/macros/desfun.static.gc b/test/goalc/source_templates/control-statements/desfun.static.gc similarity index 100% rename from test/goalc/source_templates/macros/desfun.static.gc rename to test/goalc/source_templates/control-statements/desfun.static.gc diff --git a/test/goalc/source_templates/loop_recur/dotimes.static.gc b/test/goalc/source_templates/control-statements/dotimes.static.gc similarity index 100% rename from test/goalc/source_templates/loop_recur/dotimes.static.gc rename to test/goalc/source_templates/control-statements/dotimes.static.gc diff --git a/test/goalc/source_templates/loop_recur/factorial-iterative.static.gc b/test/goalc/source_templates/control-statements/factorial-iterative.static.gc similarity index 100% rename from test/goalc/source_templates/loop_recur/factorial-iterative.static.gc rename to test/goalc/source_templates/control-statements/factorial-iterative.static.gc diff --git a/test/goalc/source_templates/loop_recur/factorial-recursive.static.gc b/test/goalc/source_templates/control-statements/factorial-recursive.static.gc similarity index 100% rename from test/goalc/source_templates/loop_recur/factorial-recursive.static.gc rename to test/goalc/source_templates/control-statements/factorial-recursive.static.gc diff --git a/test/goalc/source_templates/functions/function-returning-none.static.gc b/test/goalc/source_templates/control-statements/function-returning-none.static.gc similarity index 100% rename from test/goalc/source_templates/functions/function-returning-none.static.gc rename to test/goalc/source_templates/control-statements/function-returning-none.static.gc diff --git a/test/goalc/source_templates/functions/inline-call.static.gc b/test/goalc/source_templates/control-statements/inline-call.static.gc similarity index 100% rename from test/goalc/source_templates/functions/inline-call.static.gc rename to test/goalc/source_templates/control-statements/inline-call.static.gc diff --git a/test/goalc/source_templates/functions/inline-with-block-1.static.gc b/test/goalc/source_templates/control-statements/inline-with-block-1.static.gc similarity index 100% rename from test/goalc/source_templates/functions/inline-with-block-1.static.gc rename to test/goalc/source_templates/control-statements/inline-with-block-1.static.gc diff --git a/test/goalc/source_templates/functions/inline-with-block-2.static.gc b/test/goalc/source_templates/control-statements/inline-with-block-2.static.gc similarity index 100% rename from test/goalc/source_templates/functions/inline-with-block-2.static.gc rename to test/goalc/source_templates/control-statements/inline-with-block-2.static.gc diff --git a/test/goalc/source_templates/functions/inline-with-block-3.static.gc b/test/goalc/source_templates/control-statements/inline-with-block-3.static.gc similarity index 100% rename from test/goalc/source_templates/functions/inline-with-block-3.static.gc rename to test/goalc/source_templates/control-statements/inline-with-block-3.static.gc diff --git a/test/goalc/source_templates/functions/inline-with-block-4.static.gc b/test/goalc/source_templates/control-statements/inline-with-block-4.static.gc similarity index 100% rename from test/goalc/source_templates/functions/inline-with-block-4.static.gc rename to test/goalc/source_templates/control-statements/inline-with-block-4.static.gc diff --git a/test/goalc/source_templates/functions/lambda-1.static.gc b/test/goalc/source_templates/control-statements/lambda-1.static.gc similarity index 100% rename from test/goalc/source_templates/functions/lambda-1.static.gc rename to test/goalc/source_templates/control-statements/lambda-1.static.gc diff --git a/test/goalc/source_templates/methods/methods.static.gc b/test/goalc/source_templates/control-statements/methods.static.gc similarity index 100% rename from test/goalc/source_templates/methods/methods.static.gc rename to test/goalc/source_templates/control-statements/methods.static.gc diff --git a/test/goalc/source_templates/functions/nested-call.static.gc b/test/goalc/source_templates/control-statements/nested-call.static.gc similarity index 100% rename from test/goalc/source_templates/functions/nested-call.static.gc rename to test/goalc/source_templates/control-statements/nested-call.static.gc diff --git a/test/goalc/source_templates/library/protect.static.gc b/test/goalc/source_templates/control-statements/protect.static.gc similarity index 100% rename from test/goalc/source_templates/library/protect.static.gc rename to test/goalc/source_templates/control-statements/protect.static.gc diff --git a/test/goalc/source_templates/functions/return-arg.static.gc b/test/goalc/source_templates/control-statements/return-arg.static.gc similarity index 100% rename from test/goalc/source_templates/functions/return-arg.static.gc rename to test/goalc/source_templates/control-statements/return-arg.static.gc diff --git a/test/goalc/source_templates/functions/return-colors.static.gc b/test/goalc/source_templates/control-statements/return-colors.static.gc similarity index 100% rename from test/goalc/source_templates/functions/return-colors.static.gc rename to test/goalc/source_templates/control-statements/return-colors.static.gc diff --git a/test/goalc/source_templates/functions/return-from-trick.static.gc b/test/goalc/source_templates/control-statements/return-from-trick.static.gc similarity index 100% rename from test/goalc/source_templates/functions/return-from-trick.static.gc rename to test/goalc/source_templates/control-statements/return-from-trick.static.gc diff --git a/test/goalc/source_templates/functions/return.static.gc b/test/goalc/source_templates/control-statements/return.static.gc similarity index 100% rename from test/goalc/source_templates/functions/return.static.gc rename to test/goalc/source_templates/control-statements/return.static.gc diff --git a/test/goalc/source_templates/library/set-symbol.static.gc b/test/goalc/source_templates/control-statements/set-symbol.static.gc similarity index 100% rename from test/goalc/source_templates/library/set-symbol.static.gc rename to test/goalc/source_templates/control-statements/set-symbol.static.gc diff --git a/test/goalc/source_templates/functions/simple-call.static.gc b/test/goalc/source_templates/control-statements/simple-call.static.gc similarity index 100% rename from test/goalc/source_templates/functions/simple-call.static.gc rename to test/goalc/source_templates/control-statements/simple-call.static.gc diff --git a/test/goalc/source_templates/pointers/deref-simple.static.gc b/test/goalc/source_templates/variables/deref-simple.static.gc similarity index 100% rename from test/goalc/source_templates/pointers/deref-simple.static.gc rename to test/goalc/source_templates/variables/deref-simple.static.gc diff --git a/test/goalc/source_templates/strings/format-reg-order.static.gc b/test/goalc/source_templates/variables/format-reg-order.static.gc similarity index 100% rename from test/goalc/source_templates/strings/format-reg-order.static.gc rename to test/goalc/source_templates/variables/format-reg-order.static.gc diff --git a/test/goalc/source_templates/symbols/get-symbol-1.static.gc b/test/goalc/source_templates/variables/get-symbol-1.static.gc similarity index 100% rename from test/goalc/source_templates/symbols/get-symbol-1.static.gc rename to test/goalc/source_templates/variables/get-symbol-1.static.gc diff --git a/test/goalc/source_templates/symbols/get-symbol-2.static.gc b/test/goalc/source_templates/variables/get-symbol-2.static.gc similarity index 100% rename from test/goalc/source_templates/symbols/get-symbol-2.static.gc rename to test/goalc/source_templates/variables/get-symbol-2.static.gc diff --git a/test/goalc/source_templates/pointers/pointers.static.gc b/test/goalc/source_templates/variables/pointers.static.gc similarity index 100% rename from test/goalc/source_templates/pointers/pointers.static.gc rename to test/goalc/source_templates/variables/pointers.static.gc diff --git a/test/goalc/source_templates/strings/quote-symbol.static.gc b/test/goalc/source_templates/variables/quote-symbol.static.gc similarity index 100% rename from test/goalc/source_templates/strings/quote-symbol.static.gc rename to test/goalc/source_templates/variables/quote-symbol.static.gc diff --git a/test/goalc/source_templates/strings/string-constant-1.static.gc b/test/goalc/source_templates/variables/string-constant-1.static.gc similarity index 100% rename from test/goalc/source_templates/strings/string-constant-1.static.gc rename to test/goalc/source_templates/variables/string-constant-1.static.gc diff --git a/test/goalc/source_templates/strings/string-constant-2.static.gc b/test/goalc/source_templates/variables/string-constant-2.static.gc similarity index 100% rename from test/goalc/source_templates/strings/string-constant-2.static.gc rename to test/goalc/source_templates/variables/string-constant-2.static.gc diff --git a/test/goalc/source_templates/strings/string-symbol.static.gc b/test/goalc/source_templates/variables/string-symbol.static.gc similarity index 100% rename from test/goalc/source_templates/strings/string-symbol.static.gc rename to test/goalc/source_templates/variables/string-symbol.static.gc diff --git a/test/goalc/test_arithmetic.cpp b/test/goalc/test_arithmetic.cpp index 09d37b252f..7489448e93 100644 --- a/test/goalc/test_arithmetic.cpp +++ b/test/goalc/test_arithmetic.cpp @@ -121,15 +121,21 @@ class ArithmeticTests : public testing::TestWithParam { // Per-test-suite set-up. // Called before the first test in this test suite. static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; + runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel))); + compiler = std::make_unique(); + runner = std::make_unique(); + runner->c = compiler.get(); } // Per-test-suite tear-down. // Called after the last test in this test suite. static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); + compiler->shutdown_target(); + runtime_thread->join(); + + runtime_thread.reset(); + compiler.reset(); + runner.reset(); } // You can define per-test set-up logic as usual. @@ -142,9 +148,9 @@ class ArithmeticTests : public testing::TestWithParam { void TearDown() {} // Common Resources Across all Tests in the Suite - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; + static std::unique_ptr runtime_thread; + static std::unique_ptr compiler; + static std::unique_ptr runner; // Just to promote better test organization, supports nesting the test files 1 directory deep std::string testCategory = "arithmetic"; @@ -154,9 +160,9 @@ class ArithmeticTests : public testing::TestWithParam { // You must initialize the static variables outside of the declaration, or you'll run into // unresolved external errors -std::thread ArithmeticTests::runtime_thread; -Compiler ArithmeticTests::compiler; -GoalTest::CompilerTestRunner ArithmeticTests::runner; +std::unique_ptr ArithmeticTests::runtime_thread; +std::unique_ptr ArithmeticTests::compiler; +std::unique_ptr ArithmeticTests::runner; // Finally, we define our generic test, given our custom class that represents our test inputs // we can generate the lisp file, and pass along the path to the test runner @@ -169,7 +175,7 @@ TEST_P(ArithmeticTests, EvalIntegers) { std::string testFile = "eval-integer-" + std::to_string(param.index) + ".generated.gc"; env.write("eval-integer.template.gc", data, testFile); - runner.run_test(testCategory, testFile, {param.eval()}); + runner->run_test(testCategory, testFile, {param.eval()}); } // ValuesIn, is not the only way to use a parameterized test, but the most applicable for this @@ -184,65 +190,102 @@ INSTANTIATE_TEST_SUITE_P(EvalIntegers, IntegerParam(0), IntegerParam(-0)}))); TEST_F(ArithmeticTests, Addition) { - runner.run_static_test(env, testCategory, "add-int-literals.static.gc", {"13\n"}); - runner.run_static_test(env, testCategory, "add-let.static.gc", {"7\n"}); + runner->run_static_test(env, testCategory, "add-int-literals.static.gc", {"13\n"}); + runner->run_static_test(env, testCategory, "add-let.static.gc", {"7\n"}); } TEST_F(ArithmeticTests, AddIntegerFunction) { - runner.run_static_test(env, testCategory, "add-function.static.gc", {"21\n"}); + runner->run_static_test(env, testCategory, "add-function.static.gc", {"21\n"}); } TEST_F(ArithmeticTests, AddIntegerMultiple) { - runner.run_static_test(env, testCategory, "add-int-multiple.static.gc", {"15\n"}); - runner.run_static_test(env, testCategory, "add-int-multiple-2.static.gc", {"15\n"}); + runner->run_static_test(env, testCategory, "add-int-multiple.static.gc", {"15\n"}); + runner->run_static_test(env, testCategory, "add-int-multiple-2.static.gc", {"15\n"}); } TEST_F(ArithmeticTests, AddIntegerVariables) { - runner.run_static_test(env, testCategory, "add-int-vars.static.gc", {"7\n"}); + runner->run_static_test(env, testCategory, "add-int-vars.static.gc", {"7\n"}); } TEST_F(ArithmeticTests, AshFunction) { - runner.run_static_test(env, testCategory, "ash.static.gc", {"18\n"}); + runner->run_static_test(env, testCategory, "ash.static.gc", {"18\n"}); } TEST_F(ArithmeticTests, Division) { - runner.run_static_test(env, testCategory, "divide-1.static.gc", {"6\n"}); - runner.run_static_test(env, testCategory, "divide-2.static.gc", {"7\n"}); + runner->run_static_test(env, testCategory, "divide-1.static.gc", {"6\n"}); + runner->run_static_test(env, testCategory, "divide-2.static.gc", {"7\n"}); } TEST_F(ArithmeticTests, IntegerSymbol) { - runner.run_static_test(env, testCategory, "negative-int-symbol.static.gc", {"-123\n"}); + runner->run_static_test(env, testCategory, "negative-int-symbol.static.gc", {"-123\n"}); } TEST_F(ArithmeticTests, Modulus) { - runner.run_static_test(env, testCategory, "mod.static.gc", {"7\n"}); + runner->run_static_test(env, testCategory, "mod.static.gc", {"7\n"}); } TEST_F(ArithmeticTests, Multiplication) { - runner.run_static_test(env, testCategory, "multiply.static.gc", {"-12\n"}); - runner.run_static_test(env, testCategory, "multiply-let.static.gc", {"3\n"}); + runner->run_static_test(env, testCategory, "multiply.static.gc", {"-12\n"}); + runner->run_static_test(env, testCategory, "multiply-let.static.gc", {"3\n"}); } TEST_F(ArithmeticTests, NestedFunctionCall) { - runner.run_static_test(env, testCategory, "nested-function.static.gc", {"10\n"}); + runner->run_static_test(env, testCategory, "nested-function.static.gc", {"10\n"}); } TEST_F(ArithmeticTests, VariableShift) { - runner.run_static_test(env, testCategory, "shiftvs.static.gc", {"11\n"}); + runner->run_static_test(env, testCategory, "shiftvs.static.gc", {"11\n"}); } TEST_F(ArithmeticTests, FixedShift) { // same math as the variable shift test, just using the fixed shift operators. - runner.run_static_test(env, testCategory, "shift-fixed.static.gc", {"11\n"}); + runner->run_static_test(env, testCategory, "shift-fixed.static.gc", {"11\n"}); } TEST_F(ArithmeticTests, Subtraction) { - runner.run_static_test(env, testCategory, "subtract-1.static.gc", {"4\n"}); - runner.run_static_test(env, testCategory, "subtract-2.static.gc", {"4\n"}); - runner.run_static_test(env, testCategory, "subtract-let.static.gc", {"3\n"}); + runner->run_static_test(env, testCategory, "subtract-1.static.gc", {"4\n"}); + runner->run_static_test(env, testCategory, "subtract-2.static.gc", {"4\n"}); + runner->run_static_test(env, testCategory, "subtract-let.static.gc", {"3\n"}); } TEST_F(ArithmeticTests, Multiplication2) { - runner.run_static_test(env, testCategory, "multiply32.static.gc", {"-1234478448\n"}); - runner.run_static_test(env, testCategory, "multiply64.static.gc", {"93270638141856400\n"}); -} \ No newline at end of file + runner->run_static_test(env, testCategory, "multiply32.static.gc", {"-1234478448\n"}); + runner->run_static_test(env, testCategory, "multiply64.static.gc", {"93270638141856400\n"}); +} + +TEST_F(ArithmeticTests, Constants) { + runner->run_static_test(env, testCategory, "float.static.gc", {"1067316150\n"}); + runner->run_static_test(env, testCategory, "function-return-float-constant.static.gc", + {"3.14149\n0\n"}); +} + +TEST_F(ArithmeticTests, Operations) { + runner->run_static_test(env, testCategory, "float-pow.static.gc", {"256\n0\n"}); + runner->run_static_test(env, testCategory, "float-product.static.gc", {"120.0000\n0\n"}); +} + +TEST_F(ArithmeticTests, Symbols) { + runner->run_static_test(env, testCategory, "float-in-symbol.static.gc", {"2345.6000\n0\n"}); +} + +TEST_F(ArithmeticTests, Functions) { + runner->run_static_test(env, testCategory, "float-function.static.gc", {"10.152\n0\n"}); + runner->run_static_test( + env, testCategory, "nested-float-functions.static.gc", + {"i 1.4400 3.4000\nr 10.1523\ni 1.2000 10.1523\nr 17.5432\n17.543 10.152\n0\n"}); +} + +TEST_F(ArithmeticTests, MinMax) { + runner->run_static_test(env, testCategory, "float-max.static.gc", {"3.70\n0\n"}); + runner->run_static_test(env, testCategory, "float-min.static.gc", {"-1.20\n0\n"}); +} + +TEST_F(ArithmeticTests, LogicalOperators) { + runner->run_static_test(env, testCategory, "logand.static.gc", {"4\n"}); + runner->run_static_test(env, testCategory, "logior.static.gc", {"60\n"}); + runner->run_static_test(env, testCategory, "logxor.static.gc", {"56\n"}); +} + +TEST_F(ArithmeticTests, Comparison) { + runner->run_static_test(env, testCategory, "signed-int-compare.static.gc", {"12\n"}); +} diff --git a/test/goalc/test_collections.cpp b/test/goalc/test_collections.cpp index 0f6efea2c8..64776de847 100644 --- a/test/goalc/test_collections.cpp +++ b/test/goalc/test_collections.cpp @@ -25,13 +25,19 @@ struct CollectionParam { class CollectionTests : public testing::TestWithParam { public: static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; + runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel))); + compiler = std::make_unique(); + runner = std::make_unique(); + runner->c = compiler.get(); } static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); + compiler->shutdown_target(); + runtime_thread->join(); + + runtime_thread.reset(); + compiler.reset(); + runner.reset(); } void SetUp() { @@ -41,36 +47,36 @@ class CollectionTests : public testing::TestWithParam { void TearDown() {} - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; + static std::unique_ptr runtime_thread; + static std::unique_ptr compiler; + static std::unique_ptr runner; std::string testCategory = "collections"; inja::Environment env{GoalTest::getTemplateDir(testCategory), GoalTest::getGeneratedDir(testCategory)}; }; -std::thread CollectionTests::runtime_thread; -Compiler CollectionTests::compiler; -GoalTest::CompilerTestRunner CollectionTests::runner; +std::unique_ptr CollectionTests::runtime_thread; +std::unique_ptr CollectionTests::compiler; +std::unique_ptr CollectionTests::runner; TEST_F(CollectionTests, Pairs) { - runner.run_static_test(env, testCategory, "empty-pair.static.gc", {"()\n0\n"}); - runner.run_static_test(env, testCategory, "pair-check.static.gc", {"#t#f\n0\n"}); + runner->run_static_test(env, testCategory, "empty-pair.static.gc", {"()\n0\n"}); + runner->run_static_test(env, testCategory, "pair-check.static.gc", {"#t#f\n0\n"}); } TEST_F(CollectionTests, Lists) { - runner.run_static_test(env, testCategory, "list.static.gc", {"(a b c d)\n0\n"}); + runner->run_static_test(env, testCategory, "list.static.gc", {"(a b c d)\n0\n"}); } TEST_F(CollectionTests, InlineArray) { - runner.run_static_test(env, testCategory, "inline-array-field.static.gc", {"16\n"}); + runner->run_static_test(env, testCategory, "inline-array-field.static.gc", {"16\n"}); } TEST_F(CollectionTests, Operations) { - runner.run_static_test(env, testCategory, "cons.static.gc", {"(a . b)\n0\n"}); - runner.run_static_test(env, testCategory, "car-cdr-get.static.gc", {"ab\n0\n"}); - runner.run_static_test(env, testCategory, "car-cdr-set.static.gc", {"(c . d)\n0\n"}); - runner.run_static_test(env, testCategory, "nested-car-cdr-set.static.gc", - {"efgh\n((e . g) f . h)\n0\n"}); + runner->run_static_test(env, testCategory, "cons.static.gc", {"(a . b)\n0\n"}); + runner->run_static_test(env, testCategory, "car-cdr-get.static.gc", {"ab\n0\n"}); + runner->run_static_test(env, testCategory, "car-cdr-set.static.gc", {"(c . d)\n0\n"}); + runner->run_static_test(env, testCategory, "nested-car-cdr-set.static.gc", + {"efgh\n((e . g) f . h)\n0\n"}); } diff --git a/test/goalc/test_control_statements.cpp b/test/goalc/test_control_statements.cpp index 5dd6f1e1fa..f55f41ac08 100644 --- a/test/goalc/test_control_statements.cpp +++ b/test/goalc/test_control_statements.cpp @@ -25,13 +25,19 @@ struct ControlStatementParam { class ControlStatementTests : public testing::TestWithParam { public: static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; + runtime_thread = std::make_unique(std::thread((GoalTest::runtime_no_kernel))); + compiler = std::make_unique(); + runner = std::make_unique(); + runner->c = compiler.get(); } static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); + compiler->shutdown_target(); + runtime_thread->join(); + + runtime_thread.reset(); + compiler.reset(); + runner.reset(); } void SetUp() { @@ -41,33 +47,152 @@ class ControlStatementTests : public testing::TestWithParam runtime_thread; + static std::unique_ptr compiler; + static std::unique_ptr runner; std::string testCategory = "control-statements"; inja::Environment env{GoalTest::getTemplateDir(testCategory), GoalTest::getGeneratedDir(testCategory)}; }; -std::thread ControlStatementTests::runtime_thread; -Compiler ControlStatementTests::compiler; -GoalTest::CompilerTestRunner ControlStatementTests::runner; +std::unique_ptr ControlStatementTests::runtime_thread; +std::unique_ptr ControlStatementTests::compiler; +std::unique_ptr ControlStatementTests::runner; TEST_F(ControlStatementTests, ConditionalCompilation) { - runner.run_static_test(env, testCategory, "conditional-compilation.static.gc", {"3\n"}); + runner->run_static_test(env, testCategory, "conditional-compilation.static.gc", {"3\n"}); } TEST_F(ControlStatementTests, Blocks) { - runner.run_static_test(env, testCategory, "nested-blocks-1.static.gc", {"7\n"}); - runner.run_static_test(env, testCategory, "nested-blocks-2.static.gc", {"8\n"}); - runner.run_static_test(env, testCategory, "nested-blocks-3.static.gc", {"7\n"}); + runner->run_static_test(env, testCategory, "nested-blocks-1.static.gc", {"7\n"}); + runner->run_static_test(env, testCategory, "nested-blocks-2.static.gc", {"8\n"}); + runner->run_static_test(env, testCategory, "nested-blocks-3.static.gc", {"7\n"}); } TEST_F(ControlStatementTests, GoTo) { - runner.run_static_test(env, testCategory, "goto.static.gc", {"3\n"}); + runner->run_static_test(env, testCategory, "goto.static.gc", {"3\n"}); } TEST_F(ControlStatementTests, Branch) { - runner.run_static_test(env, testCategory, "return-value-of-if.static.gc", {"123\n"}); + runner->run_static_test(env, testCategory, "return-value-of-if.static.gc", {"123\n"}); +} + +TEST_F(ControlStatementTests, DoTimes) { + runner->run_static_test(env, testCategory, "dotimes.static.gc", {"4950\n"}); +} + +TEST_F(ControlStatementTests, Factorial) { + runner->run_static_test(env, testCategory, "factorial-recursive.static.gc", {"3628800\n"}); + runner->run_static_test(env, testCategory, "factorial-iterative.static.gc", {"3628800\n"}); +} + +TEST_F(ControlStatementTests, Definitions) { + runner->run_static_test(env, testCategory, "defun-return-constant.static.gc", {"12\n"}); + runner->run_static_test(env, testCategory, "defun-return-symbol.static.gc", {"42\n"}); +} + +TEST_F(ControlStatementTests, ReturnValue) { + runner->run_static_test(env, testCategory, "return.static.gc", {"77\n"}); + runner->run_static_test(env, testCategory, "return-arg.static.gc", {"23\n"}); + runner->run_static_test(env, testCategory, "return-colors.static.gc", {"77\n"}); +} + +TEST_F(ControlStatementTests, Calling) { + runner->run_static_test(env, testCategory, "nested-call.static.gc", {"2\n"}); + runner->run_static_test(env, testCategory, "inline-call.static.gc", {"44\n"}); + runner->run_static_test(env, testCategory, "simple-call.static.gc", {"30\n"}); +} + +TEST_F(ControlStatementTests, Anonymous) { + runner->run_static_test(env, testCategory, "declare-inline.static.gc", {"32\n"}); + runner->run_static_test(env, testCategory, "lambda-1.static.gc", {"2\n"}); +} + +TEST_F(ControlStatementTests, InlineIsInline) { + auto code = compiler->get_goos().reader.read_from_file( + {"test/goalc/source_templates/control-statements/declare-inline.static.gc"}); + auto compiled = compiler->compile_object_file("test-code", code, true); + EXPECT_EQ(compiled->functions().size(), 2); + auto& ir = compiled->top_level_function().code(); + bool got_mult = false; + for (auto& x : ir) { + EXPECT_EQ(dynamic_cast(x.get()), nullptr); + auto as_im = dynamic_cast(x.get()); + if (as_im) { + EXPECT_EQ(as_im->get_kind(), IntegerMathKind::IMUL_32); + got_mult = true; + } + } + EXPECT_TRUE(got_mult); +} + +TEST_F(ControlStatementTests, AllowInline) { + auto code = compiler->get_goos().reader.read_from_file( + {"test/goalc/source_templates/control-statements/inline-call.static.gc"}); + auto compiled = compiler->compile_object_file("test-code", code, true); + EXPECT_EQ(compiled->functions().size(), 2); + auto& ir = compiled->top_level_function().code(); + int got_mult = 0; + int got_call = 0; + for (auto& x : ir) { + if (dynamic_cast(x.get())) { + got_call++; + } + auto as_im = dynamic_cast(x.get()); + if (as_im && as_im->get_kind() == IntegerMathKind::IMUL_32) { + got_mult++; + } + } + EXPECT_EQ(got_mult, 1); + EXPECT_EQ(got_call, 1); +} + +TEST_F(ControlStatementTests, ReturnNone) { + runner->run_static_test(env, testCategory, "function-returning-none.static.gc", {"1\n"}); } + +TEST_F(ControlStatementTests, InlineBlock1) { + runner->run_static_test(env, testCategory, "inline-with-block-1.static.gc", {"1\n"}); +} + +TEST_F(ControlStatementTests, InlineBlock2) { + runner->run_static_test(env, testCategory, "inline-with-block-2.static.gc", {"3\n"}); +} + +TEST_F(ControlStatementTests, InlineBlock3) { + runner->run_static_test(env, testCategory, "inline-with-block-3.static.gc", {"4\n"}); +} + +TEST_F(ControlStatementTests, InlineBlock4) { + runner->run_static_test(env, testCategory, "inline-with-block-4.static.gc", {"3.0000\n0\n"}); +} + +TEST_F(ControlStatementTests, ReturnFromTrick) { + runner->run_static_test(env, testCategory, "return-from-trick.static.gc", {"1\n"}); +} + +TEST_F(ControlStatementTests, Set) { + runner->run_static_test(env, testCategory, "set-symbol.static.gc", {"22\n"}); +} + +TEST_F(ControlStatementTests, Protect) { + runner->run_static_test(env, testCategory, "protect.static.gc", {"33\n"}); +} + +TEST_F(ControlStatementTests, Align) { + runner->run_static_test(env, testCategory, "align16-1.static.gc", {"80\n"}); + runner->run_static_test(env, testCategory, "align16-2.static.gc", {"64\n"}); +} + +TEST_F(ControlStatementTests, Defsmacro) { + runner->run_static_test(env, testCategory, "defsmacro-defgmacro.static.gc", {"20\n"}); +} + +TEST_F(ControlStatementTests, Desfun) { + runner->run_static_test(env, testCategory, "desfun.static.gc", {"4\n"}); +} + +TEST_F(ControlStatementTests, DeReference) { + runner->run_static_test(env, testCategory, "methods.static.gc", {"#t#t\n0\n"}); +} \ No newline at end of file diff --git a/test/goalc/test_float.cpp b/test/goalc/test_float.cpp deleted file mode 100644 index ec6b398ce5..0000000000 --- a/test/goalc/test_float.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct FloatParam { - // TODO - Not Needed Yet -}; - -class FloatTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "float"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread FloatTests::runtime_thread; -Compiler FloatTests::compiler; -GoalTest::CompilerTestRunner FloatTests::runner; - -TEST_F(FloatTests, Constants) { - runner.run_static_test(env, testCategory, "float.static.gc", {"1067316150\n"}); - runner.run_static_test(env, testCategory, "function-return-float-constant.static.gc", - {"3.14149\n0\n"}); -} - -TEST_F(FloatTests, Operations) { - runner.run_static_test(env, testCategory, "float-pow.static.gc", {"256\n0\n"}); - runner.run_static_test(env, testCategory, "float-product.static.gc", {"120.0000\n0\n"}); -} - -TEST_F(FloatTests, Symbols) { - runner.run_static_test(env, testCategory, "float-in-symbol.static.gc", {"2345.6000\n0\n"}); -} - -TEST_F(FloatTests, Functions) { - runner.run_static_test(env, testCategory, "float-function.static.gc", {"10.152\n0\n"}); - runner.run_static_test( - env, testCategory, "nested-float-functions.static.gc", - {"i 1.4400 3.4000\nr 10.1523\ni 1.2000 10.1523\nr 17.5432\n17.543 10.152\n0\n"}); -} - -TEST_F(FloatTests, MinMax) { - runner.run_static_test(env, testCategory, "float-max.static.gc", {"3.70\n0\n"}); - runner.run_static_test(env, testCategory, "float-min.static.gc", {"-1.20\n0\n"}); -} \ No newline at end of file diff --git a/test/goalc/test_functions.cpp b/test/goalc/test_functions.cpp deleted file mode 100644 index dc93dd8b93..0000000000 --- a/test/goalc/test_functions.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct FunctionParam { - // TODO - Not Needed Yet -}; - -class FunctionTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "functions"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread FunctionTests::runtime_thread; -Compiler FunctionTests::compiler; -GoalTest::CompilerTestRunner FunctionTests::runner; - -TEST_F(FunctionTests, Definitions) { - runner.run_static_test(env, testCategory, "defun-return-constant.static.gc", {"12\n"}); - runner.run_static_test(env, testCategory, "defun-return-symbol.static.gc", {"42\n"}); -} - -TEST_F(FunctionTests, ReturnValue) { - runner.run_static_test(env, testCategory, "return.static.gc", {"77\n"}); - runner.run_static_test(env, testCategory, "return-arg.static.gc", {"23\n"}); - runner.run_static_test(env, testCategory, "return-colors.static.gc", {"77\n"}); -} - -TEST_F(FunctionTests, Calling) { - runner.run_static_test(env, testCategory, "nested-call.static.gc", {"2\n"}); - runner.run_static_test(env, testCategory, "inline-call.static.gc", {"44\n"}); - runner.run_static_test(env, testCategory, "simple-call.static.gc", {"30\n"}); -} - -TEST_F(FunctionTests, Anonymous) { - runner.run_static_test(env, testCategory, "declare-inline.static.gc", {"32\n"}); - runner.run_static_test(env, testCategory, "lambda-1.static.gc", {"2\n"}); -} - -TEST_F(FunctionTests, InlineIsInline) { - auto code = compiler.get_goos().reader.read_from_file( - {"test/goalc/source_templates/functions/declare-inline.static.gc"}); - auto compiled = compiler.compile_object_file("test-code", code, true); - EXPECT_EQ(compiled->functions().size(), 2); - auto& ir = compiled->top_level_function().code(); - bool got_mult = false; - for (auto& x : ir) { - EXPECT_EQ(dynamic_cast(x.get()), nullptr); - auto as_im = dynamic_cast(x.get()); - if (as_im) { - EXPECT_EQ(as_im->get_kind(), IntegerMathKind::IMUL_32); - got_mult = true; - } - } - EXPECT_TRUE(got_mult); -} - -TEST_F(FunctionTests, AllowInline) { - auto code = compiler.get_goos().reader.read_from_file( - {"test/goalc/source_templates/functions/inline-call.static.gc"}); - auto compiled = compiler.compile_object_file("test-code", code, true); - EXPECT_EQ(compiled->functions().size(), 2); - auto& ir = compiled->top_level_function().code(); - int got_mult = 0; - int got_call = 0; - for (auto& x : ir) { - if (dynamic_cast(x.get())) { - got_call++; - } - auto as_im = dynamic_cast(x.get()); - if (as_im && as_im->get_kind() == IntegerMathKind::IMUL_32) { - got_mult++; - } - } - EXPECT_EQ(got_mult, 1); - EXPECT_EQ(got_call, 1); -} - -TEST_F(FunctionTests, ReturnNone) { - runner.run_static_test(env, testCategory, "function-returning-none.static.gc", {"1\n"}); -} - -TEST_F(FunctionTests, InlineBlock1) { - runner.run_static_test(env, testCategory, "inline-with-block-1.static.gc", {"1\n"}); -} - -TEST_F(FunctionTests, InlineBlock2) { - runner.run_static_test(env, testCategory, "inline-with-block-2.static.gc", {"3\n"}); -} - -TEST_F(FunctionTests, InlineBlock3) { - runner.run_static_test(env, testCategory, "inline-with-block-3.static.gc", {"4\n"}); -} - -TEST_F(FunctionTests, InlineBlock4) { - runner.run_static_test(env, testCategory, "inline-with-block-4.static.gc", {"3.0000\n0\n"}); -} - -TEST_F(FunctionTests, ReturnFromTrick) { - runner.run_static_test(env, testCategory, "return-from-trick.static.gc", {"1\n"}); -} \ No newline at end of file diff --git a/test/goalc/test_library.cpp b/test/goalc/test_library.cpp deleted file mode 100644 index 960c9102f0..0000000000 --- a/test/goalc/test_library.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct LibraryParam { - // TODO - Not Needed Yet -}; - -class LibraryTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "library"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread LibraryTests::runtime_thread; -Compiler LibraryTests::compiler; -GoalTest::CompilerTestRunner LibraryTests::runner; - -TEST_F(LibraryTests, Set) { - runner.run_static_test(env, testCategory, "set-symbol.static.gc", {"22\n"}); -} - -TEST_F(LibraryTests, Protect) { - runner.run_static_test(env, testCategory, "protect.static.gc", {"33\n"}); -} - -TEST_F(LibraryTests, Align) { - runner.run_static_test(env, testCategory, "align16-1.static.gc", {"80\n"}); - runner.run_static_test(env, testCategory, "align16-2.static.gc", {"64\n"}); -} diff --git a/test/goalc/test_logic.cpp b/test/goalc/test_logic.cpp deleted file mode 100644 index 20c5243138..0000000000 --- a/test/goalc/test_logic.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct LogicParam { - // TODO - Not Needed Yet -}; - -class LogicTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "logic"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread LogicTests::runtime_thread; -Compiler LogicTests::compiler; -GoalTest::CompilerTestRunner LogicTests::runner; - -TEST_F(LogicTests, LogicalOperators) { - runner.run_static_test(env, testCategory, "logand.static.gc", {"4\n"}); - runner.run_static_test(env, testCategory, "logior.static.gc", {"60\n"}); - runner.run_static_test(env, testCategory, "logxor.static.gc", {"56\n"}); -} - -TEST_F(LogicTests, Comparison) { - runner.run_static_test(env, testCategory, "signed-int-compare.static.gc", {"12\n"}); -} diff --git a/test/goalc/test_loop_recur.cpp b/test/goalc/test_loop_recur.cpp deleted file mode 100644 index 171b76217a..0000000000 --- a/test/goalc/test_loop_recur.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct LoopRecurParam { - // TODO - Not Needed Yet -}; - -class LoopRecurTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "loop_recur"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread LoopRecurTests::runtime_thread; -Compiler LoopRecurTests::compiler; -GoalTest::CompilerTestRunner LoopRecurTests::runner; - -TEST_F(LoopRecurTests, DoTimes) { - runner.run_static_test(env, testCategory, "dotimes.static.gc", {"4950\n"}); -} - -TEST_F(LoopRecurTests, Factorial) { - runner.run_static_test(env, testCategory, "factorial-recursive.static.gc", {"3628800\n"}); - runner.run_static_test(env, testCategory, "factorial-iterative.static.gc", {"3628800\n"}); -} diff --git a/test/goalc/test_macros.cpp b/test/goalc/test_macros.cpp deleted file mode 100644 index fc1fb6f593..0000000000 --- a/test/goalc/test_macros.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct MacroParam { - // TODO - Not Needed Yet -}; - -class MacroTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "macros"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread MacroTests::runtime_thread; -Compiler MacroTests::compiler; -GoalTest::CompilerTestRunner MacroTests::runner; - -TEST_F(MacroTests, Defsmacro) { - runner.run_static_test(env, testCategory, "defsmacro-defgmacro.static.gc", {"20\n"}); -} - -TEST_F(MacroTests, Desfun) { - runner.run_static_test(env, testCategory, "desfun.static.gc", {"4\n"}); -} diff --git a/test/goalc/test_methods.cpp b/test/goalc/test_methods.cpp deleted file mode 100644 index a80659d9e6..0000000000 --- a/test/goalc/test_methods.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct MethodParam { - // TODO - Not Needed Yet -}; - -class MethodTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "methods"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread MethodTests::runtime_thread; -Compiler MethodTests::compiler; -GoalTest::CompilerTestRunner MethodTests::runner; - -TEST_F(MethodTests, DeReference) { - runner.run_static_test(env, testCategory, "methods.static.gc", {"#t#t\n0\n"}); -} \ No newline at end of file diff --git a/test/goalc/test_pointers.cpp b/test/goalc/test_pointers.cpp deleted file mode 100644 index 7205b89363..0000000000 --- a/test/goalc/test_pointers.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct PointerParam { - // TODO - Not Needed Yet -}; - -class PointerTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "pointers"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread PointerTests::runtime_thread; -Compiler PointerTests::compiler; -GoalTest::CompilerTestRunner PointerTests::runner; - -TEST_F(PointerTests, DeReference) { - runner.run_static_test(env, testCategory, "deref-simple.static.gc", {"structure\n0\n"}); -} - -TEST_F(PointerTests, Pointers) { - runner.run_static_test(env, testCategory, "pointers.static.gc", {"13\n"}); -} diff --git a/test/goalc/test_strings.cpp b/test/goalc/test_strings.cpp deleted file mode 100644 index 252ddad9f9..0000000000 --- a/test/goalc/test_strings.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct StringParam { - // TODO - Not Needed Yet -}; - -class StringTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "strings"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread StringTests::runtime_thread; -Compiler StringTests::compiler; -GoalTest::CompilerTestRunner StringTests::runner; - -TEST_F(StringTests, Constants) { - // TODO - runner.run_static_test(env, testCategory, "string-constant-1.static.gc"); - std::string expected = "\"test string!\""; - runner.run_static_test(env, testCategory, "string-constant-2.static.gc", {expected}, - expected.size()); -} - -TEST_F(StringTests, Symbols) { - runner.run_static_test(env, testCategory, "quote-symbol.static.gc", {"banana\n0\n"}); - std::string expected = "test-string"; - runner.run_static_test(env, testCategory, "string-symbol.static.gc", {expected}, expected.size()); -} - -TEST_F(StringTests, Formatting) { - runner.run_static_test(env, testCategory, "format-reg-order.static.gc", - {"test 1 2 3 4 5 6\n0\n"}); -} - -// expected = -// "test newline\nnewline\ntest tilde ~ \ntest A print boxed-string: \"boxed string!\"\ntest -// A " "print symbol: a-symbol\ntest A make boxed object longer: \"srt\"!\ntest A -// " "non-default pad: zzzzzzpad-me\ntest A shorten(4): a23~\ntest A don'tchange(4): -// a234\ntest A " "shorten with pad(4): sho~\ntest A a few things \"one thing\" a-second -// integer #\n"; -// -// expected += "test S a string a-symbol another string!\n"; -// expected += "test C ) ]\n"; -// expected += "test P (no type) #\n"; -// expected += "test P (with type) 1447236\n"; -// -// // todo, finish format testing. -// runner.run_test_from_file("test-format.gc", {expected}, expected.size()); diff --git a/test/goalc/test_symbols.cpp b/test/goalc/test_symbols.cpp deleted file mode 100644 index af78515962..0000000000 --- a/test/goalc/test_symbols.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include - -#include "gtest/gtest.h" -#include "game/runtime.h" -#include "goalc/listener/Listener.h" -#include "goalc/compiler/Compiler.h" - -#include "inja.hpp" -#include "third-party/json.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include - -struct SymbolParam { - // TODO - Not Needed Yet -}; - -class SymbolTests : public testing::TestWithParam { - public: - static void SetUpTestSuite() { - runtime_thread = std::thread((GoalTest::runtime_no_kernel)); - runner.c = &compiler; - } - - static void TearDownTestSuite() { - compiler.shutdown_target(); - runtime_thread.join(); - } - - void SetUp() { - GoalTest::createDirIfAbsent(GoalTest::getTemplateDir(testCategory)); - GoalTest::createDirIfAbsent(GoalTest::getGeneratedDir(testCategory)); - } - - void TearDown() {} - - static std::thread runtime_thread; - static Compiler compiler; - static GoalTest::CompilerTestRunner runner; - - std::string testCategory = "symbols"; - inja::Environment env{GoalTest::getTemplateDir(testCategory), - GoalTest::getGeneratedDir(testCategory)}; -}; - -std::thread SymbolTests::runtime_thread; -Compiler SymbolTests::compiler; -GoalTest::CompilerTestRunner SymbolTests::runner; - -TEST_F(SymbolTests, GetSymbol) { - runner.run_static_test(env, testCategory, "get-symbol-1.static.gc", - {"1342756\n"}); // 0x147d24 in hex - runner.run_static_test(env, testCategory, "get-symbol-2.static.gc", - {"1342764\n"}); // 0x147d2c in hex -} diff --git a/test/goalc/test_variables.cpp b/test/goalc/test_variables.cpp index 99d811fc9e..fd55191193 100644 --- a/test/goalc/test_variables.cpp +++ b/test/goalc/test_variables.cpp @@ -93,4 +93,52 @@ TEST_F(VariableTests, StackArrayAlignment) { TEST_F(VariableTests, StackStructureAlignment) { runner.run_static_test(env, testCategory, "stack-structure-align.gc", {"1234\n"}); -} \ No newline at end of file +} + +TEST_F(VariableTests, GetSymbol) { + runner.run_static_test(env, testCategory, "get-symbol-1.static.gc", + {"1342756\n"}); // 0x147d24 in hex + runner.run_static_test(env, testCategory, "get-symbol-2.static.gc", + {"1342764\n"}); // 0x147d2c in hex +} + +TEST_F(VariableTests, Constants) { + // TODO - runner.run_static_test(env, testCategory, "string-constant-1.static.gc"); + std::string expected = "\"test string!\""; + runner.run_static_test(env, testCategory, "string-constant-2.static.gc", {expected}, + expected.size()); +} + +TEST_F(VariableTests, Symbols) { + runner.run_static_test(env, testCategory, "quote-symbol.static.gc", {"banana\n0\n"}); + std::string expected = "test-string"; + runner.run_static_test(env, testCategory, "string-symbol.static.gc", {expected}, expected.size()); +} + +TEST_F(VariableTests, Formatting) { + runner.run_static_test(env, testCategory, "format-reg-order.static.gc", + {"test 1 2 3 4 5 6\n0\n"}); +} + +TEST_F(VariableTests, DeReference) { + runner.run_static_test(env, testCategory, "deref-simple.static.gc", {"structure\n0\n"}); +} + +TEST_F(VariableTests, Pointers) { + runner.run_static_test(env, testCategory, "pointers.static.gc", {"13\n"}); +} + +// expected = +// "test newline\nnewline\ntest tilde ~ \ntest A print boxed-string: \"boxed string!\"\ntest +// A " "print symbol: a-symbol\ntest A make boxed object longer: \"srt\"!\ntest A +// " "non-default pad: zzzzzzpad-me\ntest A shorten(4): a23~\ntest A don'tchange(4): +// a234\ntest A " "shorten with pad(4): sho~\ntest A a few things \"one thing\" a-second +// integer #\n"; +// +// expected += "test S a string a-symbol another string!\n"; +// expected += "test C ) ]\n"; +// expected += "test P (no type) #\n"; +// expected += "test P (with type) 1447236\n"; +// +// // todo, finish format testing. +// runner.run_test_from_file("test-format.gc", {expected}, expected.size()); diff --git a/test/test_listener_deci2.cpp b/test/test_listener_deci2.cpp index ebc5aedeab..6037806977 100644 --- a/test/test_listener_deci2.cpp +++ b/test/test_listener_deci2.cpp @@ -58,7 +58,7 @@ TEST(Listener, CheckConnectionStaysAlive) { } EXPECT_TRUE(s.check_for_listener()); - std::this_thread::sleep_for(std::chrono::seconds(2)); // sorry for making tests slow. + std::this_thread::sleep_for(std::chrono::milliseconds(500)); EXPECT_TRUE(s.check_for_listener()); EXPECT_TRUE(l.is_connected()); }