mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 07:28:22 -10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1588644fec | ||
|
|
0abd592038 | ||
|
|
909e799bdd | ||
|
|
5a9f181aff | ||
|
|
b0ba22a43d | ||
|
|
c89faebe4e | ||
|
|
059e149590 |
No files matched your search
@@ -8,6 +8,7 @@ env:
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration: [Debug, Release]
|
||||
compiler: [gcc-5, gcc-10, clang-9]
|
||||
|
||||
@@ -32,4 +32,5 @@ export LD_LIBRARY_PATH
|
||||
|
||||
cmake -G Ninja -DFSO_FATAL_WARNINGS=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON $CMAKE_OPTIONS \
|
||||
-DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DFSO_BUILD_APPIMAGE=ON -DCMAKE_BUILD_TYPE=$CONFIGURATION \
|
||||
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
|
||||
-DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON \
|
||||
-DSHADERS_ENABLE_COMPILATION=ON ..
|
||||
@@ -63,6 +63,8 @@ ENDIF(FSO_USE_SPEECH)
|
||||
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC jansson)
|
||||
|
||||
target_link_libraries(code PUBLIC variant)
|
||||
|
||||
# Headers for standalone "gui" on UNIX
|
||||
IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(code PUBLIC ${MONGOOSE_LIBS})
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
Action::~Action() = default;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
enum class ActionResult
|
||||
{
|
||||
Finished,
|
||||
Errored,
|
||||
Wait
|
||||
};
|
||||
|
||||
class Action {
|
||||
public:
|
||||
virtual ~Action() = 0;
|
||||
|
||||
virtual ActionResult execute(ProgramLocals& locals) const = 0;
|
||||
|
||||
virtual std::unique_ptr<Action> clone() const = 0;
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#include "ActionDefinition.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
ActionDefinition::ActionDefinition(SCP_string name, SCP_vector<ActionParameter> parameters)
|
||||
: m_name(std::move(name)), m_parameters(std::move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
const SCP_string& ActionDefinition::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
const SCP_vector<ActionParameter>& ActionDefinition::getParameters() const
|
||||
{
|
||||
return m_parameters;
|
||||
}
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
#include "actions/expression/Value.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
struct ActionParameter {
|
||||
SCP_string name;
|
||||
expression::ValueType type;
|
||||
};
|
||||
|
||||
class ActionDefinition {
|
||||
public:
|
||||
ActionDefinition(SCP_string name, SCP_vector<ActionParameter> parameters);
|
||||
|
||||
const SCP_string& getName() const;
|
||||
const SCP_vector<actions::ActionParameter>& getParameters() const;
|
||||
|
||||
virtual flagset<ProgramContextFlags> getRequiredContext() const = 0;
|
||||
|
||||
virtual std::unique_ptr<Action> createAction(
|
||||
const SCP_unordered_map<SCP_string, expression::ActionExpression>& parameterExpressions) const = 0;
|
||||
|
||||
private:
|
||||
SCP_string m_name;
|
||||
SCP_vector<ActionParameter> m_parameters;
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,148 @@
|
||||
|
||||
#include "ActionDefinitionManager.h"
|
||||
|
||||
#include "BuiltinActionDefinition.h"
|
||||
|
||||
#include "actions/types/MoveToSubmodel.h"
|
||||
#include "actions/types/ParticleEffectAction.h"
|
||||
#include "actions/types/PlaySoundAction.h"
|
||||
#include "actions/types/SetDirectionAction.h"
|
||||
#include "actions/types/SetPositionAction.h"
|
||||
#include "actions/types/WaitAction.h"
|
||||
#include "utils/join_string.h"
|
||||
|
||||
namespace actions {
|
||||
namespace {
|
||||
|
||||
void parseActionParameters(const SCP_vector<ActionParameter>& params,
|
||||
SCP_unordered_map<SCP_string, expression::ActionExpression>& parameterExpressions,
|
||||
const expression::ParseContext& context)
|
||||
{
|
||||
// We do not impose a set order of the parameters so we need to do something similar to the outer loop and
|
||||
// check for every possibility in a loop.
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
// We might be doing some empty loops here in case of errors but there is a bound so this will finish
|
||||
// eventually
|
||||
for (const auto& parameter : params) {
|
||||
// Do not check for parameters which we already found
|
||||
if (parameterExpressions.find(parameter.name) != parameterExpressions.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto paramString = "+" + parameter.name + ":";
|
||||
|
||||
if (!optional_string(paramString.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We found our parameter!
|
||||
parameterExpressions[parameter.name] =
|
||||
expression::ActionExpression::parseFromTable(parameter.type, context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const ActionDefinitionManager& ActionDefinitionManager::instance()
|
||||
{
|
||||
static const ActionDefinitionManager manager = []() {
|
||||
ActionDefinitionManager newManager;
|
||||
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::MoveToSubmodel>("Move To Subobject")));
|
||||
newManager.addDefinition(std::unique_ptr<ActionDefinition>(
|
||||
new BuiltinActionDefinition<types::ParticleEffectAction>("Start Particle Effect")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::PlaySoundAction>("Play 3D Sound")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetDirectionAction>("Set Direction")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::SetPositionAction>("Set Position")));
|
||||
newManager.addDefinition(
|
||||
std::unique_ptr<ActionDefinition>(new BuiltinActionDefinition<types::WaitAction>("Wait")));
|
||||
|
||||
return newManager;
|
||||
}();
|
||||
return manager;
|
||||
}
|
||||
void ActionDefinitionManager::addDefinition(std::unique_ptr<ActionDefinition> def)
|
||||
{
|
||||
m_definitions.push_back(std::move(def));
|
||||
}
|
||||
std::unique_ptr<Action> ActionDefinitionManager::parseAction(const flagset<ProgramContextFlags>& context_flags,
|
||||
const expression::ParseContext& context) const
|
||||
{
|
||||
// We search through all definitions for every time we want to check for an action. This is not the most efficient
|
||||
// way to handle this since it results in an O(n^2) runtime. A better alternative would be to either construct a
|
||||
// regex with all the accepted actions as alternatives (although runtime of this is also doubtful) or peek at the
|
||||
// next token, extract the relevant part (The stuff between "+" and ":") and then look that up in a map. Then we
|
||||
// would get down to O(n).
|
||||
// Since this only happens at parse time, this is good enough for now.
|
||||
for (const auto& actionDef : m_definitions) {
|
||||
const auto parseString = "+" + actionDef->getName() + ":";
|
||||
|
||||
if (!optional_string(parseString.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SCP_unordered_map<SCP_string, expression::ActionExpression> parameterExpressions;
|
||||
const auto& params = actionDef->getParameters();
|
||||
|
||||
if (params.size() == 1) {
|
||||
// Single parameters are expected to be placed directly after the action name
|
||||
parameterExpressions[params.front().name] =
|
||||
expression::ActionExpression::parseFromTable(params.front().type, context);
|
||||
} else {
|
||||
parseActionParameters(params, parameterExpressions, context);
|
||||
|
||||
if (parameterExpressions.size() != params.size()) {
|
||||
SCP_vector<ActionParameter> missingParameters;
|
||||
std::copy_if(params.cbegin(),
|
||||
params.cend(),
|
||||
std::back_inserter(missingParameters),
|
||||
[¶meterExpressions](const ActionParameter& param) {
|
||||
const auto iter = parameterExpressions.find(param.name);
|
||||
return iter == parameterExpressions.cend();
|
||||
});
|
||||
|
||||
SCP_vector<SCP_string> missingParameterNames;
|
||||
std::transform(missingParameters.cbegin(),
|
||||
missingParameters.cend(),
|
||||
std::back_inserter(missingParameterNames),
|
||||
[](const ActionParameter& param) { return "+" + param.name; });
|
||||
|
||||
const auto namesList = util::join_container(missingParameterNames, ", ");
|
||||
|
||||
error_display(0, "Missing parameters for action '%s': %s", parseString.c_str(), namesList.c_str());
|
||||
|
||||
// Fix up the parameter list so that we can continue parsing
|
||||
for (const auto& missingParam : missingParameters) {
|
||||
parameterExpressions[missingParam.name] = expression::ActionExpression();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto actionInstance = actionDef->createAction(parameterExpressions);
|
||||
|
||||
const auto requiredFlags = actionDef->getRequiredContext();
|
||||
|
||||
if ((context_flags & requiredFlags) != requiredFlags) {
|
||||
// We are missing at least one context flag so this action is not valid here. We still return the action
|
||||
// here though since that is the only way we can keep parsing the table without throwing random error
|
||||
// messages at the user. However, this will trigger an Assertion (in debug) or crashes when the action is
|
||||
// actually run later.
|
||||
error_display(0,
|
||||
"The action %s is not available in the current context. This will lead to an Assertion failure when "
|
||||
"this action is triggered.",
|
||||
parseString.c_str());
|
||||
}
|
||||
|
||||
return actionInstance;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Action>();
|
||||
}
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "ActionDefinition.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
class ActionDefinitionManager {
|
||||
public:
|
||||
// This type is supposed to be global so it may not be copied
|
||||
ActionDefinitionManager(const ActionDefinitionManager&) = delete;
|
||||
ActionDefinitionManager& operator=(const ActionDefinitionManager&) = delete;
|
||||
|
||||
ActionDefinitionManager(ActionDefinitionManager&&) noexcept = default;
|
||||
ActionDefinitionManager& operator=(ActionDefinitionManager&&) noexcept = default;
|
||||
|
||||
std::unique_ptr<Action> parseAction(const flagset<ProgramContextFlags>& context_flags,
|
||||
const expression::ParseContext& context) const;
|
||||
|
||||
static const ActionDefinitionManager& instance();
|
||||
|
||||
private:
|
||||
ActionDefinitionManager() = default;
|
||||
|
||||
void addDefinition(std::unique_ptr<ActionDefinition> def);
|
||||
|
||||
SCP_vector<std::unique_ptr<ActionDefinition>> m_definitions;
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "BuiltinActionDefinition.h"
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "ActionDefinition.h"
|
||||
|
||||
#include "expression/Value.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
template <typename TAction>
|
||||
class BuiltinActionDefinition : public ActionDefinition {
|
||||
using ActionValueType = typename TAction::ValueType;
|
||||
|
||||
public:
|
||||
BuiltinActionDefinition(SCP_string name)
|
||||
: ActionDefinition(std::move(name), {{"parameter", expression::ValueTypeTraits<ActionValueType>::type}})
|
||||
{
|
||||
}
|
||||
|
||||
flagset<ProgramContextFlags> getRequiredContext() const override
|
||||
{
|
||||
return flagset<ProgramContextFlags>(TAction::getRequiredExecutionContextFlags());
|
||||
}
|
||||
|
||||
std::unique_ptr<Action> createAction(
|
||||
const SCP_unordered_map<SCP_string, expression::ActionExpression>& parameterExpressions) const override
|
||||
{
|
||||
const auto paramIter = parameterExpressions.find("parameter");
|
||||
|
||||
// This should have been caught earlier
|
||||
Assertion(paramIter != parameterExpressions.cend(), "Could not find built-in parameter!");
|
||||
|
||||
return std::unique_ptr<Action>(new TAction(paramIter->second.template asTyped<ActionValueType>()));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,174 @@
|
||||
|
||||
#include "Program.h"
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
#include "actions/ActionDefinitionManager.h"
|
||||
#include "executor/global_executors.h"
|
||||
#include "tracing/Monitor.h"
|
||||
#include "tracing/categories.h"
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
namespace {
|
||||
using namespace actions;
|
||||
|
||||
tracing::Monitor<int> RunningProgramsMonitor("RunningPrograms", 0);
|
||||
|
||||
struct ProgramRunner {
|
||||
tracing::RunningCounter runningCounter{RunningProgramsMonitor};
|
||||
|
||||
ProgramInstance instance;
|
||||
|
||||
explicit ProgramRunner(const ProgramInstance& _instance) : instance(_instance) {}
|
||||
|
||||
executor::Executor::CallbackResult operator()()
|
||||
{
|
||||
TRACE_SCOPE(tracing::ProgramStepOne);
|
||||
|
||||
auto res = instance.step();
|
||||
|
||||
switch (res) {
|
||||
case ProgramState::Running:
|
||||
// If the program is still running then we need to reschedule our execution
|
||||
return executor::Executor::CallbackResult::Reschedule;
|
||||
case ProgramState::Done:
|
||||
case ProgramState::Errored:
|
||||
default:
|
||||
return executor::Executor::CallbackResult::Done;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace actions {
|
||||
|
||||
ProgramInstance::ProgramInstance(const actions::Program* program) : _program(program) {}
|
||||
|
||||
ProgramState ProgramInstance::step()
|
||||
{
|
||||
if (!_locals.host.IsValid()) {
|
||||
return ProgramState::Done;
|
||||
}
|
||||
|
||||
auto& actions = _program->getActions();
|
||||
|
||||
for (; _currentInstruction < actions.size(); ++_currentInstruction) {
|
||||
auto& action = actions[_currentInstruction];
|
||||
|
||||
auto result = action->execute(_locals);
|
||||
|
||||
if (result == ActionResult::Errored) {
|
||||
return ProgramState::Errored;
|
||||
}
|
||||
|
||||
if (result == ActionResult::Wait) {
|
||||
// Action is not done yet, call again next frame
|
||||
return ProgramState::Running;
|
||||
}
|
||||
|
||||
// Action finished, run next action in program
|
||||
}
|
||||
|
||||
// End of program reached, we are done now
|
||||
return ProgramState::Done;
|
||||
}
|
||||
ProgramLocals& ProgramInstance::locals()
|
||||
{
|
||||
return _locals;
|
||||
}
|
||||
const ProgramLocals& ProgramInstance::locals() const
|
||||
{
|
||||
return _locals;
|
||||
}
|
||||
|
||||
const SCP_vector<std::unique_ptr<actions::Action>>& Program::getActions() const
|
||||
{
|
||||
return _actions;
|
||||
}
|
||||
|
||||
Program::Program() = default;
|
||||
|
||||
ProgramInstance Program::newInstance() const
|
||||
{
|
||||
return ProgramInstance(this);
|
||||
}
|
||||
|
||||
void Program::parseActions(const flagset<ProgramContextFlags>& context_flags, const expression::ParseContext& context)
|
||||
{
|
||||
while (true) {
|
||||
auto action = ActionDefinitionManager::instance().parseAction(context_flags, context);
|
||||
|
||||
if (!action) {
|
||||
break;
|
||||
}
|
||||
|
||||
_actions.push_back(std::move(action));
|
||||
}
|
||||
}
|
||||
|
||||
Program::Program(const Program& other) { *this = other; }
|
||||
Program& Program::operator=(const Program& other)
|
||||
{
|
||||
_actions.clear();
|
||||
_actions.reserve(other._actions.size());
|
||||
|
||||
for (auto& action : other._actions) {
|
||||
_actions.emplace_back(action->clone());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Program& Program::operator=(Program&&) noexcept = default;
|
||||
Program::Program(Program&&) noexcept = default;
|
||||
|
||||
const SCP_vector<actions::Program>& ProgramSet::getPrograms() const
|
||||
{
|
||||
return _programs;
|
||||
}
|
||||
|
||||
ProgramSet::ProgramSet() = default;
|
||||
|
||||
ProgramSet::ProgramSet(const flagset<ProgramContextFlags>& context_flags) : _contextFlags(context_flags) {}
|
||||
|
||||
void ProgramSet::start(object* objp, const vec3d* local_pos, const matrix* local_orient, int submodel) const
|
||||
{
|
||||
if (_contextFlags[ProgramContextFlags::HasObject]) {
|
||||
Assertion(objp != nullptr, "Invalid object pointer supplied.");
|
||||
}
|
||||
if (_contextFlags[ProgramContextFlags::HasSubobject]) {
|
||||
Assertion(submodel >= 0, "Invalid subobject supplied.");
|
||||
}
|
||||
|
||||
for (const auto& prog : _programs) {
|
||||
auto instance = prog.newInstance();
|
||||
|
||||
instance.locals().host = object_h(objp);
|
||||
instance.locals().localPosition = *local_pos;
|
||||
instance.locals().localOrient = *local_orient;
|
||||
instance.locals().hostSubobject = submodel;
|
||||
instance.locals().variables = getDefaultTableVariables();
|
||||
|
||||
// Just use the executor system to take care of running this program
|
||||
executor::OnSimulationExecutor->post(ProgramRunner(instance));
|
||||
}
|
||||
}
|
||||
|
||||
ProgramSet ProgramSet::parseProgramSet(const char* tag, const flagset<ProgramContextFlags>& context_flags)
|
||||
{
|
||||
ProgramSet set(context_flags);
|
||||
|
||||
const auto parseContext = getTableParseContext();
|
||||
|
||||
while (optional_string(tag)) {
|
||||
Program p;
|
||||
p.parseActions(context_flags, parseContext);
|
||||
|
||||
set._programs.push_back(std::move(p));
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include "Action.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
class Program;
|
||||
class ProgramSet;
|
||||
|
||||
enum class ProgramState
|
||||
{
|
||||
Running,
|
||||
Done,
|
||||
Errored
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An instance of a program execution
|
||||
*
|
||||
* A program instance contains all information related to a single execution of a program. A program instance is
|
||||
* independent from other instances. Local variables used by actions are stored in a specific structure which can be
|
||||
* used by actions to keep track of state in this specific instance.
|
||||
*/
|
||||
class ProgramInstance {
|
||||
size_t _currentInstruction = 0;
|
||||
ProgramLocals _locals;
|
||||
const Program* _program = nullptr;
|
||||
|
||||
public:
|
||||
explicit ProgramInstance(const Program* program);
|
||||
|
||||
ProgramState step();
|
||||
|
||||
ProgramLocals& locals();
|
||||
const ProgramLocals& locals() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A program specified in a table
|
||||
*
|
||||
* A program is a sequential collection of Actions which are executed in sequence.
|
||||
*/
|
||||
class Program {
|
||||
SCP_vector<std::unique_ptr<Action>> _actions;
|
||||
|
||||
public:
|
||||
Program();
|
||||
|
||||
Program(const Program& other);
|
||||
Program& operator=(const Program& other);
|
||||
|
||||
Program(Program&& other) noexcept;
|
||||
Program& operator=(Program&& other) noexcept;
|
||||
|
||||
const SCP_vector<std::unique_ptr<actions::Action>>& getActions() const;
|
||||
|
||||
/**
|
||||
* @brief Creates a new program instance from this program
|
||||
*
|
||||
* The program instance is initialized to its initial values.
|
||||
*
|
||||
* @return The new program instance
|
||||
*/
|
||||
ProgramInstance newInstance() const;
|
||||
|
||||
void parseActions(const flagset<ProgramContextFlags>& context_flags, const expression::ParseContext& context);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A set of parsed programs
|
||||
*
|
||||
* Programs are parsed in sets of zero or more programs to make it possible for the content creator to split up
|
||||
* programs.
|
||||
*/
|
||||
class ProgramSet {
|
||||
flagset<ProgramContextFlags> _contextFlags;
|
||||
|
||||
SCP_vector<Program> _programs;
|
||||
|
||||
public:
|
||||
ProgramSet();
|
||||
explicit ProgramSet(const flagset<ProgramContextFlags>& context_flags);
|
||||
|
||||
const SCP_vector<actions::Program>& getPrograms() const;
|
||||
|
||||
/**
|
||||
* @brief Starts the execution of all programs within this set with the specified parameters
|
||||
* @param objp The object on which this program is executed
|
||||
* @param local_pos The local position relative to the object or the subsystem if specified
|
||||
* @param local_orien The local orientation relative to the object or the subsystem if specified
|
||||
* @param submodel The submodel of the model to which this program is attached to.
|
||||
*/
|
||||
void start(object* objp, const vec3d* local_pos, const matrix* local_orient, int submodel = -1) const;
|
||||
|
||||
/**
|
||||
* @brief Parses a program set of zero or more programs
|
||||
*
|
||||
* The tag is entirely optional and if it doesn't appear in the current table then an empty set will be returned
|
||||
* which does nothing if started.
|
||||
*
|
||||
* @param tag The tag which is required before a program can be specified
|
||||
* @param context_flags A set of flags which specify in which environment the program will be used. This is used
|
||||
* mainly for validating the used actions.
|
||||
* @return The parsed program set.
|
||||
*/
|
||||
static ProgramSet parseProgramSet(const char* tag, const flagset<ProgramContextFlags>& context_flags = {});
|
||||
};
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace actions {
|
||||
|
||||
expression::ParseContext getTableParseContext()
|
||||
{
|
||||
expression::ParseContext ctx;
|
||||
|
||||
auto& locals = ctx.variables.addScope("locals");
|
||||
|
||||
locals.addMember("position", expression::ValueType::Vector);
|
||||
locals.addMember("direction", expression::ValueType::Vector);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
expression::ProgramVariables getDefaultTableVariables()
|
||||
{
|
||||
expression::ProgramVariables vars;
|
||||
|
||||
vars.setValue({"locals", "position"}, expression::Value(vmd_zero_vector));
|
||||
vars.setValue({"locals", "direction"}, expression::Value(vmd_zero_vector));
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/flagset.h"
|
||||
|
||||
#include "actions/expression/ParseContext.h"
|
||||
#include "actions/expression/ProgramVariables.h"
|
||||
#include "math/vecmat.h"
|
||||
#include "object/object.h"
|
||||
|
||||
class object;
|
||||
class ship_subsys;
|
||||
|
||||
namespace actions {
|
||||
|
||||
struct ProgramLocals {
|
||||
object_h host;
|
||||
vec3d localPosition = vmd_zero_vector;
|
||||
matrix localOrient = vmd_identity_matrix;
|
||||
int hostSubobject = -1;
|
||||
|
||||
int waitTimestamp = 0;
|
||||
|
||||
expression::ProgramVariables variables;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A list of flags for altering the program parsing behavior
|
||||
*
|
||||
* This should be used for differentiating between different program environments when validating the program (e.g. a
|
||||
* particle effect requires an object host).
|
||||
*/
|
||||
// clang-format off
|
||||
FLAG_LIST(ProgramContextFlags) {
|
||||
HasObject = 0, //!< The program will be started with an object host
|
||||
HasSubobject, //!< The program will be started with a subobject host
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* @brief Constructs the "table" parse context
|
||||
*
|
||||
* This is the context that is available when parsing a program from an external table (e.g. ships or weapons).
|
||||
*
|
||||
* @return The parse context
|
||||
*/
|
||||
expression::ParseContext getTableParseContext();
|
||||
|
||||
/**
|
||||
* @brief Gets a program variables instance initialized with the default values
|
||||
*
|
||||
* The values are consistent with what is required for the default table parse context;
|
||||
*
|
||||
* @return The program variables
|
||||
*/
|
||||
expression::ProgramVariables getDefaultTableVariables();
|
||||
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
#include "ActionExpression.h"
|
||||
|
||||
#include "ExpressionParser.h"
|
||||
#include "TypeDefinition.h"
|
||||
|
||||
#include "actions/expression/nodes/AbstractExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace {
|
||||
|
||||
SCP_string getTypeName(ValueType type)
|
||||
{
|
||||
const auto& typeDef = TypeDefinition::forValueType(type);
|
||||
return typeDef.getName();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ActionExpression ActionExpression::parseFromTable(ValueType expectedReturnType, const ParseContext& context)
|
||||
{
|
||||
SCP_string expressionText;
|
||||
|
||||
stuff_string(expressionText, F_NAME);
|
||||
|
||||
ExpressionParser parser(expressionText);
|
||||
|
||||
auto expression = parser.parse(context);
|
||||
|
||||
if (!expression) {
|
||||
error_display(0, "Failed to parse action expression:\n%s", parser.getErrorText().c_str());
|
||||
return ActionExpression();
|
||||
}
|
||||
|
||||
auto type = expression->getExpressionType();
|
||||
|
||||
// Check if the type this evaluates to matches what we expect
|
||||
if (!checkTypeWithImplicitConversion(type, expectedReturnType)) {
|
||||
error_display(0,
|
||||
"Expression evaluates to type <%s> but <%s> was expected!",
|
||||
getTypeName(type).c_str(),
|
||||
getTypeName(expectedReturnType).c_str());
|
||||
return ActionExpression();
|
||||
}
|
||||
|
||||
// Everything is valid
|
||||
return ActionExpression(expression);
|
||||
}
|
||||
|
||||
Value ActionExpression::execute(const ProgramVariables& variables) const
|
||||
{
|
||||
// Do not crash on invalid expressions
|
||||
if (!isValid()) {
|
||||
return Value();
|
||||
}
|
||||
|
||||
return m_expression->execute(variables);
|
||||
}
|
||||
bool ActionExpression::isValid() const
|
||||
{
|
||||
return m_expression != nullptr;
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "ParseContext.h"
|
||||
#include "ProgramVariables.h"
|
||||
#include "TypeDefinition.h"
|
||||
|
||||
#include "parse/parselo.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
class AbstractExpression;
|
||||
}
|
||||
template <typename T>
|
||||
class TypedActionExpression;
|
||||
|
||||
class ActionExpression {
|
||||
public:
|
||||
ActionExpression() = default;
|
||||
|
||||
Value execute(const ProgramVariables& variables) const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
template <typename T>
|
||||
TypedActionExpression<T> asTyped() const;
|
||||
|
||||
static ActionExpression parseFromTable(ValueType expectedReturnType, const ParseContext& context);
|
||||
|
||||
protected:
|
||||
explicit ActionExpression(std::shared_ptr<nodes::AbstractExpression> expression)
|
||||
: m_expression(std::move(expression))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<nodes::AbstractExpression> m_expression;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedActionExpression {
|
||||
public:
|
||||
explicit TypedActionExpression(ActionExpression expression) : m_expression(std::move(expression)) {}
|
||||
|
||||
T execute(const ProgramVariables& variables) const
|
||||
{
|
||||
// Do not crash on invalid expressions
|
||||
if (!m_expression.isValid()) {
|
||||
return T();
|
||||
}
|
||||
|
||||
return m_expression.execute(variables).template get<T>();
|
||||
}
|
||||
|
||||
static TypedActionExpression<T> parseFromTable(const ParseContext& context)
|
||||
{
|
||||
return ActionExpression::parseFromTable(ValueTypeTraits<T>::type, context).template asTyped<T>();
|
||||
}
|
||||
|
||||
private:
|
||||
ActionExpression m_expression;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
TypedActionExpression<T> ActionExpression::asTyped() const
|
||||
{
|
||||
return TypedActionExpression<T>(*this);
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,194 @@
|
||||
|
||||
#include "ExpressionParser.h"
|
||||
|
||||
#include "actions/expression/nodes/FunctionCallExpression.h"
|
||||
#include "actions/expression/nodes/LiteralExpression.h"
|
||||
#include "actions/expression/nodes/RandomRangeExpression.h"
|
||||
#include "actions/expression/nodes/VariableReferenceExpression.h"
|
||||
#include "actions/expression/nodes/VectorConstructorExpression.h"
|
||||
#include "libs/antlr/ErrorListener.h"
|
||||
|
||||
PUSH_SUPPRESS_WARNINGS
|
||||
#include "action_expression/generated/ActionExpressionLexer.h"
|
||||
#include "action_expression/generated/ActionExpressionParser.h"
|
||||
#include "action_expression/generated/ActionExpressionVisitor.h"
|
||||
POP_SUPPRESS_WARNINGS
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
namespace {
|
||||
|
||||
class ExpressionBuilderVisitor : public ActionExpressionVisitor {
|
||||
public:
|
||||
antlrcpp::Any visitExpression_main(ActionExpressionParser::Expression_mainContext* context) override
|
||||
{
|
||||
return visit(context->expression());
|
||||
}
|
||||
antlrcpp::Any visitExpression(ActionExpressionParser::ExpressionContext* context) override
|
||||
{
|
||||
if (context->value_expression() != nullptr) {
|
||||
return visit(context->value_expression());
|
||||
}
|
||||
if (context->parenthesis_expression()) {
|
||||
return visit(context->parenthesis_expression());
|
||||
}
|
||||
if (context->random_range_expression()) {
|
||||
return visit(context->random_range_expression());
|
||||
}
|
||||
if (context->variable_reference_expression()) {
|
||||
return visit(context->variable_reference_expression());
|
||||
}
|
||||
|
||||
// This is an operator so treat it as one.
|
||||
antlr4::Token* operatorTok;
|
||||
SCP_string operatorText;
|
||||
if (context->PLUS() != nullptr) {
|
||||
operatorTok = context->PLUS()->getSymbol();
|
||||
operatorText = context->PLUS()->getText();
|
||||
} else {
|
||||
operatorTok = context->MINUS()->getSymbol();
|
||||
operatorText = context->MINUS()->getText();
|
||||
}
|
||||
|
||||
const auto leftExpr = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
const auto rightExpr = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto operatorExpression = std::make_shared<nodes::FunctionCallExpression>(operatorTok,
|
||||
true,
|
||||
std::move(operatorText),
|
||||
SCP_vector<std::shared_ptr<nodes::AbstractExpression>>{leftExpr, rightExpr});
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(operatorExpression);
|
||||
}
|
||||
antlrcpp::Any visitVariable_reference_expression(
|
||||
ActionExpressionParser::Variable_reference_expressionContext* context) override
|
||||
{
|
||||
const auto identifiers = context->IDENTIFIER();
|
||||
|
||||
SCP_vector<SCP_string> partNames;
|
||||
partNames.reserve(identifiers.size());
|
||||
|
||||
std::transform(identifiers.begin(),
|
||||
identifiers.end(),
|
||||
std::back_inserter(partNames),
|
||||
[](antlr4::tree::TerminalNode* node) { return node->getText(); });
|
||||
|
||||
SCP_vector<antlr4::Token*> partTokens;
|
||||
partTokens.reserve(identifiers.size());
|
||||
|
||||
std::transform(identifiers.begin(),
|
||||
identifiers.end(),
|
||||
std::back_inserter(partTokens),
|
||||
[](antlr4::tree::TerminalNode* node) { return node->getSymbol(); });
|
||||
|
||||
auto expression =
|
||||
std::make_shared<nodes::VariableReferenceExpression>(std::move(partNames), std::move(partTokens));
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
|
||||
}
|
||||
antlrcpp::Any visitRandom_range_expression(ActionExpressionParser::Random_range_expressionContext* context) override
|
||||
{
|
||||
auto expression = std::make_shared<nodes::RandomRangeExpression>(context->RAND_L_PAREN()->getSymbol(),
|
||||
visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>(),
|
||||
visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>());
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
|
||||
}
|
||||
antlrcpp::Any visitLiteral_expression(ActionExpressionParser::Literal_expressionContext* context) override
|
||||
{
|
||||
std::shared_ptr<nodes::LiteralExpression> expression;
|
||||
|
||||
if (context->FLOAT() != nullptr) {
|
||||
expression = std::make_shared<nodes::LiteralExpression>(context->FLOAT()->getSymbol(),
|
||||
Value(std::stof(context->FLOAT()->getText())));
|
||||
} else if (context->INT() != nullptr) {
|
||||
expression = std::make_shared<nodes::LiteralExpression>(context->INT()->getSymbol(),
|
||||
Value(std::stoi(context->INT()->getText())));
|
||||
} else {
|
||||
const auto idText = context->STRING()->getText();
|
||||
|
||||
// Cut off the first and last characters since those are the < > braces
|
||||
expression = std::make_shared<nodes::LiteralExpression>(context->STRING()->getSymbol(),
|
||||
Value(idText.substr(1, idText.size() - 2)));
|
||||
}
|
||||
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
|
||||
}
|
||||
antlrcpp::Any visitParenthesis_expression(ActionExpressionParser::Parenthesis_expressionContext* context) override
|
||||
{
|
||||
return visit(context->expression());
|
||||
}
|
||||
antlrcpp::Any visitValue_expression(ActionExpressionParser::Value_expressionContext* context) override
|
||||
{
|
||||
return visitChildren(context);
|
||||
}
|
||||
antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext* context) override
|
||||
{
|
||||
auto xExpression = visit(context->expression(0)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
auto yExpression = visit(context->expression(1)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
auto zExpression = visit(context->expression(2)).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
auto expression = std::make_shared<nodes::VectorConstructorExpression>(context->L_PAREN()->getSymbol(),
|
||||
xExpression,
|
||||
yExpression,
|
||||
zExpression);
|
||||
|
||||
return std::static_pointer_cast<nodes::AbstractExpression>(expression);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ExpressionParser::ExpressionParser(SCP_string expressionText) : m_expressionText(std::move(expressionText)) {}
|
||||
|
||||
std::shared_ptr<nodes::AbstractExpression> ExpressionParser::parse(const ParseContext& context)
|
||||
{
|
||||
antlr4::ANTLRInputStream input(m_expressionText);
|
||||
ActionExpressionLexer lexer(&input);
|
||||
antlr4::CommonTokenStream tokens(&lexer);
|
||||
|
||||
::ActionExpressionParser parser(&tokens);
|
||||
// By default we log to stderr which we do not want
|
||||
parser.removeErrorListeners();
|
||||
libs::antlr::ErrorListener errListener;
|
||||
parser.addErrorListener(&errListener);
|
||||
|
||||
antlr4::tree::ParseTree* tree = parser.expression_main();
|
||||
|
||||
std::shared_ptr<nodes::AbstractExpression> exprReturn;
|
||||
if (errListener.diagnostics.empty()) {
|
||||
// Only do semantic checking if syntax is valid
|
||||
ExpressionBuilderVisitor builder;
|
||||
exprReturn = tree->accept(&builder).as<std::shared_ptr<nodes::AbstractExpression>>();
|
||||
|
||||
if (!exprReturn->validate(&parser, context)) {
|
||||
exprReturn = nullptr;
|
||||
} else {
|
||||
exprReturn->validationDone();
|
||||
}
|
||||
}
|
||||
|
||||
if (!errListener.diagnostics.empty()) {
|
||||
SCP_stringstream outStream;
|
||||
for (const auto& diag : errListener.diagnostics) {
|
||||
SCP_string tokenUnderline;
|
||||
if (diag.tokenLength > 1) {
|
||||
tokenUnderline = SCP_string(diag.tokenLength - 1, '~');
|
||||
}
|
||||
outStream << m_expressionText << "\n"
|
||||
<< SCP_string(diag.columnInLine, ' ') << "^" << tokenUnderline << "\n"
|
||||
<< diag.errorMessage << "\n";
|
||||
}
|
||||
|
||||
m_errorText = outStream.str();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return exprReturn;
|
||||
}
|
||||
|
||||
const SCP_string& ExpressionParser::getErrorText() const
|
||||
{
|
||||
return m_errorText;
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include "ParseContext.h"
|
||||
|
||||
#include "actions/expression/nodes/AbstractExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
class ExpressionParser {
|
||||
public:
|
||||
ExpressionParser(SCP_string expressionText);
|
||||
|
||||
std::shared_ptr<nodes::AbstractExpression> parse(const ParseContext& context);
|
||||
|
||||
const SCP_string& getErrorText() const;
|
||||
|
||||
private:
|
||||
SCP_string m_expressionText;
|
||||
|
||||
SCP_string m_errorText;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
#include "FunctionManager.h"
|
||||
|
||||
#include "TypeDefinition.h"
|
||||
|
||||
#include "math/vecmat.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace {
|
||||
template <typename T>
|
||||
Value value_plus(const SCP_vector<Value>& parameters)
|
||||
{
|
||||
return Value(parameters[0].get<T>() + parameters[1].get<T>());
|
||||
}
|
||||
template <typename T>
|
||||
Value value_minus(const SCP_vector<Value>& parameters)
|
||||
{
|
||||
return Value(parameters[0].get<T>() - parameters[1].get<T>());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
const FunctionManager& FunctionManager::instance()
|
||||
{
|
||||
static const FunctionManager manager = []() {
|
||||
FunctionManager newManager;
|
||||
|
||||
newManager.addOperator("+", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_plus<int>);
|
||||
newManager.addOperator("+", {ValueType::Float, ValueType::Float}, ValueType::Float, value_plus<float>);
|
||||
newManager.addOperator("+", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_plus<vec3d>);
|
||||
|
||||
newManager.addOperator("-", {ValueType::Integer, ValueType::Integer}, ValueType::Integer, value_minus<int>);
|
||||
newManager.addOperator("-", {ValueType::Float, ValueType::Float}, ValueType::Float, value_minus<float>);
|
||||
newManager.addOperator("-", {ValueType::Vector, ValueType::Vector}, ValueType::Vector, value_minus<vec3d>);
|
||||
|
||||
return newManager;
|
||||
}();
|
||||
return manager;
|
||||
}
|
||||
void FunctionManager::addOperator(const SCP_string& name,
|
||||
std::initializer_list<ValueType> parameterTypes,
|
||||
ValueType returnType,
|
||||
FunctionImplementation implementation)
|
||||
{
|
||||
m_operators[name].push_back({name, parameterTypes, returnType, std::move(implementation)});
|
||||
}
|
||||
const FunctionDefinition* FunctionManager::findOperator(const SCP_string& name,
|
||||
const SCP_vector<ValueType>& parameters) const
|
||||
{
|
||||
const auto iter = m_operators.find(name);
|
||||
|
||||
if (iter == m_operators.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Prefer exact matches
|
||||
for (const auto& funcDef : iter->second) {
|
||||
if (funcDef.parameterTypes == parameters) {
|
||||
return &funcDef;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check if there are matches with implicit conversions
|
||||
for (const auto& funcDef : iter->second) {
|
||||
// Reject functions with different amount of elements
|
||||
if (funcDef.parameterTypes.size() != parameters.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto funcParamIter = funcDef.parameterTypes.cbegin();
|
||||
auto actualParamIter = parameters.cbegin();
|
||||
|
||||
bool match = true;
|
||||
for (; funcParamIter != funcDef.parameterTypes.cend(); ++funcParamIter, ++actualParamIter) {
|
||||
if (!checkTypeWithImplicitConversion(*actualParamIter, *funcParamIter)) {
|
||||
// Also doesn't match with implicit conversions
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
return &funcDef;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FunctionManager::FunctionManager() = default;
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "Value.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
using FunctionImplementation = std::function<Value(const SCP_vector<Value>& parameters)>;
|
||||
|
||||
struct FunctionDefinition {
|
||||
SCP_string name;
|
||||
|
||||
SCP_vector<ValueType> parameterTypes;
|
||||
|
||||
ValueType returnType;
|
||||
|
||||
FunctionImplementation implementation;
|
||||
};
|
||||
|
||||
class FunctionManager {
|
||||
public:
|
||||
// This type is supposed to be global so it may not be copied
|
||||
FunctionManager(const FunctionManager&) = delete;
|
||||
FunctionManager& operator=(const FunctionManager&) = delete;
|
||||
|
||||
FunctionManager(FunctionManager&&) noexcept = default;
|
||||
FunctionManager& operator=(FunctionManager&&) noexcept = default;
|
||||
|
||||
void addOperator(const SCP_string& name,
|
||||
std::initializer_list<ValueType> parameterTypes,
|
||||
ValueType returnType,
|
||||
FunctionImplementation implementation);
|
||||
|
||||
const FunctionDefinition* findOperator(const SCP_string& name, const SCP_vector<ValueType>& parameterTypes) const;
|
||||
|
||||
static const FunctionManager& instance();
|
||||
|
||||
private:
|
||||
FunctionManager();
|
||||
|
||||
SCP_unordered_map<SCP_string, SCP_vector<FunctionDefinition>> m_operators;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "ProgramVariables.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
struct ParseContext {
|
||||
ProgramVariablesDefinition variables;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
#include "ProgramVariables.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
ProgramVariablesDefinition& ProgramVariablesDefinition::addScope(const SCP_string& name)
|
||||
{
|
||||
auto scope = std::unique_ptr<ProgramVariablesDefinition>(new ProgramVariablesDefinition());
|
||||
|
||||
auto scopePtr = scope.get();
|
||||
|
||||
m_scopes.insert(std::make_pair(name, std::move(scope)));
|
||||
|
||||
return *scopePtr;
|
||||
}
|
||||
void ProgramVariablesDefinition::addMember(const SCP_string& name, ValueType type)
|
||||
{
|
||||
m_memberTypes[name] = type;
|
||||
}
|
||||
ProgramVariablesDefinition* ProgramVariablesDefinition::getScope(const SCP_string& name) const
|
||||
{
|
||||
const auto iter = m_scopes.find(name);
|
||||
|
||||
if (iter == m_scopes.cend()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return iter->second.get();
|
||||
}
|
||||
ValueType ProgramVariablesDefinition::getMemberType(const SCP_string& name) const
|
||||
{
|
||||
const auto iter = m_memberTypes.find(name);
|
||||
|
||||
if (iter == m_memberTypes.cend()) {
|
||||
return ValueType::Invalid;
|
||||
}
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
Value ProgramVariables::getValue(std::initializer_list<const char*> memberPathParts) const
|
||||
{
|
||||
return getValue<decltype(memberPathParts)>(memberPathParts);
|
||||
}
|
||||
void ProgramVariables::setValue(std::initializer_list<const char*> memberPathParts, Value value)
|
||||
{
|
||||
setValue<decltype(memberPathParts)>(memberPathParts, std::move(value));
|
||||
}
|
||||
Value ProgramVariables::getValue(const SCP_string& fullMemberName) const
|
||||
{
|
||||
const auto iter = m_values.find(fullMemberName);
|
||||
|
||||
// This should have been validated earlier
|
||||
Assertion(iter != m_values.end(), "Could not find member %s in variables!", fullMemberName.c_str());
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "Value.h"
|
||||
|
||||
#include "utils/join_string.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
struct ProgramVariables {
|
||||
public:
|
||||
template <typename TContainer>
|
||||
static SCP_string getMemberName(const TContainer& memberPathParts)
|
||||
{
|
||||
return util::join_container(memberPathParts, ".");
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
Value getValue(const TContainer& memberPathParts) const
|
||||
{
|
||||
const auto name = getMemberName(memberPathParts);
|
||||
|
||||
return getValue(name);
|
||||
}
|
||||
|
||||
Value getValue(std::initializer_list<const char*> memberPathParts) const;
|
||||
|
||||
Value getValue(const SCP_string& fullMemberName) const;
|
||||
|
||||
template <typename TContainer>
|
||||
void setValue(const TContainer& memberPathParts, Value value)
|
||||
{
|
||||
const auto name = getMemberName(memberPathParts);
|
||||
|
||||
m_values[name] = std::move(value);
|
||||
}
|
||||
|
||||
void setValue(std::initializer_list<const char*> memberPathParts, Value value);
|
||||
|
||||
private:
|
||||
SCP_unordered_map<SCP_string, Value> m_values;
|
||||
};
|
||||
|
||||
class ProgramVariablesDefinition {
|
||||
public:
|
||||
ProgramVariablesDefinition& addScope(const SCP_string& name);
|
||||
|
||||
void addMember(const SCP_string& name, ValueType type);
|
||||
|
||||
ProgramVariablesDefinition* getScope(const SCP_string& name) const;
|
||||
|
||||
ValueType getMemberType(const SCP_string& name) const;
|
||||
|
||||
private:
|
||||
SCP_unordered_map<SCP_string, std::unique_ptr<ProgramVariablesDefinition>> m_scopes;
|
||||
|
||||
SCP_unordered_map<SCP_string, ValueType> m_memberTypes;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
#include "TypeDefinition.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
// Integers can be safely converted to floats (for the most part)
|
||||
TypeDefinition TypeDefinition::s_integer("Integer", {ValueType::Float});
|
||||
// No implicit conversions here
|
||||
TypeDefinition TypeDefinition::s_float("Float", {});
|
||||
TypeDefinition TypeDefinition::s_vector("Vector", {});
|
||||
// Identifiers are a technicality needed for making non-math values work but they have no further use other than their
|
||||
// string content
|
||||
TypeDefinition TypeDefinition::s_identifier("Identifier", {});
|
||||
|
||||
TypeDefinition::TypeDefinition(SCP_string name, SCP_vector<actions::expression::ValueType> allowedImplicitConversion)
|
||||
: m_name(std::move(name)), m_allowedImplicitConversions(std::move(allowedImplicitConversion))
|
||||
{
|
||||
}
|
||||
|
||||
const SCP_string& TypeDefinition::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
const SCP_vector<actions::expression::ValueType>& TypeDefinition::getAllowedImplicitConversions() const
|
||||
{
|
||||
return m_allowedImplicitConversions;
|
||||
}
|
||||
const TypeDefinition& TypeDefinition::forValueType(ValueType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ValueType::Integer:
|
||||
return s_integer;
|
||||
case ValueType::Float:
|
||||
return s_float;
|
||||
case ValueType::Vector:
|
||||
return s_vector;
|
||||
case ValueType::String:
|
||||
return s_identifier;
|
||||
default:
|
||||
UNREACHABLE("Invalid value type!");
|
||||
return s_integer; // Make compiler happy
|
||||
}
|
||||
}
|
||||
|
||||
bool checkTypeWithImplicitConversion(ValueType currentType, ValueType expectedType)
|
||||
{
|
||||
if (currentType == expectedType) {
|
||||
// No need to consider implicit conversions;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& currentTypeDef = TypeDefinition::forValueType(currentType);
|
||||
const auto& allowedConversions = currentTypeDef.getAllowedImplicitConversions();
|
||||
|
||||
// For now, no transitiv conversions are allowed
|
||||
return std::find(allowedConversions.cbegin(), allowedConversions.cend(), expectedType) != allowedConversions.cend();
|
||||
}
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "Value.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
class TypeDefinition {
|
||||
public:
|
||||
TypeDefinition(SCP_string name, SCP_vector<actions::expression::ValueType> allowedImplicitConversion);
|
||||
|
||||
const SCP_string& getName() const;
|
||||
|
||||
const SCP_vector<actions::expression::ValueType>& getAllowedImplicitConversions() const;
|
||||
|
||||
static const TypeDefinition& forValueType(ValueType type);
|
||||
|
||||
// This type is supposed to be global so it may not be copied
|
||||
TypeDefinition(const TypeDefinition&) = delete;
|
||||
TypeDefinition& operator=(const TypeDefinition&) = delete;
|
||||
|
||||
TypeDefinition(TypeDefinition&&) = delete;
|
||||
TypeDefinition& operator=(TypeDefinition&&) = delete;
|
||||
|
||||
private:
|
||||
SCP_string m_name;
|
||||
|
||||
// The types this type is allowed to implicitly convert to
|
||||
SCP_vector<ValueType> m_allowedImplicitConversions;
|
||||
|
||||
static TypeDefinition s_integer;
|
||||
static TypeDefinition s_float;
|
||||
static TypeDefinition s_vector;
|
||||
static TypeDefinition s_identifier;
|
||||
};
|
||||
|
||||
bool checkTypeWithImplicitConversion(ValueType currentType, ValueType expectedType);
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
#include "Value.h"
|
||||
#include "math/vecmat.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
Value::Value(int val) : m_value(val) {}
|
||||
Value::Value(float val) : m_value(val) {}
|
||||
Value::Value(const vec3d& val) : m_value(val) {}
|
||||
Value::Value(SCP_string val) : m_value(std::move(val)) {}
|
||||
|
||||
ValueType actions::expression::Value::getType() const
|
||||
{
|
||||
switch (m_value.index()) {
|
||||
case 1:
|
||||
return ValueType::Integer;
|
||||
case 2:
|
||||
return ValueType::Float;
|
||||
case 3:
|
||||
return ValueType::Vector;
|
||||
case 4:
|
||||
return ValueType::String;
|
||||
default:
|
||||
return ValueType::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
int Value::getInteger() const
|
||||
{
|
||||
return get<int>();
|
||||
}
|
||||
float Value::getFloat() const
|
||||
{
|
||||
return get<float>();
|
||||
}
|
||||
vec3d Value::getVector() const
|
||||
{
|
||||
return get<vec3d>();
|
||||
}
|
||||
SCP_string Value::getIdentifier() const
|
||||
{
|
||||
return get<SCP_string>();
|
||||
}
|
||||
bool operator==(const Value& lhs, const Value& rhs)
|
||||
{
|
||||
return lhs.m_value == rhs.m_value;
|
||||
}
|
||||
bool operator!=(const Value& lhs, const Value& rhs)
|
||||
{
|
||||
return !(rhs == lhs);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, const Value& value)
|
||||
{
|
||||
os << "Value<";
|
||||
|
||||
switch (value.getType()) {
|
||||
case ValueType::Invalid:
|
||||
os << "INVALID";
|
||||
break;
|
||||
case ValueType::Integer:
|
||||
os << value.get<int>();
|
||||
break;
|
||||
case ValueType::Float:
|
||||
os << value.get<float>();
|
||||
break;
|
||||
case ValueType::Vector:
|
||||
os << value.get<vec3d>();
|
||||
break;
|
||||
case ValueType::String:
|
||||
os << value.get<SCP_string>();
|
||||
break;
|
||||
}
|
||||
|
||||
os << ">";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include <mpark/variant.hpp>
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
|
||||
namespace detail {
|
||||
template <typename ToType>
|
||||
struct implicit_conversion {
|
||||
template <typename T>
|
||||
ToType operator()(const T&)
|
||||
{
|
||||
throw std::runtime_error("Invalid implicit conversion.");
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct implicit_conversion<float> {
|
||||
inline float operator()(int val) {
|
||||
return i2fl(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float operator()(const T&)
|
||||
{
|
||||
throw std::runtime_error("Invalid implicit conversion.");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
enum class ValueType
|
||||
{
|
||||
Invalid,
|
||||
Integer,
|
||||
Float,
|
||||
Vector,
|
||||
String,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ValueTypeTraits;
|
||||
|
||||
template <>
|
||||
struct ValueTypeTraits<int> {
|
||||
static constexpr ValueType type = ValueType::Integer;
|
||||
};
|
||||
template <>
|
||||
struct ValueTypeTraits<float> {
|
||||
static constexpr ValueType type = ValueType::Float;
|
||||
};
|
||||
template <>
|
||||
struct ValueTypeTraits<vec3d> {
|
||||
static constexpr ValueType type = ValueType::Vector;
|
||||
};
|
||||
template <>
|
||||
struct ValueTypeTraits<SCP_string> {
|
||||
static constexpr ValueType type = ValueType::String;
|
||||
};
|
||||
|
||||
class Value {
|
||||
public:
|
||||
Value() = default;
|
||||
|
||||
explicit Value(int val);
|
||||
explicit Value(float val);
|
||||
explicit Value(const vec3d& val);
|
||||
explicit Value(SCP_string val);
|
||||
|
||||
ValueType getType() const;
|
||||
|
||||
int getInteger() const;
|
||||
float getFloat() const;
|
||||
vec3d getVector() const;
|
||||
SCP_string getIdentifier() const;
|
||||
|
||||
template <typename T>
|
||||
T get() const
|
||||
{
|
||||
const auto currentType = getType();
|
||||
const auto expectedType = ValueTypeTraits<T>::type;
|
||||
|
||||
if (currentType == expectedType) {
|
||||
// No conversion necessary
|
||||
return mpark::get<T>(m_value);
|
||||
}
|
||||
|
||||
return mpark::visit(detail::implicit_conversion<T>{}, m_value);
|
||||
}
|
||||
|
||||
friend bool operator==(const Value& lhs, const Value& rhs);
|
||||
friend bool operator!=(const Value& lhs, const Value& rhs);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Value& value);
|
||||
|
||||
private:
|
||||
mpark::variant<mpark::monostate, int, float, vec3d, SCP_string> m_value;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#include "AbstractExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
AbstractExpression::AbstractExpression(antlr4::Token* token) : m_token(token) {}
|
||||
AbstractExpression::~AbstractExpression() = default;
|
||||
|
||||
antlr4::Token* AbstractExpression::getToken() const
|
||||
{
|
||||
return m_token;
|
||||
}
|
||||
ValueType AbstractExpression::getExpressionType() const
|
||||
{
|
||||
// Since expressions are immutable, caching this will be more efficient
|
||||
if (m_cachedType == ValueType::Invalid) {
|
||||
m_cachedType = determineReturnType();
|
||||
}
|
||||
return m_cachedType;
|
||||
}
|
||||
void AbstractExpression::validationDone()
|
||||
{
|
||||
// This pointer will become invalid after this so reset it now to avoid issues
|
||||
m_token = nullptr;
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/expression/ParseContext.h"
|
||||
#include "actions/expression/Value.h"
|
||||
|
||||
#include <Parser.h>
|
||||
#include <Token.h>
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
class AbstractExpression {
|
||||
public:
|
||||
AbstractExpression(antlr4::Token* token);
|
||||
virtual ~AbstractExpression();
|
||||
|
||||
virtual Value execute(const ProgramVariables& variables) const = 0;
|
||||
|
||||
virtual bool validate(antlr4::Parser* parser, const ParseContext& context) = 0;
|
||||
|
||||
virtual void validationDone();
|
||||
|
||||
ValueType getExpressionType() const;
|
||||
|
||||
antlr4::Token* getToken() const;
|
||||
|
||||
protected:
|
||||
virtual ValueType determineReturnType() const = 0;
|
||||
|
||||
antlr4::Token* m_token = nullptr;
|
||||
|
||||
mutable ValueType m_cachedType = ValueType::Invalid;
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,95 @@
|
||||
|
||||
#include "FunctionCallExpression.h"
|
||||
|
||||
#include "actions/expression/TypeDefinition.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
FunctionCallExpression::FunctionCallExpression(antlr4::Token* token,
|
||||
bool isOperator,
|
||||
SCP_string functionName,
|
||||
SCP_vector<std::shared_ptr<AbstractExpression>> parameterExpressions)
|
||||
: AbstractExpression(token), m_isOperator(isOperator), m_functionName(std::move(functionName)),
|
||||
m_parameterExpressions(std::move(parameterExpressions))
|
||||
{
|
||||
}
|
||||
FunctionCallExpression::~FunctionCallExpression() = default;
|
||||
|
||||
Value FunctionCallExpression::execute(const ProgramVariables& variables) const
|
||||
{
|
||||
SCP_vector<Value> parameterValues;
|
||||
parameterValues.reserve(m_parameterExpressions.size());
|
||||
|
||||
std::transform(m_parameterExpressions.cbegin(),
|
||||
m_parameterExpressions.cend(),
|
||||
std::back_inserter(parameterValues),
|
||||
[&variables](const std::shared_ptr<AbstractExpression>& expression) { return expression->execute(variables); });
|
||||
|
||||
return m_functionDef->implementation(parameterValues);
|
||||
}
|
||||
bool FunctionCallExpression::validate(antlr4::Parser* parser, const ParseContext& context)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
for (const auto& paramExpression : m_parameterExpressions) {
|
||||
valid &= paramExpression->validate(parser, context);
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
// Exit early if there were errors since the values below are meaningless otherwise
|
||||
return false;
|
||||
}
|
||||
|
||||
Assertion(m_isOperator, "Non-operator functions are not supported yet!");
|
||||
|
||||
SCP_vector<ValueType> parameterTypes;
|
||||
|
||||
std::transform(m_parameterExpressions.cbegin(),
|
||||
m_parameterExpressions.cend(),
|
||||
std::back_inserter(parameterTypes),
|
||||
[](const std::shared_ptr<AbstractExpression>& expression) { return expression->getExpressionType(); });
|
||||
|
||||
const auto functionDef = FunctionManager::instance().findOperator(m_functionName, parameterTypes);
|
||||
|
||||
if (functionDef == nullptr) {
|
||||
SCP_stringstream paramListStream;
|
||||
if (!parameterTypes.empty()) {
|
||||
paramListStream << "<" << TypeDefinition::forValueType(parameterTypes.front()).getName() << ">";
|
||||
|
||||
for (auto iter = parameterTypes.cbegin() + 1; iter != parameterTypes.cend(); ++iter) {
|
||||
paramListStream << ", <" << TypeDefinition::forValueType(*iter).getName() << ">";
|
||||
}
|
||||
}
|
||||
|
||||
parser->notifyErrorListeners(m_token,
|
||||
SCP_string("Could not find a definition for the ") + (m_isOperator ? "operator" : "function") + " '" +
|
||||
m_functionName + "' with parameters (" + paramListStream.str() + ")",
|
||||
nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_functionDef = functionDef;
|
||||
return true;
|
||||
}
|
||||
ValueType FunctionCallExpression::determineReturnType() const
|
||||
{
|
||||
return m_functionDef->returnType;
|
||||
}
|
||||
void FunctionCallExpression::validationDone()
|
||||
{
|
||||
AbstractExpression::validationDone();
|
||||
|
||||
// We no longer need this so we can save some memory
|
||||
m_functionName.clear();
|
||||
m_functionName.shrink_to_fit();
|
||||
|
||||
for (const auto& paramExpression : m_parameterExpressions) {
|
||||
paramExpression->validationDone();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractExpression.h"
|
||||
|
||||
#include "actions/expression/FunctionManager.h"
|
||||
#include "actions/expression/Value.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
class FunctionCallExpression : public AbstractExpression {
|
||||
public:
|
||||
FunctionCallExpression(antlr4::Token* token,
|
||||
bool isOperator,
|
||||
SCP_string functionName,
|
||||
SCP_vector<std::shared_ptr<AbstractExpression>> parameterExpressions);
|
||||
~FunctionCallExpression() override;
|
||||
|
||||
Value execute(const ProgramVariables& variables) const override;
|
||||
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
|
||||
void validationDone() override;
|
||||
|
||||
protected:
|
||||
ValueType determineReturnType() const override;
|
||||
|
||||
private:
|
||||
bool m_isOperator;
|
||||
SCP_string m_functionName;
|
||||
|
||||
const FunctionDefinition* m_functionDef = nullptr;
|
||||
|
||||
SCP_vector<std::shared_ptr<AbstractExpression>> m_parameterExpressions;
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#include "LiteralExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
LiteralExpression::LiteralExpression(antlr4::Token* token, Value literalValue)
|
||||
: AbstractExpression(token), m_literalValue(std::move(literalValue))
|
||||
{
|
||||
}
|
||||
LiteralExpression::~LiteralExpression() = default;
|
||||
|
||||
Value LiteralExpression::execute(const ProgramVariables& /*variables*/) const
|
||||
{
|
||||
return m_literalValue;
|
||||
}
|
||||
bool LiteralExpression::validate(antlr4::Parser* /*parser*/, const ParseContext& /*context*/)
|
||||
{
|
||||
// Literals are always valid
|
||||
return true;
|
||||
}
|
||||
ValueType LiteralExpression::determineReturnType() const
|
||||
{
|
||||
return m_literalValue.getType();
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractExpression.h"
|
||||
|
||||
#include "actions/expression/Value.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
class LiteralExpression : public AbstractExpression {
|
||||
public:
|
||||
LiteralExpression(antlr4::Token* token, Value literalValue);
|
||||
~LiteralExpression() override;
|
||||
|
||||
Value execute(const ProgramVariables& variables) const override;
|
||||
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
|
||||
|
||||
protected:
|
||||
ValueType determineReturnType() const override;
|
||||
|
||||
private:
|
||||
Value m_literalValue;
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,108 @@
|
||||
|
||||
#include "RandomRangeExpression.h"
|
||||
|
||||
#include "actions/expression/TypeDefinition.h"
|
||||
#include "utils/RandomRange.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
Value executeHelper(const Value& leftVal, const Value& rightVal)
|
||||
{
|
||||
auto leftContentVal = leftVal.get<T>();
|
||||
auto rightContentVal = rightVal.get<T>();
|
||||
|
||||
if (leftContentVal == rightContentVal) {
|
||||
// no need to do random stuff here
|
||||
return Value(rightContentVal);
|
||||
}
|
||||
|
||||
if (rightContentVal < leftContentVal) {
|
||||
// We can fix this issue
|
||||
std::swap(leftContentVal, rightContentVal);
|
||||
}
|
||||
|
||||
// Might be a bit inefficient not to cache this somehow but the bounds can be dynamic
|
||||
return Value(util::UniformRange<T>(leftContentVal, rightContentVal).next());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RandomRangeExpression::RandomRangeExpression(antlr4::Token* token,
|
||||
std::shared_ptr<AbstractExpression> leftExpression,
|
||||
std::shared_ptr<AbstractExpression> rightExpression)
|
||||
: AbstractExpression(token), m_leftExpression(std::move(leftExpression)),
|
||||
m_rightExpression(std::move(rightExpression))
|
||||
{
|
||||
}
|
||||
RandomRangeExpression::~RandomRangeExpression() = default;
|
||||
|
||||
Value RandomRangeExpression::execute(const ProgramVariables& variables) const
|
||||
{
|
||||
const auto leftVal = m_leftExpression->execute(variables);
|
||||
const auto rightVal = m_rightExpression->execute(variables);
|
||||
|
||||
if (leftVal.getType() == ValueType::Integer) {
|
||||
return executeHelper<int>(leftVal, rightVal);
|
||||
} else {
|
||||
return executeHelper<float>(leftVal, rightVal);
|
||||
}
|
||||
}
|
||||
bool RandomRangeExpression::validate(antlr4::Parser* parser, const ParseContext& context)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
valid &= m_leftExpression->validate(parser, context);
|
||||
valid &= m_rightExpression->validate(parser, context);
|
||||
|
||||
if (!valid) {
|
||||
// Exit early if there were errors since the values below are meaningless otherwise
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto leftType = m_leftExpression->getExpressionType();
|
||||
const auto rightType = m_rightExpression->getExpressionType();
|
||||
|
||||
const auto& leftTypedef = TypeDefinition::forValueType(leftType);
|
||||
const auto& rightTypedef = TypeDefinition::forValueType(rightType);
|
||||
|
||||
// Both values must be the same
|
||||
if (leftType != rightType) {
|
||||
parser->notifyErrorListeners(m_rightExpression->getToken(),
|
||||
"Inconsistent types for random range. Must be the same but got <" + leftTypedef.getName() + "> and <" +
|
||||
rightTypedef.getName() + ">.",
|
||||
nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// And we only support floats or integers
|
||||
if (leftType != ValueType::Float && leftType != ValueType::Integer) {
|
||||
parser->notifyErrorListeners(m_leftExpression->getToken(),
|
||||
"Invalid parameter type for random range. Must be <Float> or <Integer> but got <" + leftTypedef.getName() +
|
||||
">.",
|
||||
nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything is fine.
|
||||
return true;
|
||||
}
|
||||
ValueType RandomRangeExpression::determineReturnType() const
|
||||
{
|
||||
// Return type is the same as the contained return types
|
||||
return m_leftExpression->getExpressionType();
|
||||
}
|
||||
void RandomRangeExpression::validationDone()
|
||||
{
|
||||
AbstractExpression::validationDone();
|
||||
|
||||
m_leftExpression->validationDone();
|
||||
m_rightExpression->validationDone();
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
class RandomRangeExpression : public AbstractExpression {
|
||||
public:
|
||||
RandomRangeExpression(antlr4::Token* token,
|
||||
std::shared_ptr<AbstractExpression> leftExpression,
|
||||
std::shared_ptr<AbstractExpression> rightExpression);
|
||||
~RandomRangeExpression() override;
|
||||
|
||||
Value execute(const ProgramVariables& variables) const override;
|
||||
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
|
||||
void validationDone() override;
|
||||
|
||||
protected:
|
||||
ValueType determineReturnType() const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AbstractExpression> m_leftExpression;
|
||||
std::shared_ptr<AbstractExpression> m_rightExpression;
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
#include "VariableReferenceExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
VariableReferenceExpression::VariableReferenceExpression(SCP_vector<SCP_string> references,
|
||||
SCP_vector<antlr4::Token*> referenceTokens)
|
||||
: AbstractExpression(referenceTokens.back()), m_references(std::move(references)),
|
||||
m_referenceTokens(std::move(referenceTokens))
|
||||
{
|
||||
}
|
||||
VariableReferenceExpression::~VariableReferenceExpression() = default;
|
||||
|
||||
Value VariableReferenceExpression::execute(const ProgramVariables& variables) const
|
||||
{
|
||||
return variables.getValue(m_fullVariablePath);
|
||||
}
|
||||
bool VariableReferenceExpression::validate(antlr4::Parser* parser, const ParseContext& context)
|
||||
{
|
||||
// Start out in the global scope
|
||||
auto currentScope = &context.variables;
|
||||
SCP_string currentScopeName("<global>");
|
||||
|
||||
for (size_t i = 0; i < m_references.size() - 1; ++i) {
|
||||
const auto nextScope = currentScope->getScope(m_references[i]);
|
||||
|
||||
if (nextScope == nullptr) {
|
||||
parser->notifyErrorListeners(m_referenceTokens[i],
|
||||
"Could not find scope " + m_references[i] + " in scope " + currentScopeName + ".",
|
||||
nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
currentScope = nextScope;
|
||||
currentScopeName = m_references[i];
|
||||
}
|
||||
|
||||
auto variableType = currentScope->getMemberType(m_references.back());
|
||||
|
||||
if (variableType == ValueType::Invalid) {
|
||||
parser->notifyErrorListeners(m_referenceTokens.back(),
|
||||
"Could not find variable " + m_references.back() + " in scope " + currentScopeName + ".",
|
||||
nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache this so we don't duplicate all this code in determineReturnType()
|
||||
m_variableType = variableType;
|
||||
m_fullVariablePath = ProgramVariables::getMemberName(m_references);
|
||||
return true;
|
||||
}
|
||||
ValueType VariableReferenceExpression::determineReturnType() const
|
||||
{
|
||||
return m_variableType;
|
||||
}
|
||||
void VariableReferenceExpression::validationDone()
|
||||
{
|
||||
AbstractExpression::validationDone();
|
||||
|
||||
// Clear these since they are not necessary anymore
|
||||
m_references.clear();
|
||||
m_referenceTokens.clear();
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
class VariableReferenceExpression : public AbstractExpression {
|
||||
public:
|
||||
VariableReferenceExpression(const SCP_vector<SCP_string> references,
|
||||
SCP_vector<antlr4::Token*> referenceTokens);
|
||||
~VariableReferenceExpression() override;
|
||||
|
||||
Value execute(const ProgramVariables& variables) const override;
|
||||
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
|
||||
void validationDone() override;
|
||||
|
||||
protected:
|
||||
ValueType determineReturnType() const override;
|
||||
|
||||
private:
|
||||
ValueType m_variableType = ValueType::Invalid;
|
||||
SCP_string m_fullVariablePath;
|
||||
|
||||
SCP_vector<SCP_string> m_references;
|
||||
SCP_vector<antlr4::Token*> m_referenceTokens;
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
#include "VectorConstructorExpression.h"
|
||||
|
||||
#include "actions/expression/TypeDefinition.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
VectorConstructorExpression::VectorConstructorExpression(antlr4::Token* token,
|
||||
std::shared_ptr<AbstractExpression> xExpression,
|
||||
std::shared_ptr<AbstractExpression> yExpression,
|
||||
std::shared_ptr<AbstractExpression> zExpression)
|
||||
: AbstractExpression(token), m_xExpression(std::move(xExpression)), m_yExpression(std::move(yExpression)),
|
||||
m_zExpression(std::move(zExpression))
|
||||
{
|
||||
}
|
||||
VectorConstructorExpression::~VectorConstructorExpression() = default;
|
||||
|
||||
Value VectorConstructorExpression::execute(const ProgramVariables& variables) const
|
||||
{
|
||||
auto xValue = m_xExpression->execute(variables);
|
||||
auto yValue = m_yExpression->execute(variables);
|
||||
auto zValue = m_zExpression->execute(variables);
|
||||
|
||||
vec3d vecVal;
|
||||
|
||||
vecVal.xyz.x = xValue.getFloat();
|
||||
vecVal.xyz.y = yValue.getFloat();
|
||||
vecVal.xyz.z = zValue.getFloat();
|
||||
|
||||
return Value(vecVal);
|
||||
}
|
||||
bool VectorConstructorExpression::validate(antlr4::Parser* parser, const ParseContext& context)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
valid &= m_xExpression->validate(parser, context);
|
||||
valid &= m_yExpression->validate(parser, context);
|
||||
valid &= m_zExpression->validate(parser, context);
|
||||
|
||||
if (!valid) {
|
||||
// Exit early if there were errors since the values below are meaningless otherwise
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkTypeWithImplicitConversion(m_xExpression->getExpressionType(), ValueType::Float)) {
|
||||
const auto& typeDef = TypeDefinition::forValueType(m_xExpression->getExpressionType());
|
||||
parser->notifyErrorListeners(m_xExpression->getToken(),
|
||||
"Invalid value type for vector constructor. Expected <Float>, got <" + typeDef.getName() + ">",
|
||||
nullptr);
|
||||
valid = false;
|
||||
}
|
||||
if (!checkTypeWithImplicitConversion(m_yExpression->getExpressionType(), ValueType::Float)) {
|
||||
const auto& typeDef = TypeDefinition::forValueType(m_yExpression->getExpressionType());
|
||||
parser->notifyErrorListeners(m_yExpression->getToken(),
|
||||
"Invalid value type for vector constructor. Expected <Float>, got <" + typeDef.getName() + ">",
|
||||
nullptr);
|
||||
valid = false;
|
||||
}
|
||||
if (!checkTypeWithImplicitConversion(m_zExpression->getExpressionType(), ValueType::Float)) {
|
||||
const auto& typeDef = TypeDefinition::forValueType(m_zExpression->getExpressionType());
|
||||
parser->notifyErrorListeners(m_zExpression->getToken(),
|
||||
"Invalid value type for vector constructor. Expected <Float>, got <" + typeDef.getName() + ">",
|
||||
nullptr);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
ValueType VectorConstructorExpression::determineReturnType() const
|
||||
{
|
||||
// No need to look at the expressions here since we will always be a vector
|
||||
return ValueType::Vector;
|
||||
}
|
||||
void VectorConstructorExpression::validationDone()
|
||||
{
|
||||
AbstractExpression::validationDone();
|
||||
|
||||
m_xExpression->validationDone();
|
||||
m_yExpression->validationDone();
|
||||
m_zExpression->validationDone();
|
||||
}
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractExpression.h"
|
||||
|
||||
#include "actions/expression/Value.h"
|
||||
|
||||
namespace actions {
|
||||
namespace expression {
|
||||
namespace nodes {
|
||||
|
||||
class VectorConstructorExpression : public AbstractExpression {
|
||||
public:
|
||||
VectorConstructorExpression(antlr4::Token* token,
|
||||
std::shared_ptr<AbstractExpression> xExpression,
|
||||
std::shared_ptr<AbstractExpression> yExpression,
|
||||
std::shared_ptr<AbstractExpression> zExpression);
|
||||
~VectorConstructorExpression() override;
|
||||
|
||||
Value execute(const ProgramVariables& variables) const override;
|
||||
bool validate(antlr4::Parser* parser, const ParseContext& context) override;
|
||||
void validationDone() override;
|
||||
|
||||
protected:
|
||||
ValueType determineReturnType() const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<AbstractExpression> m_xExpression;
|
||||
std::shared_ptr<AbstractExpression> m_yExpression;
|
||||
std::shared_ptr<AbstractExpression> m_zExpression;
|
||||
};
|
||||
|
||||
} // namespace nodes
|
||||
} // namespace expression
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
#include "MoveToSubmodel.h"
|
||||
|
||||
#include "math/vecmat.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
flagset<ProgramContextFlags> MoveToSubmodel::getRequiredExecutionContextFlags()
|
||||
{
|
||||
return flagset<ProgramContextFlags>{ProgramContextFlags::HasObject, ProgramContextFlags::HasSubobject};
|
||||
}
|
||||
|
||||
MoveToSubmodel::MoveToSubmodel(expression::TypedActionExpression<ValueType> subObjectExpression)
|
||||
: m_subObjectExpression(std::move(subObjectExpression))
|
||||
{
|
||||
}
|
||||
MoveToSubmodel::~MoveToSubmodel() = default;
|
||||
|
||||
ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
{
|
||||
// The calling code should ensure that this never happens
|
||||
Assertion(locals.hostSubobject >= 0, "Did not have a valid host subobject.");
|
||||
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
const auto destinationSubObject = m_subObjectExpression.execute(locals.variables);
|
||||
bool goToParent = false;
|
||||
if (destinationSubObject == "<parent>") {
|
||||
goToParent = true;
|
||||
}
|
||||
|
||||
if (goToParent) {
|
||||
// Special case when we simply want to go to our parent without explicitly specifying its name
|
||||
auto parentSubobject = pm->submodel[locals.hostSubobject].parent;
|
||||
|
||||
if (parentSubobject < 0) {
|
||||
Warning(LOCATION,
|
||||
"Current program subobject %s on model %s has no parent!",
|
||||
pm->submodel[locals.hostSubobject].name,
|
||||
pm->filename);
|
||||
return ActionResult::Errored;
|
||||
}
|
||||
|
||||
// We have a valid parent so this move will work properly
|
||||
locals.hostSubobject = parentSubobject;
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
|
||||
// We need to do a linear search for the right subobject
|
||||
for (int i = 0; i < pm->n_models; ++i) {
|
||||
const auto submodel = pm->submodel[i];
|
||||
|
||||
if (subsystem_stricmp(destinationSubObject.c_str(), submodel.name) == 0) {
|
||||
// Found something!
|
||||
locals.hostSubobject = i;
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
}
|
||||
|
||||
Warning(LOCATION, "Could not find subobject %s in model %s!", destinationSubObject.c_str(), pm->filename);
|
||||
return ActionResult::Errored;
|
||||
}
|
||||
|
||||
std::unique_ptr<Action> MoveToSubmodel::clone() const
|
||||
{
|
||||
return std::unique_ptr<Action>(new MoveToSubmodel(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "globalincs/flagset.h"
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
class MoveToSubmodel : public Action {
|
||||
public:
|
||||
using ValueType = SCP_string;
|
||||
|
||||
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
|
||||
|
||||
explicit MoveToSubmodel(expression::TypedActionExpression<ValueType> subObjectExpression);
|
||||
~MoveToSubmodel() override;
|
||||
|
||||
ActionResult execute(ProgramLocals& locals) const override;
|
||||
|
||||
std::unique_ptr<Action> clone() const override;
|
||||
|
||||
private:
|
||||
expression::TypedActionExpression<ValueType> m_subObjectExpression;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
#include "ParticleEffectAction.h"
|
||||
|
||||
#include "math/vecmat.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "ship/ship.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
flagset<ProgramContextFlags> ParticleEffectAction::getRequiredExecutionContextFlags()
|
||||
{
|
||||
return flagset<ProgramContextFlags>{ProgramContextFlags::HasObject};
|
||||
}
|
||||
|
||||
ParticleEffectAction::ParticleEffectAction(expression::TypedActionExpression<ValueType> effectExpression)
|
||||
: m_effectExpression(std::move(effectExpression))
|
||||
{
|
||||
}
|
||||
ParticleEffectAction::~ParticleEffectAction() = default;
|
||||
|
||||
ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
{
|
||||
auto effectIdx = particle::ParticleManager::get()->getEffectByName(m_effectExpression.execute(locals.variables));
|
||||
|
||||
if (!effectIdx.isValid()) {
|
||||
// In case the parsing code failed
|
||||
return ActionResult::Errored;
|
||||
}
|
||||
|
||||
using namespace particle;
|
||||
|
||||
auto source = ParticleManager::get()->createSource(effectIdx);
|
||||
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
find_submodel_instance_point_orient(&local_pos,
|
||||
&local_orient,
|
||||
pm,
|
||||
pmi,
|
||||
locals.hostSubobject,
|
||||
&locals.localPosition,
|
||||
&locals.localOrient);
|
||||
} else {
|
||||
local_pos = locals.localPosition;
|
||||
local_orient = locals.localOrient;
|
||||
}
|
||||
|
||||
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
|
||||
|
||||
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
|
||||
|
||||
source.moveToObject(locals.host.objp, &local_pos);
|
||||
source.setOrientationFromNormalizedVec(&direction, true);
|
||||
|
||||
source.finish();
|
||||
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
|
||||
std::unique_ptr<Action> ParticleEffectAction::clone() const
|
||||
{
|
||||
return std::unique_ptr<Action>(new ParticleEffectAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
class ParticleEffectAction : public Action {
|
||||
|
||||
public:
|
||||
using ValueType = SCP_string;
|
||||
|
||||
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
|
||||
|
||||
explicit ParticleEffectAction(expression::TypedActionExpression<ValueType> effectExpression);
|
||||
~ParticleEffectAction() override;
|
||||
|
||||
ActionResult execute(ProgramLocals& locals) const override;
|
||||
|
||||
std::unique_ptr<Action> clone() const override;
|
||||
|
||||
private:
|
||||
expression::TypedActionExpression<ValueType> m_effectExpression;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
//
|
||||
|
||||
#include "PlaySoundAction.h"
|
||||
|
||||
#include "ship/ship.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
flagset<ProgramContextFlags> PlaySoundAction::getRequiredExecutionContextFlags()
|
||||
{
|
||||
return flagset<ProgramContextFlags>{ProgramContextFlags::HasObject};
|
||||
}
|
||||
|
||||
PlaySoundAction::PlaySoundAction(expression::TypedActionExpression<ValueType> soundIdExpression)
|
||||
: m_soundIdExpression(std::move(soundIdExpression))
|
||||
{
|
||||
}
|
||||
PlaySoundAction::~PlaySoundAction() = default;
|
||||
|
||||
ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
{
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
find_submodel_instance_point_orient(&local_pos,
|
||||
&local_orient,
|
||||
pm,
|
||||
pmi,
|
||||
locals.hostSubobject,
|
||||
&locals.localPosition,
|
||||
&locals.localOrient);
|
||||
} else {
|
||||
local_pos = locals.localPosition;
|
||||
local_orient = locals.localOrient;
|
||||
}
|
||||
|
||||
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
|
||||
|
||||
vec3d global_pos;
|
||||
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp->orient);
|
||||
global_pos += locals.host.objp->pos;
|
||||
|
||||
const auto soundId = gamesnd_get_by_name(m_soundIdExpression.execute(locals.variables).c_str());
|
||||
|
||||
// Sound is not attached to the host but the object sound system currently only supports persistent sounds
|
||||
snd_play_3d(gamesnd_get_game_sound(soundId), &global_pos, &Eye_position);
|
||||
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
std::unique_ptr<Action> PlaySoundAction::clone() const
|
||||
{
|
||||
return std::unique_ptr<Action>(new PlaySoundAction(*this));
|
||||
}
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
class PlaySoundAction : public Action {
|
||||
public:
|
||||
using ValueType = SCP_string;
|
||||
|
||||
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
|
||||
|
||||
explicit PlaySoundAction(expression::TypedActionExpression<ValueType> soundIdExpression);
|
||||
~PlaySoundAction() override;
|
||||
|
||||
ActionResult execute(ProgramLocals& locals) const override;
|
||||
|
||||
std::unique_ptr<Action> clone() const override;
|
||||
|
||||
private:
|
||||
expression::TypedActionExpression<ValueType> m_soundIdExpression;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#include "SetDirectionAction.h"
|
||||
|
||||
#include "math/vecmat.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
flagset<ProgramContextFlags> SetDirectionAction::getRequiredExecutionContextFlags()
|
||||
{
|
||||
return flagset<ProgramContextFlags>{};
|
||||
}
|
||||
|
||||
SetDirectionAction::SetDirectionAction(expression::TypedActionExpression<vec3d> newDirExpression)
|
||||
: m_newDirExpression(std::move(newDirExpression))
|
||||
{
|
||||
}
|
||||
SetDirectionAction::~SetDirectionAction() = default;
|
||||
|
||||
ActionResult SetDirectionAction::execute(ProgramLocals& locals) const
|
||||
{
|
||||
auto dir = m_newDirExpression.execute(locals.variables);
|
||||
|
||||
vm_vec_normalize_safe(&dir);
|
||||
|
||||
locals.variables.setValue({"locals", "direction"}, expression::Value(dir));
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
|
||||
std::unique_ptr<Action> SetDirectionAction::clone() const
|
||||
{
|
||||
return std::unique_ptr<Action>(new SetDirectionAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
class SetDirectionAction : public Action {
|
||||
public:
|
||||
using ValueType = vec3d;
|
||||
|
||||
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
|
||||
|
||||
SetDirectionAction(expression::TypedActionExpression<ValueType> newDirExpression);
|
||||
~SetDirectionAction() override;
|
||||
|
||||
ActionResult execute(ProgramLocals& locals) const override;
|
||||
|
||||
std::unique_ptr<Action> clone() const override;
|
||||
|
||||
private:
|
||||
expression::TypedActionExpression<ValueType> m_newDirExpression;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
#include "SetPositionAction.h"
|
||||
|
||||
#include "parse/parselo.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
flagset<ProgramContextFlags> SetPositionAction::getRequiredExecutionContextFlags()
|
||||
{
|
||||
return flagset<ProgramContextFlags>{};
|
||||
}
|
||||
|
||||
SetPositionAction::SetPositionAction(expression::TypedActionExpression<ValueType> newPositionExpression)
|
||||
: m_newPosExpression(std::move(newPositionExpression))
|
||||
{
|
||||
}
|
||||
SetPositionAction::~SetPositionAction() = default;
|
||||
|
||||
ActionResult SetPositionAction::execute(ProgramLocals& locals) const
|
||||
{
|
||||
locals.variables.setValue({"locals", "position"}, expression::Value(m_newPosExpression.execute(locals.variables)));
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
|
||||
std::unique_ptr<Action> SetPositionAction::clone() const
|
||||
{
|
||||
return std::unique_ptr<Action>(new SetPositionAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
class SetPositionAction : public Action {
|
||||
|
||||
public:
|
||||
using ValueType = vec3d;
|
||||
|
||||
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
|
||||
|
||||
SetPositionAction(expression::TypedActionExpression<ValueType> newPositionExpression);
|
||||
~SetPositionAction() override;
|
||||
|
||||
ActionResult execute(ProgramLocals& locals) const override;
|
||||
|
||||
std::unique_ptr<Action> clone() const override;
|
||||
|
||||
private:
|
||||
expression::TypedActionExpression<vec3d> m_newPosExpression;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
#include "WaitAction.h"
|
||||
|
||||
#include "io/timer.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
flagset<ProgramContextFlags> WaitAction::getRequiredExecutionContextFlags()
|
||||
{
|
||||
return flagset<ProgramContextFlags>{};
|
||||
}
|
||||
|
||||
WaitAction::WaitAction(expression::TypedActionExpression<float> waitTimeExpression)
|
||||
: _waitTimeExpression(std::move(waitTimeExpression))
|
||||
{
|
||||
}
|
||||
WaitAction::~WaitAction() = default;
|
||||
|
||||
ActionResult WaitAction::execute(actions::ProgramLocals& locals) const
|
||||
{
|
||||
if (!timestamp_valid(locals.waitTimestamp)) {
|
||||
auto waitTime = _waitTimeExpression.execute(locals.variables);
|
||||
|
||||
// Catch errors in the expression
|
||||
if (waitTime < 0.001f) {
|
||||
waitTime = 0.001f;
|
||||
}
|
||||
|
||||
locals.waitTimestamp = timestamp(fl2i(waitTime * TIMESTAMP_FREQUENCY));
|
||||
}
|
||||
if (!timestamp_elapsed(locals.waitTimestamp)) {
|
||||
// Wait until the timestamp is elapsed
|
||||
return ActionResult::Wait;
|
||||
}
|
||||
// Timestamp is elapsed. The timestamp is elapsed so that timestamp_valid above returns false for the next wait
|
||||
// action
|
||||
locals.waitTimestamp = 0;
|
||||
return ActionResult::Finished;
|
||||
}
|
||||
std::unique_ptr<Action> WaitAction::clone() const
|
||||
{
|
||||
return std::unique_ptr<Action>(new WaitAction(*this));
|
||||
}
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "actions/Action.h"
|
||||
#include "actions/common.h"
|
||||
#include "actions/expression/ActionExpression.h"
|
||||
#include "utils/RandomRange.h"
|
||||
|
||||
namespace actions {
|
||||
namespace types {
|
||||
|
||||
class WaitAction : public Action {
|
||||
public:
|
||||
using ValueType = float;
|
||||
|
||||
static flagset<ProgramContextFlags> getRequiredExecutionContextFlags();
|
||||
|
||||
explicit WaitAction(expression::TypedActionExpression<ValueType> waitTimeExpression);
|
||||
~WaitAction() override;
|
||||
|
||||
ActionResult execute(ProgramLocals& locals) const override;
|
||||
|
||||
std::unique_ptr<Action> clone() const override;
|
||||
|
||||
private:
|
||||
expression::TypedActionExpression<ValueType> _waitTimeExpression;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace actions
|
||||
+22
-10
@@ -10,6 +10,7 @@
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
|
||||
#include "gamesnd.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "localization/localize.h"
|
||||
#include "parse/parselo.h"
|
||||
@@ -421,21 +422,32 @@ bool parse_game_sound(const char* tag, gamesnd_id* idx_dest)
|
||||
{
|
||||
if (optional_string(tag))
|
||||
{
|
||||
SCP_string buf;
|
||||
stuff_string(buf, F_NAME);
|
||||
|
||||
*idx_dest = gamesnd_get_by_name(buf.c_str());
|
||||
|
||||
// The special case "-1" is needed to silence warnings where sounds are intentionally removed
|
||||
if (idx_dest->isValid() || buf == "-1")
|
||||
return true;
|
||||
|
||||
error_display(0, "Could not find game sound with name '%s'!", buf.c_str());
|
||||
*idx_dest = parse_game_sound_inline();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parses a game sound that should appear at the current parsing location
|
||||
* @return The game sound id or invalid id when parsing fails
|
||||
*/
|
||||
gamesnd_id parse_game_sound_inline()
|
||||
{
|
||||
SCP_string buf;
|
||||
stuff_string(buf, F_NAME);
|
||||
|
||||
auto id = gamesnd_get_by_name(buf.c_str());
|
||||
|
||||
// The special case "-1" is needed to silence warnings where sounds are intentionally removed
|
||||
if (!id.isValid() && buf != "-1") {
|
||||
error_display(0, "Could not find game sound with name '%s'!", buf.c_str());
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a sound. When using this function for a table entry,
|
||||
* required_string and optional_string aren't needed, as this function deals with
|
||||
|
||||
@@ -372,6 +372,8 @@ interface_snd_id gamesnd_get_by_iface_tbl_index(int index);
|
||||
// Does all parsing for a sound. Returns true if a sound was successfully parsed.
|
||||
bool parse_game_sound(const char* tag, gamesnd_id* idx_dest);
|
||||
|
||||
gamesnd_id parse_game_sound_inline();
|
||||
|
||||
void parse_iface_sound(const char* tag, interface_snd_id* idx_dest);
|
||||
void parse_iface_sound_list(const char* tag, SCP_vector<interface_snd_id>& destination, const char* object_name, bool scp_list = false);
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#include "ErrorListener.h"
|
||||
|
||||
namespace libs {
|
||||
namespace antlr {
|
||||
|
||||
void ErrorListener::syntaxError(antlr4::Recognizer*,
|
||||
antlr4::Token* offendingSymbol,
|
||||
size_t line,
|
||||
size_t charPositionInLine,
|
||||
const std::string& msg,
|
||||
std::exception_ptr)
|
||||
{
|
||||
// Apparently stop < start is a thing?
|
||||
const auto left = std::min(offendingSymbol->getStartIndex(), offendingSymbol->getStopIndex());
|
||||
const auto right = std::max(offendingSymbol->getStartIndex(), offendingSymbol->getStopIndex());
|
||||
const auto length = right - left + 1;
|
||||
|
||||
diagnostics.push_back(Diagnostic{line, charPositionInLine, length, msg});
|
||||
}
|
||||
|
||||
} // namespace antlr
|
||||
} // namespace libs
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#include <BaseErrorListener.h>
|
||||
#include <Token.h>
|
||||
|
||||
namespace libs {
|
||||
namespace antlr {
|
||||
|
||||
struct Diagnostic {
|
||||
size_t line;
|
||||
size_t columnInLine;
|
||||
size_t tokenLength;
|
||||
SCP_string errorMessage;
|
||||
};
|
||||
|
||||
struct ErrorListener : public antlr4::BaseErrorListener {
|
||||
SCP_vector<Diagnostic> diagnostics;
|
||||
|
||||
void syntaxError(antlr4::Recognizer* /*recognizer*/,
|
||||
antlr4::Token* offendingSymbol,
|
||||
size_t line,
|
||||
size_t charPositionInLine,
|
||||
const std::string& msg,
|
||||
std::exception_ptr /*e*/) override;
|
||||
};
|
||||
|
||||
} // namespace antlr
|
||||
} // namespace libs
|
||||
@@ -157,6 +157,17 @@ void vm_set_identity(matrix *m)
|
||||
m->vec.fvec.xyz.x = 0.0f; m->vec.fvec.xyz.y = 0.0f; m->vec.fvec.xyz.z = 1.0f;
|
||||
}
|
||||
|
||||
vec3d vm_vec_new(float x, float y, float z)
|
||||
{
|
||||
vec3d vec;
|
||||
|
||||
vec.xyz.x = x;
|
||||
vec.xyz.y = y;
|
||||
vec.xyz.z = z;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
//adds two vectors, fills in dest, returns ptr to dest
|
||||
//ok for dest to equal either source, but should use vm_vec_add2() if so
|
||||
//dest = src0 + src1
|
||||
@@ -2831,3 +2842,9 @@ void vm_interpolate_angles_quick(angles *dest0, angles *src0, angles *src1, floa
|
||||
dest0->h = src0->h + (arc_measures.h * interp_perc);
|
||||
dest0->b = src0->b + (arc_measures.b * interp_perc);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const vec3d& vec)
|
||||
{
|
||||
os << "vec3d<" << vec.xyz.x << ", " << vec.xyz.y << ", " << vec.xyz.z << ")";
|
||||
return os;
|
||||
}
|
||||
@@ -52,6 +52,8 @@ extern void vm_set_identity(matrix *m);
|
||||
|
||||
#define vm_vec_make(v,_x,_y,_z) ((v)->xyz.x=(_x), (v)->xyz.y=(_y), (v)->xyz.z=(_z))
|
||||
|
||||
extern vec3d vm_vec_new(float x, float y, float z);
|
||||
|
||||
//Global constants
|
||||
|
||||
extern vec3d vmd_zero_vector;
|
||||
@@ -654,6 +656,8 @@ inline matrix operator*(const matrix& left, const matrix& right) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const vec3d& vec);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+9
-7
@@ -12,14 +12,16 @@
|
||||
#ifndef _MODEL_H
|
||||
#define _MODEL_H
|
||||
|
||||
#include "globalincs/globals.h" // for NAME_LENGTH
|
||||
#include "globalincs/globals.h" // for NAME_LENGTH
|
||||
#include "globalincs/pstypes.h"
|
||||
#include "graphics/2d.h"
|
||||
|
||||
#include "actions/Program.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "io/timer.h"
|
||||
#include "model/model_flags.h"
|
||||
#include "object/object.h"
|
||||
#include "ship/ship_flags.h"
|
||||
#include "model/model_flags.h"
|
||||
|
||||
class object;
|
||||
class model_render_params;
|
||||
@@ -204,13 +206,13 @@ public:
|
||||
|
||||
//Per-turret ownage settings - SUSHI
|
||||
int turret_max_bomb_ownage;
|
||||
int turret_max_target_ownage;
|
||||
int turret_max_target_ownage;
|
||||
|
||||
actions::ProgramSet beam_warmdown_program;
|
||||
|
||||
void reset();
|
||||
|
||||
model_subsystem() {
|
||||
reset();
|
||||
}
|
||||
model_subsystem();
|
||||
};
|
||||
|
||||
typedef struct model_special {
|
||||
|
||||
@@ -5565,4 +5565,10 @@ void model_subsystem::reset()
|
||||
|
||||
turret_max_bomb_ownage = 0;
|
||||
turret_max_target_ownage = 0;
|
||||
|
||||
beam_warmdown_program = actions::ProgramSet();
|
||||
}
|
||||
|
||||
model_subsystem::model_subsystem() {
|
||||
reset();
|
||||
}
|
||||
@@ -165,22 +165,22 @@ bool SourceOrigin::isValid() const {
|
||||
|
||||
SourceOrientation::SourceOrientation() : m_orientation(vmd_identity_matrix) {}
|
||||
|
||||
void SourceOrientation::setFromVector(const vec3d& vec) {
|
||||
void SourceOrientation::setFromVector(const vec3d& vec, bool relative) {
|
||||
vec3d workVec = vec;
|
||||
|
||||
vm_vec_normalize(&workVec);
|
||||
|
||||
this->setFromNormalizedVector(workVec);
|
||||
this->setFromNormalizedVector(workVec, relative);
|
||||
}
|
||||
|
||||
void SourceOrientation::setFromNormalizedVector(const vec3d& vec) {
|
||||
void SourceOrientation::setFromNormalizedVector(const vec3d& vec, bool relative) {
|
||||
vm_vector_2_matrix_norm(&m_orientation, &vec);
|
||||
m_isRelative = false;
|
||||
m_isRelative = relative;
|
||||
}
|
||||
|
||||
void SourceOrientation::setFromMatrix(const matrix& mat) {
|
||||
void SourceOrientation::setFromMatrix(const matrix& mat, bool relative) {
|
||||
m_orientation = mat;
|
||||
m_isRelative = false;
|
||||
m_isRelative = relative;
|
||||
}
|
||||
|
||||
void SourceOrientation::setNormal(const vec3d& normal) {
|
||||
|
||||
@@ -155,18 +155,18 @@ class SourceOrientation {
|
||||
*
|
||||
* @param vec The vector to create the matrix from
|
||||
*/
|
||||
void setFromVector(const vec3d& vec);
|
||||
void setFromVector(const vec3d& vec, bool relative = false);
|
||||
|
||||
/**
|
||||
* @brief Sets the direction from an already normalized vector
|
||||
*
|
||||
* @param vec The normalized vector
|
||||
*/
|
||||
void setFromNormalizedVector(const vec3d& vec);
|
||||
void setFromNormalizedVector(const vec3d& vec, bool relative = false);
|
||||
|
||||
void setNormal(const vec3d& normal);
|
||||
|
||||
void setFromMatrix(const matrix& mat);
|
||||
void setFromMatrix(const matrix& mat, bool relative = false);
|
||||
|
||||
vec3d getDirectionVector(const SourceOrigin* origin) const;
|
||||
|
||||
|
||||
@@ -84,28 +84,28 @@ namespace particle
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleSourceWrapper::setOrientationFromNormalizedVec(vec3d* normalizedDir)
|
||||
void ParticleSourceWrapper::setOrientationFromNormalizedVec(vec3d* normalizedDir, bool relative)
|
||||
{
|
||||
for (auto& source : m_sources)
|
||||
{
|
||||
source->getOrientation()->setFromNormalizedVector(*normalizedDir);
|
||||
source->getOrientation()->setFromNormalizedVector(*normalizedDir, relative);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParticleSourceWrapper::setOrientationFromVec(vec3d* dir)
|
||||
void ParticleSourceWrapper::setOrientationFromVec(vec3d* dir, bool relative)
|
||||
{
|
||||
for (auto& source : m_sources)
|
||||
{
|
||||
source->getOrientation()->setFromVector(*dir);
|
||||
source->getOrientation()->setFromVector(*dir, relative);
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleSourceWrapper::setOrientationMatrix(matrix* mtx)
|
||||
void ParticleSourceWrapper::setOrientationMatrix(matrix* mtx, bool relative)
|
||||
{
|
||||
for (auto& source : m_sources)
|
||||
{
|
||||
source->getOrientation()->setFromMatrix(*mtx);
|
||||
source->getOrientation()->setFromMatrix(*mtx, relative);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,11 +54,11 @@ namespace particle
|
||||
|
||||
void moveTo(vec3d* pos);
|
||||
|
||||
void setOrientationFromNormalizedVec(vec3d* normalizedDir);
|
||||
void setOrientationFromNormalizedVec(vec3d* normalizedDir, bool relative = false);
|
||||
|
||||
void setOrientationFromVec(vec3d* dir);
|
||||
void setOrientationFromVec(vec3d* dir, bool relative = false);
|
||||
|
||||
void setOrientationMatrix(matrix* mtx);
|
||||
void setOrientationMatrix(matrix* mtx, bool relative = false);
|
||||
|
||||
void setOrientationNormal(vec3d* normal);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "doc_parser.h"
|
||||
|
||||
#include "parse/parselo.h"
|
||||
#include "libs/antlr/ErrorListener.h"
|
||||
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
@@ -15,32 +16,6 @@ namespace scripting {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Diagnostic {
|
||||
size_t line;
|
||||
size_t columnInLine;
|
||||
size_t tokenLength;
|
||||
SCP_string errorMessage;
|
||||
};
|
||||
|
||||
struct ErrorListener : public antlr4::BaseErrorListener {
|
||||
SCP_vector<Diagnostic> diagnostics;
|
||||
|
||||
void syntaxError(antlr4::Recognizer* /*recognizer*/,
|
||||
antlr4::Token* offendingSymbol,
|
||||
size_t line,
|
||||
size_t charPositionInLine,
|
||||
const std::string& msg,
|
||||
std::exception_ptr /*e*/) override
|
||||
{
|
||||
// Apparently stop < start is a thing?
|
||||
const auto left = std::min(offendingSymbol->getStartIndex(), offendingSymbol->getStopIndex());
|
||||
const auto right = std::max(offendingSymbol->getStartIndex(), offendingSymbol->getStopIndex());
|
||||
const auto length = right - left + 1;
|
||||
|
||||
diagnostics.push_back(Diagnostic{line, charPositionInLine, length, msg});
|
||||
}
|
||||
};
|
||||
|
||||
ade_type_info merge_alternatives(const ade_type_info& left, const ade_type_info& right)
|
||||
{
|
||||
SCP_vector<ade_type_info> elements;
|
||||
@@ -369,7 +344,7 @@ bool argument_list_parser::parse(const SCP_string& argumentList)
|
||||
ArgumentListParser parser(&tokens);
|
||||
// By default we log to stderr which we do not want
|
||||
parser.removeErrorListeners();
|
||||
ErrorListener errListener;
|
||||
libs::antlr::ErrorListener errListener;
|
||||
parser.addErrorListener(&errListener);
|
||||
|
||||
antlr4::tree::ParseTree* tree = parser.arg_list();
|
||||
|
||||
+24
-14
@@ -943,7 +943,7 @@ void ship_info::clone(const ship_info& other)
|
||||
|
||||
if ( other.n_subsystems > 0 ) {
|
||||
if( n_subsystems < 1 ) {
|
||||
subsystems = (model_subsystem *)vm_malloc(sizeof(model_subsystem) * other.n_subsystems);
|
||||
subsystems = new model_subsystem[other.n_subsystems];
|
||||
} else {
|
||||
for ( int i = 0; i < n_subsystems; i++ ) {
|
||||
for ( int j = 0; j < subsystems[i].n_triggers; j++ ) {
|
||||
@@ -954,10 +954,11 @@ void ship_info::clone(const ship_info& other)
|
||||
}
|
||||
}
|
||||
}
|
||||
subsystems = (model_subsystem *)vm_realloc(subsystems, sizeof(model_subsystem) * other.n_subsystems);
|
||||
delete[] subsystems;
|
||||
subsystems = new model_subsystem[other.n_subsystems];
|
||||
}
|
||||
|
||||
Assert(subsystems != NULL);
|
||||
Assert(subsystems != nullptr);
|
||||
for ( int i = n_subsystems; i < other.n_subsystems; i++ ) {
|
||||
subsystems[i].triggers = (queued_animation*) vm_malloc(sizeof(queued_animation) * (other.subsystems[i].n_triggers));
|
||||
}
|
||||
@@ -1896,8 +1897,8 @@ ship_info::~ship_info()
|
||||
}
|
||||
}
|
||||
|
||||
vm_free(subsystems);
|
||||
subsystems = NULL;
|
||||
delete[] subsystems;
|
||||
subsystems = nullptr;
|
||||
}
|
||||
|
||||
free_strings();
|
||||
@@ -4531,9 +4532,9 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
|
||||
int n_subsystems = 0;
|
||||
int cont_flag = 1;
|
||||
model_subsystem subsystems[MAX_MODEL_SUBSYSTEMS]; // see model.h for max_model_subsystems
|
||||
model_subsystem subsystems[MAX_MODEL_SUBSYSTEMS] = {}; // see model.h for max_model_subsystems
|
||||
for (auto i=0; i<MAX_MODEL_SUBSYSTEMS; i++) {
|
||||
subsystems[i].stepped_rotation = NULL;
|
||||
subsystems[i].reset();
|
||||
}
|
||||
|
||||
float hull_percentage_of_hits = 100.0f;
|
||||
@@ -5033,6 +5034,8 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
}
|
||||
}
|
||||
|
||||
sp->beam_warmdown_program = actions::ProgramSet::parseProgramSet("$On Beam Warmdown:",
|
||||
{actions::ProgramContextFlags::HasObject, actions::ProgramContextFlags::HasSubobject});
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@@ -5055,14 +5058,21 @@ static void parse_ship_values(ship_info* sip, const bool is_template, const bool
|
||||
// when done reading subsystems, malloc and copy the subsystem data to the ship info structure
|
||||
int orig_n_subsystems = sip->n_subsystems;
|
||||
if ( n_subsystems > 0 ) {
|
||||
if(sip->n_subsystems < 1) {
|
||||
sip->n_subsystems = n_subsystems;
|
||||
sip->subsystems = (model_subsystem*)vm_malloc(sizeof(model_subsystem) * sip->n_subsystems);
|
||||
// Let's make sure that n_subsystems is not negative
|
||||
Assertion(sip->n_subsystems >= 0, "Invalid n_subsystems detected!");
|
||||
auto new_n = sip->n_subsystems + n_subsystems;
|
||||
|
||||
std::unique_ptr<model_subsystem[]> subsys_storage(new model_subsystem[new_n]);
|
||||
|
||||
if(sip->n_subsystems <= 0) {
|
||||
sip->n_subsystems = n_subsystems;
|
||||
} else {
|
||||
// This used realloc originally so we need to copy the existing subsystems to the new storage
|
||||
std::copy(sip->subsystems, sip->subsystems + sip->n_subsystems, subsys_storage.get());
|
||||
|
||||
sip->n_subsystems += n_subsystems;
|
||||
sip->subsystems = (model_subsystem *)vm_realloc(sip->subsystems, sizeof(model_subsystem) * sip->n_subsystems);
|
||||
}
|
||||
}
|
||||
sip->subsystems = subsys_storage.release();
|
||||
|
||||
Assert(sip->subsystems != NULL);
|
||||
}
|
||||
@@ -13328,7 +13338,7 @@ int ship_type_name_lookup(const char *name)
|
||||
// Return true/false for subsystem found/not found.
|
||||
// Stuff vector *pos with absolute position.
|
||||
// subsysp is a pointer to the subsystem.
|
||||
int get_subsystem_pos(vec3d *pos, object *objp, ship_subsys *subsysp)
|
||||
int get_subsystem_pos(vec3d* pos, object* objp, ship_subsys* subsysp)
|
||||
{
|
||||
if (subsysp == NULL) {
|
||||
*pos = objp->pos;
|
||||
@@ -13336,7 +13346,7 @@ int get_subsystem_pos(vec3d *pos, object *objp, ship_subsys *subsysp)
|
||||
}
|
||||
Assertion(objp->type == OBJ_SHIP, "Only ships can have subsystems!");
|
||||
|
||||
model_subsystem *mss = subsysp->system_info;
|
||||
model_subsystem* mss = subsysp->system_info;
|
||||
|
||||
if (mss->subobj_num == -1) {
|
||||
// If it's a special point subsys, we can use its offset directly
|
||||
|
||||
@@ -6,6 +6,67 @@ add_file_folder(""
|
||||
prefix_header.h
|
||||
)
|
||||
|
||||
add_file_folder("Actions"
|
||||
actions/Action.cpp
|
||||
actions/Action.h
|
||||
actions/ActionDefinition.cpp
|
||||
actions/ActionDefinition.h
|
||||
actions/ActionDefinitionManager.cpp
|
||||
actions/ActionDefinitionManager.h
|
||||
actions/BuiltinActionDefinition.cpp
|
||||
actions/BuiltinActionDefinition.h
|
||||
actions/common.cpp
|
||||
actions/common.h
|
||||
actions/Program.cpp
|
||||
actions/Program.h
|
||||
)
|
||||
|
||||
add_file_folder("Actions\\\\Expression"
|
||||
actions/expression/ActionExpression.cpp
|
||||
actions/expression/ActionExpression.h
|
||||
actions/expression/ExpressionParser.cpp
|
||||
actions/expression/ExpressionParser.h
|
||||
actions/expression/FunctionManager.cpp
|
||||
actions/expression/FunctionManager.h
|
||||
actions/expression/ParseContext.h
|
||||
actions/expression/ProgramVariables.cpp
|
||||
actions/expression/ProgramVariables.h
|
||||
actions/expression/TypeDefinition.cpp
|
||||
actions/expression/TypeDefinition.h
|
||||
actions/expression/Value.cpp
|
||||
actions/expression/Value.h
|
||||
)
|
||||
|
||||
add_file_folder("Actions\\\\Expression\\\\Nodes"
|
||||
actions/expression/nodes/AbstractExpression.cpp
|
||||
actions/expression/nodes/AbstractExpression.h
|
||||
actions/expression/nodes/FunctionCallExpression.cpp
|
||||
actions/expression/nodes/FunctionCallExpression.h
|
||||
actions/expression/nodes/LiteralExpression.cpp
|
||||
actions/expression/nodes/LiteralExpression.h
|
||||
actions/expression/nodes/RandomRangeExpression.cpp
|
||||
actions/expression/nodes/RandomRangeExpression.h
|
||||
actions/expression/nodes/VariableReferenceExpression.cpp
|
||||
actions/expression/nodes/VariableReferenceExpression.h
|
||||
actions/expression/nodes/VectorConstructorExpression.cpp
|
||||
actions/expression/nodes/VectorConstructorExpression.h
|
||||
)
|
||||
|
||||
add_file_folder("Actions\\\\Types"
|
||||
actions/types/MoveToSubmodel.cpp
|
||||
actions/types/MoveToSubmodel.h
|
||||
actions/types/ParticleEffectAction.cpp
|
||||
actions/types/ParticleEffectAction.h
|
||||
actions/types/PlaySoundAction.cpp
|
||||
actions/types/PlaySoundAction.h
|
||||
actions/types/SetDirectionAction.cpp
|
||||
actions/types/SetDirectionAction.h
|
||||
actions/types/SetPositionAction.cpp
|
||||
actions/types/SetPositionAction.h
|
||||
actions/types/WaitAction.cpp
|
||||
actions/types/WaitAction.h
|
||||
)
|
||||
|
||||
# AI files
|
||||
add_file_folder("AI"
|
||||
ai/ai.cpp
|
||||
@@ -637,6 +698,11 @@ add_file_folder("Libs"
|
||||
libs/jansson.h
|
||||
)
|
||||
|
||||
add_file_folder("Libs\\\\AntLR"
|
||||
libs/antlr/ErrorListener.cpp
|
||||
libs/antlr/ErrorListener.h
|
||||
)
|
||||
|
||||
add_file_folder("Libs\\\\Discord"
|
||||
libs/discord/discord.cpp
|
||||
libs/discord/discord.h
|
||||
@@ -1458,6 +1524,7 @@ add_file_folder("Utils"
|
||||
utils/HeapAllocator.cpp
|
||||
utils/HeapAllocator.h
|
||||
utils/id.h
|
||||
utils/join_string.h
|
||||
utils/RandomRange.h
|
||||
utils/string_utils.cpp
|
||||
utils/string_utils.h
|
||||
|
||||
@@ -5,10 +5,35 @@ using namespace tracing;
|
||||
|
||||
namespace tracing {
|
||||
|
||||
MonitorBase::MonitorBase(const char* name) : _name(name), _tracing_cat(name, false) {
|
||||
}
|
||||
void MonitorBase::valueChanged(float newVal) {
|
||||
MonitorBase::MonitorBase(const char* name) : _name(name), _tracing_cat(name, false) {}
|
||||
void MonitorBase::valueChanged(float newVal)
|
||||
{
|
||||
tracing::counter::value(_tracing_cat, newVal);
|
||||
}
|
||||
|
||||
RunningCounter::RunningCounter(Monitor<int>& monitor) : _monitor(monitor)
|
||||
{
|
||||
_monitor += 1;
|
||||
}
|
||||
RunningCounter::~RunningCounter()
|
||||
{
|
||||
_monitor -= 1;
|
||||
}
|
||||
RunningCounter::RunningCounter(const RunningCounter& other) : _monitor(other._monitor)
|
||||
{
|
||||
_monitor += 1;
|
||||
}
|
||||
RunningCounter& RunningCounter::operator=(const RunningCounter&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
RunningCounter::RunningCounter(RunningCounter&& other) noexcept : _monitor(other._monitor)
|
||||
{
|
||||
_monitor += 1;
|
||||
}
|
||||
RunningCounter& RunningCounter::operator=(RunningCounter&&) noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace tracing
|
||||
+18
-1
@@ -58,7 +58,24 @@ class Monitor: public MonitorBase {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Class that keeps track of how many operations are currently running
|
||||
*/
|
||||
class RunningCounter {
|
||||
Monitor<int>& _monitor;
|
||||
|
||||
public:
|
||||
explicit RunningCounter(Monitor<int>& monitor);
|
||||
~RunningCounter();
|
||||
|
||||
RunningCounter(const RunningCounter&);
|
||||
RunningCounter& operator=(const RunningCounter&);
|
||||
|
||||
RunningCounter(RunningCounter&&) noexcept;
|
||||
RunningCounter& operator=(RunningCounter&&) noexcept;
|
||||
};
|
||||
|
||||
} // namespace tracing
|
||||
|
||||
// Creates a monitor variable
|
||||
#define MONITOR(function_name) static ::tracing::Monitor<int> mon_##function_name(#function_name, 0);
|
||||
|
||||
@@ -143,4 +143,6 @@ Category RenderDecals("Render all decals", true);
|
||||
Category RenderSingleDecal("Render single decal", true);
|
||||
Category GpuHeapAllocate("GPU heap allocate", false);
|
||||
Category GpuHeapDeallocate("GPU heap deallocate", false);
|
||||
|
||||
Category ProgramStepOne("Step one program", false);
|
||||
}
|
||||
@@ -159,6 +159,8 @@ extern Category RenderSingleDecal;
|
||||
extern Category GpuHeapAllocate;
|
||||
extern Category GpuHeapDeallocate;
|
||||
|
||||
extern Category ProgramStepOne;
|
||||
|
||||
}
|
||||
|
||||
#endif // _TRACING_CATEGORIES_H
|
||||
+1
-1
@@ -46,7 +46,7 @@ public:
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline bool isValid() { return m_val != default_value; }
|
||||
inline bool isValid() const { return m_val != default_value; }
|
||||
|
||||
private:
|
||||
Impl m_val;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
namespace util {
|
||||
|
||||
template <typename TIter>
|
||||
SCP_string join_range(TIter&& begin, TIter&& end, const SCP_string& joiner)
|
||||
{
|
||||
SCP_stringstream stream;
|
||||
bool first = true;
|
||||
|
||||
for (auto iter = begin; iter != end; ++iter) {
|
||||
stream << *iter;
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
stream << joiner;
|
||||
}
|
||||
}
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <typename TContainer>
|
||||
SCP_string join_container(TContainer& container, const SCP_string& joiner)
|
||||
{
|
||||
return join_range(std::begin(container), std::end(container), joiner);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
@@ -2006,6 +2006,14 @@ void beam_start_warmdown(beam *b)
|
||||
snd_stop(b->beam_sound_loop);
|
||||
b->beam_sound_loop = sound_handle::invalid();
|
||||
}
|
||||
|
||||
if (b->subsys != nullptr) {
|
||||
// Starts the warmdown program if it exists
|
||||
b->subsys->system_info->beam_warmdown_program.start(b->objp,
|
||||
&vmd_zero_vector,
|
||||
&vmd_identity_matrix,
|
||||
b->subsys->system_info->subobj_num);
|
||||
}
|
||||
}
|
||||
|
||||
// recalculate beam sounds (looping sounds relative to the player)
|
||||
|
||||
@@ -14,15 +14,17 @@
|
||||
|
||||
#include "globalincs/globals.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
|
||||
#include "actions/Program.h"
|
||||
#include "decals/decals.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/generic.h"
|
||||
#include "gamesnd/gamesnd.h"
|
||||
#include "model/model.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
#include "weapon/shockwave.h"
|
||||
#include "weapon/trails.h"
|
||||
#include "particle/ParticleManager.h"
|
||||
#include "weapon/weapon_flags.h"
|
||||
#include "decals/decals.h"
|
||||
|
||||
class object;
|
||||
class ship_subsys;
|
||||
@@ -512,6 +514,8 @@ struct weapon_info
|
||||
|
||||
decals::creation_info impact_decal;
|
||||
|
||||
actions::ProgramSet on_create_program;
|
||||
|
||||
public:
|
||||
weapon_info();
|
||||
|
||||
|
||||
+28
-4
@@ -3012,6 +3012,19 @@ int parse_weapon(int subtype, bool replace, const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
// This only works with lasters and missiles for now
|
||||
if (wip->subtype == WP_MISSILE || wip->subtype == WP_LASER) {
|
||||
// We always have an object we are attached to
|
||||
flagset<actions::ProgramContextFlags> contexts{actions::ProgramContextFlags::HasObject};
|
||||
|
||||
if (wip->render_type == WRT_POF) {
|
||||
// We will render with a model so we can have subobejcts
|
||||
contexts.set(actions::ProgramContextFlags::HasSubobject, true);
|
||||
}
|
||||
|
||||
wip->on_create_program = actions::ProgramSet::parseProgramSet("$On Create:", contexts);
|
||||
}
|
||||
|
||||
/* Generate a substitution pattern for this weapon.
|
||||
This pattern is very naive such that it calculates the lowest common denominator as being all of
|
||||
the periods multiplied together.
|
||||
@@ -5764,10 +5777,8 @@ int weapon_create( vec3d * pos, matrix * porient, int weapon_type, int parent_ob
|
||||
|
||||
objp->radius = model_get_radius(wip->model_num);
|
||||
|
||||
// if we intrinsic-rotate, make sure we have a model instance
|
||||
if (model_get(wip->model_num)->flags & PM_FLAG_HAS_INTRINSIC_ROTATE) {
|
||||
wp->model_instance_num = model_create_instance(false, wip->model_num);
|
||||
}
|
||||
// Always create an instance in case we need them
|
||||
wp->model_instance_num = model_create_instance(false, wip->model_num);
|
||||
} else if ( wip->render_type == WRT_LASER ) {
|
||||
objp->radius = wip->laser_head_radius;
|
||||
}
|
||||
@@ -5948,6 +5959,17 @@ int weapon_create( vec3d * pos, matrix * porient, int weapon_type, int parent_ob
|
||||
|
||||
weapon_update_state(wp);
|
||||
|
||||
if (wip->render_type == WRT_LASER) {
|
||||
// No model so we also have no submodel
|
||||
wip->on_create_program.start(&Objects[objnum], &vmd_zero_vector, &vmd_identity_matrix, -1);
|
||||
} else if (wip->render_type == WRT_POF) {
|
||||
// We have a model so we can specify a subobject
|
||||
wip->on_create_program.start(&Objects[objnum],
|
||||
&vmd_zero_vector,
|
||||
&vmd_identity_matrix,
|
||||
model_get(wip->model_num)->detail[0]);
|
||||
}
|
||||
|
||||
Script_system.SetHookObject("Weapon", &Objects[objnum]);
|
||||
Script_system.RunCondition(CHA_ONWEAPONCREATED);
|
||||
Script_system.RemHookVar("Weapon");
|
||||
@@ -8361,6 +8383,8 @@ void weapon_info::reset()
|
||||
|
||||
// Reset using default constructor
|
||||
this->impact_decal = decals::creation_info();
|
||||
|
||||
this->on_create_program = actions::ProgramSet();
|
||||
}
|
||||
|
||||
const char* weapon_info::get_display_name() const
|
||||
|
||||
@@ -48,3 +48,5 @@ include(antlr4.cmake)
|
||||
include(vulkan.cmake)
|
||||
|
||||
add_subdirectory(mdns)
|
||||
|
||||
add_subdirectory(variant)
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
add_library(variant INTERFACE)
|
||||
|
||||
target_include_directories(variant SYSTEM INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
File diff suppressed because it is too large.
Load diff
+6
-1
@@ -1,7 +1,12 @@
|
||||
|
||||
find_program(GLSLC_PATH glslc)
|
||||
|
||||
if (GLSLC_PATH)
|
||||
# Add an option for this so that this can be disabled locally when not needed
|
||||
option(SHADERS_ENABLE_COMPILATION "Enable compilation of shaders to SPIR-V" OFF)
|
||||
|
||||
mark_as_advanced(SHADERS_ENABLE_COMPILATION)
|
||||
|
||||
if (SHADERS_ENABLE_COMPILATION AND GLSLC_PATH)
|
||||
if(PLATFORM_WINDOWS)
|
||||
set(SHADERTOOL_FILENAME "shadertool-windows.tar.gz")
|
||||
elseif(PLATFORM_LINUX)
|
||||
|
||||
+33
-18
@@ -1,4 +1,35 @@
|
||||
|
||||
function(add_parser filename)
|
||||
get_filename_component(_name "${filename}" NAME_WE)
|
||||
get_filename_component(_absolutePath "${filename}" ABSOLUTE)
|
||||
|
||||
get_filename_component(_directory "${_absolutePath}" DIRECTORY)
|
||||
get_filename_component(_directoryName "${_directory}" NAME)
|
||||
|
||||
if (ANTLR_FOUND)
|
||||
antlr_target(${_name} "${_absolutePath}"
|
||||
VISITOR
|
||||
OUTPUT_DIRECTORY "${_directory}/generated")
|
||||
target_sources(parsers PRIVATE "${_absolutePath}")
|
||||
source_group("${_directoryName}" FILES "${_absolutePath}")
|
||||
else()
|
||||
# Otherwise we just use the ones that are checked in
|
||||
set(ANTLR_${_name}_OUTPUTS
|
||||
${_directory}/generated/${_name}BaseVisitor.cpp
|
||||
${_directory}/generated/${_name}BaseVisitor.h
|
||||
${_directory}/generated/${_name}Lexer.cpp
|
||||
${_directory}/generated/${_name}Lexer.h
|
||||
${_directory}/generated/${_name}Parser.cpp
|
||||
${_directory}/generated/${_name}Parser.h
|
||||
${_directory}/generated/${_name}Visitor.cpp
|
||||
${_directory}/generated/${_name}Visitor.h
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(parsers PRIVATE ${ANTLR_${_name}_OUTPUTS})
|
||||
source_group("${_directoryName}\\generated" FILES ${ANTLR_${_name}_OUTPUTS})
|
||||
endfunction()
|
||||
|
||||
add_library(parsers STATIC)
|
||||
|
||||
target_link_libraries(parsers PUBLIC antlr4_static)
|
||||
@@ -8,28 +39,12 @@ find_package(ANTLR)
|
||||
if (ANTLR_FOUND)
|
||||
# If we have an ANTLR installation then we can generate new sources
|
||||
message(STATUS "Using ANTLR to generate parser")
|
||||
antlr_target(ArgumentList "${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/ArgumentList.g4"
|
||||
VISITOR
|
||||
OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated")
|
||||
target_sources(parsers PRIVATE "arg_parser/ArgumentList.g4")
|
||||
source_group("arg_parser" FILES "arg_parser\\ArgumentList.g4")
|
||||
else()
|
||||
# Otherwise we just use the ones that are checked in
|
||||
message(STATUS "Using generated ANTLR files")
|
||||
set(ANTLR_ArgumentList_OUTPUTS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListBaseVisitor.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListBaseVisitor.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListLexer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListLexer.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListParser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListParser.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListVisitor.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arg_parser/generated/ArgumentListVisitor.h
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(parsers PRIVATE ${ANTLR_ArgumentList_OUTPUTS})
|
||||
source_group("arg_parser\\generated" FILES ${ANTLR_ArgumentList_OUTPUTS})
|
||||
add_parser(arg_parser/ArgumentList.g4)
|
||||
add_parser(action_expression/ActionExpression.g4)
|
||||
|
||||
target_include_directories(parsers PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
grammar ActionExpression;
|
||||
|
||||
expression_main: expression EOF;
|
||||
|
||||
expression
|
||||
: value_expression
|
||||
| random_range_expression
|
||||
| parenthesis_expression
|
||||
| variable_reference_expression
|
||||
| expression ( PLUS | MINUS ) expression
|
||||
;
|
||||
|
||||
parenthesis_expression: L_PAREN expression R_PAREN;
|
||||
|
||||
value_expression
|
||||
: literal_expression
|
||||
| vec3d_constructor
|
||||
;
|
||||
|
||||
literal_expression
|
||||
: FLOAT
|
||||
| INT
|
||||
| STRING
|
||||
;
|
||||
|
||||
// variable references are just a list of identifiers instead of being applied to expressions to avoid introducing types
|
||||
// for all the intermediate parts
|
||||
variable_reference_expression: IDENTIFIER (DOT IDENTIFIER)*;
|
||||
|
||||
random_range_expression: RAND_L_PAREN expression expression R_PAREN;
|
||||
|
||||
vec3d_constructor: L_PAREN expression expression expression R_PAREN;
|
||||
|
||||
PLUS: '+';
|
||||
MINUS: '-';
|
||||
|
||||
FLOAT
|
||||
: '-'? ([0-9]+ '.' [0-9]+)
|
||||
;
|
||||
|
||||
INT: '-'? [0-9]+;
|
||||
|
||||
// The left parenthesis for the start of a random range
|
||||
RAND_L_PAREN: '~(';
|
||||
|
||||
L_PAREN: '(';
|
||||
R_PAREN: ')';
|
||||
|
||||
IDENTIFIER: [a-zA-Z][a-zA-Z0-9]*;
|
||||
|
||||
DOT: '.';
|
||||
|
||||
STRING: '"' .*? '"';
|
||||
|
||||
SPACE
|
||||
: [ \t\r\n] -> skip
|
||||
;
|
||||
|
||||
OTHER
|
||||
: .
|
||||
;
|
||||
@@ -0,0 +1,43 @@
|
||||
token literal names:
|
||||
null
|
||||
'+'
|
||||
'-'
|
||||
null
|
||||
null
|
||||
'~('
|
||||
'('
|
||||
')'
|
||||
null
|
||||
'.'
|
||||
null
|
||||
null
|
||||
null
|
||||
|
||||
token symbolic names:
|
||||
null
|
||||
PLUS
|
||||
MINUS
|
||||
FLOAT
|
||||
INT
|
||||
RAND_L_PAREN
|
||||
L_PAREN
|
||||
R_PAREN
|
||||
IDENTIFIER
|
||||
DOT
|
||||
STRING
|
||||
SPACE
|
||||
OTHER
|
||||
|
||||
rule names:
|
||||
expression_main
|
||||
expression
|
||||
parenthesis_expression
|
||||
value_expression
|
||||
literal_expression
|
||||
variable_reference_expression
|
||||
random_range_expression
|
||||
vec3d_constructor
|
||||
|
||||
|
||||
atn:
|
||||
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 14, 66, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 27, 10, 3, 3, 3, 3, 3, 3, 3, 7, 3, 32, 10, 3, 12, 3, 14, 3, 35, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 5, 5, 43, 10, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 7, 7, 50, 10, 7, 12, 7, 14, 7, 53, 11, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 2, 3, 4, 10, 2, 4, 6, 8, 10, 12, 14, 16, 2, 4, 3, 2, 3, 4, 4, 2, 5, 6, 12, 12, 2, 63, 2, 18, 3, 2, 2, 2, 4, 26, 3, 2, 2, 2, 6, 36, 3, 2, 2, 2, 8, 42, 3, 2, 2, 2, 10, 44, 3, 2, 2, 2, 12, 46, 3, 2, 2, 2, 14, 54, 3, 2, 2, 2, 16, 59, 3, 2, 2, 2, 18, 19, 5, 4, 3, 2, 19, 20, 7, 2, 2, 3, 20, 3, 3, 2, 2, 2, 21, 22, 8, 3, 1, 2, 22, 27, 5, 8, 5, 2, 23, 27, 5, 14, 8, 2, 24, 27, 5, 6, 4, 2, 25, 27, 5, 12, 7, 2, 26, 21, 3, 2, 2, 2, 26, 23, 3, 2, 2, 2, 26, 24, 3, 2, 2, 2, 26, 25, 3, 2, 2, 2, 27, 33, 3, 2, 2, 2, 28, 29, 12, 3, 2, 2, 29, 30, 9, 2, 2, 2, 30, 32, 5, 4, 3, 4, 31, 28, 3, 2, 2, 2, 32, 35, 3, 2, 2, 2, 33, 31, 3, 2, 2, 2, 33, 34, 3, 2, 2, 2, 34, 5, 3, 2, 2, 2, 35, 33, 3, 2, 2, 2, 36, 37, 7, 8, 2, 2, 37, 38, 5, 4, 3, 2, 38, 39, 7, 9, 2, 2, 39, 7, 3, 2, 2, 2, 40, 43, 5, 10, 6, 2, 41, 43, 5, 16, 9, 2, 42, 40, 3, 2, 2, 2, 42, 41, 3, 2, 2, 2, 43, 9, 3, 2, 2, 2, 44, 45, 9, 3, 2, 2, 45, 11, 3, 2, 2, 2, 46, 51, 7, 10, 2, 2, 47, 48, 7, 11, 2, 2, 48, 50, 7, 10, 2, 2, 49, 47, 3, 2, 2, 2, 50, 53, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 13, 3, 2, 2, 2, 53, 51, 3, 2, 2, 2, 54, 55, 7, 7, 2, 2, 55, 56, 5, 4, 3, 2, 56, 57, 5, 4, 3, 2, 57, 58, 7, 9, 2, 2, 58, 15, 3, 2, 2, 2, 59, 60, 7, 8, 2, 2, 60, 61, 5, 4, 3, 2, 61, 62, 5, 4, 3, 2, 62, 63, 5, 4, 3, 2, 63, 64, 7, 9, 2, 2, 64, 17, 3, 2, 2, 2, 6, 26, 33, 42, 51]
|
||||
@@ -0,0 +1,18 @@
|
||||
PLUS=1
|
||||
MINUS=2
|
||||
FLOAT=3
|
||||
INT=4
|
||||
RAND_L_PAREN=5
|
||||
L_PAREN=6
|
||||
R_PAREN=7
|
||||
IDENTIFIER=8
|
||||
DOT=9
|
||||
STRING=10
|
||||
SPACE=11
|
||||
OTHER=12
|
||||
'+'=1
|
||||
'-'=2
|
||||
'~('=5
|
||||
'('=6
|
||||
')'=7
|
||||
'.'=9
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
|
||||
#include "ActionExpressionBaseVisitor.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
#include "ActionExpressionVisitor.h"
|
||||
|
||||
|
||||
/**
|
||||
* This class provides an empty implementation of ActionExpressionVisitor, which can be
|
||||
* extended to create a visitor which only needs to handle a subset of the available methods.
|
||||
*/
|
||||
class ActionExpressionBaseVisitor : public ActionExpressionVisitor {
|
||||
public:
|
||||
|
||||
virtual antlrcpp::Any visitExpression_main(ActionExpressionParser::Expression_mainContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitExpression(ActionExpressionParser::ExpressionContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitParenthesis_expression(ActionExpressionParser::Parenthesis_expressionContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitValue_expression(ActionExpressionParser::Value_expressionContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitLiteral_expression(ActionExpressionParser::Literal_expressionContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitVariable_reference_expression(ActionExpressionParser::Variable_reference_expressionContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitRandom_range_expression(ActionExpressionParser::Random_range_expressionContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
|
||||
#include "ActionExpressionLexer.h"
|
||||
|
||||
|
||||
using namespace antlr4;
|
||||
|
||||
|
||||
ActionExpressionLexer::ActionExpressionLexer(CharStream *input) : Lexer(input) {
|
||||
_interpreter = new atn::LexerATNSimulator(this, _atn, _decisionToDFA, _sharedContextCache);
|
||||
}
|
||||
|
||||
ActionExpressionLexer::~ActionExpressionLexer() {
|
||||
delete _interpreter;
|
||||
}
|
||||
|
||||
std::string ActionExpressionLexer::getGrammarFileName() const {
|
||||
return "ActionExpression.g4";
|
||||
}
|
||||
|
||||
const std::vector<std::string>& ActionExpressionLexer::getRuleNames() const {
|
||||
return _ruleNames;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& ActionExpressionLexer::getChannelNames() const {
|
||||
return _channelNames;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& ActionExpressionLexer::getModeNames() const {
|
||||
return _modeNames;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& ActionExpressionLexer::getTokenNames() const {
|
||||
return _tokenNames;
|
||||
}
|
||||
|
||||
dfa::Vocabulary& ActionExpressionLexer::getVocabulary() const {
|
||||
return _vocabulary;
|
||||
}
|
||||
|
||||
const std::vector<uint16_t> ActionExpressionLexer::getSerializedATN() const {
|
||||
return _serializedATN;
|
||||
}
|
||||
|
||||
const atn::ATN& ActionExpressionLexer::getATN() const {
|
||||
return _atn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Static vars and initialization.
|
||||
std::vector<dfa::DFA> ActionExpressionLexer::_decisionToDFA;
|
||||
atn::PredictionContextCache ActionExpressionLexer::_sharedContextCache;
|
||||
|
||||
// We own the ATN which in turn owns the ATN states.
|
||||
atn::ATN ActionExpressionLexer::_atn;
|
||||
std::vector<uint16_t> ActionExpressionLexer::_serializedATN;
|
||||
|
||||
std::vector<std::string> ActionExpressionLexer::_ruleNames = {
|
||||
u8"PLUS", u8"MINUS", u8"FLOAT", u8"INT", u8"RAND_L_PAREN", u8"L_PAREN",
|
||||
u8"R_PAREN", u8"IDENTIFIER", u8"DOT", u8"STRING", u8"SPACE", u8"OTHER"
|
||||
};
|
||||
|
||||
std::vector<std::string> ActionExpressionLexer::_channelNames = {
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
|
||||
};
|
||||
|
||||
std::vector<std::string> ActionExpressionLexer::_modeNames = {
|
||||
u8"DEFAULT_MODE"
|
||||
};
|
||||
|
||||
std::vector<std::string> ActionExpressionLexer::_literalNames = {
|
||||
"", u8"'+'", u8"'-'", "", "", u8"'~('", u8"'('", u8"')'", "", u8"'.'"
|
||||
};
|
||||
|
||||
std::vector<std::string> ActionExpressionLexer::_symbolicNames = {
|
||||
"", u8"PLUS", u8"MINUS", u8"FLOAT", u8"INT", u8"RAND_L_PAREN", u8"L_PAREN",
|
||||
u8"R_PAREN", u8"IDENTIFIER", u8"DOT", u8"STRING", u8"SPACE", u8"OTHER"
|
||||
};
|
||||
|
||||
dfa::Vocabulary ActionExpressionLexer::_vocabulary(_literalNames, _symbolicNames);
|
||||
|
||||
std::vector<std::string> ActionExpressionLexer::_tokenNames;
|
||||
|
||||
ActionExpressionLexer::Initializer::Initializer() {
|
||||
// This code could be in a static initializer lambda, but VS doesn't allow access to private class members from there.
|
||||
for (size_t i = 0; i < _symbolicNames.size(); ++i) {
|
||||
std::string name = _vocabulary.getLiteralName(i);
|
||||
if (name.empty()) {
|
||||
name = _vocabulary.getSymbolicName(i);
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
_tokenNames.push_back("<INVALID>");
|
||||
} else {
|
||||
_tokenNames.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
_serializedATN = {
|
||||
0x3, 0x608b, 0xa72a, 0x8133, 0xb9ed, 0x417c, 0x3be7, 0x7786, 0x5964,
|
||||
0x2, 0xe, 0x54, 0x8, 0x1, 0x4, 0x2, 0x9, 0x2, 0x4, 0x3, 0x9, 0x3, 0x4,
|
||||
0x4, 0x9, 0x4, 0x4, 0x5, 0x9, 0x5, 0x4, 0x6, 0x9, 0x6, 0x4, 0x7, 0x9,
|
||||
0x7, 0x4, 0x8, 0x9, 0x8, 0x4, 0x9, 0x9, 0x9, 0x4, 0xa, 0x9, 0xa, 0x4,
|
||||
0xb, 0x9, 0xb, 0x4, 0xc, 0x9, 0xc, 0x4, 0xd, 0x9, 0xd, 0x3, 0x2, 0x3,
|
||||
0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x5, 0x4, 0x21, 0xa, 0x4, 0x3, 0x4,
|
||||
0x6, 0x4, 0x24, 0xa, 0x4, 0xd, 0x4, 0xe, 0x4, 0x25, 0x3, 0x4, 0x3, 0x4,
|
||||
0x6, 0x4, 0x2a, 0xa, 0x4, 0xd, 0x4, 0xe, 0x4, 0x2b, 0x3, 0x5, 0x5, 0x5,
|
||||
0x2f, 0xa, 0x5, 0x3, 0x5, 0x6, 0x5, 0x32, 0xa, 0x5, 0xd, 0x5, 0xe, 0x5,
|
||||
0x33, 0x3, 0x6, 0x3, 0x6, 0x3, 0x6, 0x3, 0x7, 0x3, 0x7, 0x3, 0x8, 0x3,
|
||||
0x8, 0x3, 0x9, 0x3, 0x9, 0x7, 0x9, 0x3f, 0xa, 0x9, 0xc, 0x9, 0xe, 0x9,
|
||||
0x42, 0xb, 0x9, 0x3, 0xa, 0x3, 0xa, 0x3, 0xb, 0x3, 0xb, 0x7, 0xb, 0x48,
|
||||
0xa, 0xb, 0xc, 0xb, 0xe, 0xb, 0x4b, 0xb, 0xb, 0x3, 0xb, 0x3, 0xb, 0x3,
|
||||
0xc, 0x3, 0xc, 0x3, 0xc, 0x3, 0xc, 0x3, 0xd, 0x3, 0xd, 0x3, 0x49, 0x2,
|
||||
0xe, 0x3, 0x3, 0x5, 0x4, 0x7, 0x5, 0x9, 0x6, 0xb, 0x7, 0xd, 0x8, 0xf,
|
||||
0x9, 0x11, 0xa, 0x13, 0xb, 0x15, 0xc, 0x17, 0xd, 0x19, 0xe, 0x3, 0x2,
|
||||
0x6, 0x3, 0x2, 0x32, 0x3b, 0x4, 0x2, 0x43, 0x5c, 0x63, 0x7c, 0x5, 0x2,
|
||||
0x32, 0x3b, 0x43, 0x5c, 0x63, 0x7c, 0x5, 0x2, 0xb, 0xc, 0xf, 0xf, 0x22,
|
||||
0x22, 0x2, 0x5a, 0x2, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x5, 0x3, 0x2, 0x2,
|
||||
0x2, 0x2, 0x7, 0x3, 0x2, 0x2, 0x2, 0x2, 0x9, 0x3, 0x2, 0x2, 0x2, 0x2,
|
||||
0xb, 0x3, 0x2, 0x2, 0x2, 0x2, 0xd, 0x3, 0x2, 0x2, 0x2, 0x2, 0xf, 0x3,
|
||||
0x2, 0x2, 0x2, 0x2, 0x11, 0x3, 0x2, 0x2, 0x2, 0x2, 0x13, 0x3, 0x2, 0x2,
|
||||
0x2, 0x2, 0x15, 0x3, 0x2, 0x2, 0x2, 0x2, 0x17, 0x3, 0x2, 0x2, 0x2, 0x2,
|
||||
0x19, 0x3, 0x2, 0x2, 0x2, 0x3, 0x1b, 0x3, 0x2, 0x2, 0x2, 0x5, 0x1d,
|
||||
0x3, 0x2, 0x2, 0x2, 0x7, 0x20, 0x3, 0x2, 0x2, 0x2, 0x9, 0x2e, 0x3, 0x2,
|
||||
0x2, 0x2, 0xb, 0x35, 0x3, 0x2, 0x2, 0x2, 0xd, 0x38, 0x3, 0x2, 0x2, 0x2,
|
||||
0xf, 0x3a, 0x3, 0x2, 0x2, 0x2, 0x11, 0x3c, 0x3, 0x2, 0x2, 0x2, 0x13,
|
||||
0x43, 0x3, 0x2, 0x2, 0x2, 0x15, 0x45, 0x3, 0x2, 0x2, 0x2, 0x17, 0x4e,
|
||||
0x3, 0x2, 0x2, 0x2, 0x19, 0x52, 0x3, 0x2, 0x2, 0x2, 0x1b, 0x1c, 0x7,
|
||||
0x2d, 0x2, 0x2, 0x1c, 0x4, 0x3, 0x2, 0x2, 0x2, 0x1d, 0x1e, 0x7, 0x2f,
|
||||
0x2, 0x2, 0x1e, 0x6, 0x3, 0x2, 0x2, 0x2, 0x1f, 0x21, 0x7, 0x2f, 0x2,
|
||||
0x2, 0x20, 0x1f, 0x3, 0x2, 0x2, 0x2, 0x20, 0x21, 0x3, 0x2, 0x2, 0x2,
|
||||
0x21, 0x23, 0x3, 0x2, 0x2, 0x2, 0x22, 0x24, 0x9, 0x2, 0x2, 0x2, 0x23,
|
||||
0x22, 0x3, 0x2, 0x2, 0x2, 0x24, 0x25, 0x3, 0x2, 0x2, 0x2, 0x25, 0x23,
|
||||
0x3, 0x2, 0x2, 0x2, 0x25, 0x26, 0x3, 0x2, 0x2, 0x2, 0x26, 0x27, 0x3,
|
||||
0x2, 0x2, 0x2, 0x27, 0x29, 0x7, 0x30, 0x2, 0x2, 0x28, 0x2a, 0x9, 0x2,
|
||||
0x2, 0x2, 0x29, 0x28, 0x3, 0x2, 0x2, 0x2, 0x2a, 0x2b, 0x3, 0x2, 0x2,
|
||||
0x2, 0x2b, 0x29, 0x3, 0x2, 0x2, 0x2, 0x2b, 0x2c, 0x3, 0x2, 0x2, 0x2,
|
||||
0x2c, 0x8, 0x3, 0x2, 0x2, 0x2, 0x2d, 0x2f, 0x7, 0x2f, 0x2, 0x2, 0x2e,
|
||||
0x2d, 0x3, 0x2, 0x2, 0x2, 0x2e, 0x2f, 0x3, 0x2, 0x2, 0x2, 0x2f, 0x31,
|
||||
0x3, 0x2, 0x2, 0x2, 0x30, 0x32, 0x9, 0x2, 0x2, 0x2, 0x31, 0x30, 0x3,
|
||||
0x2, 0x2, 0x2, 0x32, 0x33, 0x3, 0x2, 0x2, 0x2, 0x33, 0x31, 0x3, 0x2,
|
||||
0x2, 0x2, 0x33, 0x34, 0x3, 0x2, 0x2, 0x2, 0x34, 0xa, 0x3, 0x2, 0x2,
|
||||
0x2, 0x35, 0x36, 0x7, 0x80, 0x2, 0x2, 0x36, 0x37, 0x7, 0x2a, 0x2, 0x2,
|
||||
0x37, 0xc, 0x3, 0x2, 0x2, 0x2, 0x38, 0x39, 0x7, 0x2a, 0x2, 0x2, 0x39,
|
||||
0xe, 0x3, 0x2, 0x2, 0x2, 0x3a, 0x3b, 0x7, 0x2b, 0x2, 0x2, 0x3b, 0x10,
|
||||
0x3, 0x2, 0x2, 0x2, 0x3c, 0x40, 0x9, 0x3, 0x2, 0x2, 0x3d, 0x3f, 0x9,
|
||||
0x4, 0x2, 0x2, 0x3e, 0x3d, 0x3, 0x2, 0x2, 0x2, 0x3f, 0x42, 0x3, 0x2,
|
||||
0x2, 0x2, 0x40, 0x3e, 0x3, 0x2, 0x2, 0x2, 0x40, 0x41, 0x3, 0x2, 0x2,
|
||||
0x2, 0x41, 0x12, 0x3, 0x2, 0x2, 0x2, 0x42, 0x40, 0x3, 0x2, 0x2, 0x2,
|
||||
0x43, 0x44, 0x7, 0x30, 0x2, 0x2, 0x44, 0x14, 0x3, 0x2, 0x2, 0x2, 0x45,
|
||||
0x49, 0x7, 0x24, 0x2, 0x2, 0x46, 0x48, 0xb, 0x2, 0x2, 0x2, 0x47, 0x46,
|
||||
0x3, 0x2, 0x2, 0x2, 0x48, 0x4b, 0x3, 0x2, 0x2, 0x2, 0x49, 0x4a, 0x3,
|
||||
0x2, 0x2, 0x2, 0x49, 0x47, 0x3, 0x2, 0x2, 0x2, 0x4a, 0x4c, 0x3, 0x2,
|
||||
0x2, 0x2, 0x4b, 0x49, 0x3, 0x2, 0x2, 0x2, 0x4c, 0x4d, 0x7, 0x24, 0x2,
|
||||
0x2, 0x4d, 0x16, 0x3, 0x2, 0x2, 0x2, 0x4e, 0x4f, 0x9, 0x5, 0x2, 0x2,
|
||||
0x4f, 0x50, 0x3, 0x2, 0x2, 0x2, 0x50, 0x51, 0x8, 0xc, 0x2, 0x2, 0x51,
|
||||
0x18, 0x3, 0x2, 0x2, 0x2, 0x52, 0x53, 0xb, 0x2, 0x2, 0x2, 0x53, 0x1a,
|
||||
0x3, 0x2, 0x2, 0x2, 0xa, 0x2, 0x20, 0x25, 0x2b, 0x2e, 0x33, 0x40, 0x49,
|
||||
0x3, 0x8, 0x2, 0x2,
|
||||
};
|
||||
|
||||
atn::ATNDeserializer deserializer;
|
||||
_atn = deserializer.deserialize(_serializedATN);
|
||||
|
||||
size_t count = _atn.getNumberOfDecisions();
|
||||
_decisionToDFA.reserve(count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
_decisionToDFA.emplace_back(_atn.getDecisionState(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
ActionExpressionLexer::Initializer ActionExpressionLexer::_init;
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class ActionExpressionLexer : public antlr4::Lexer {
|
||||
public:
|
||||
enum {
|
||||
PLUS = 1, MINUS = 2, FLOAT = 3, INT = 4, RAND_L_PAREN = 5, L_PAREN = 6,
|
||||
R_PAREN = 7, IDENTIFIER = 8, DOT = 9, STRING = 10, SPACE = 11, OTHER = 12
|
||||
};
|
||||
|
||||
ActionExpressionLexer(antlr4::CharStream *input);
|
||||
~ActionExpressionLexer();
|
||||
|
||||
virtual std::string getGrammarFileName() const override;
|
||||
virtual const std::vector<std::string>& getRuleNames() const override;
|
||||
|
||||
virtual const std::vector<std::string>& getChannelNames() const override;
|
||||
virtual const std::vector<std::string>& getModeNames() const override;
|
||||
virtual const std::vector<std::string>& getTokenNames() const override; // deprecated, use vocabulary instead
|
||||
virtual antlr4::dfa::Vocabulary& getVocabulary() const override;
|
||||
|
||||
virtual const std::vector<uint16_t> getSerializedATN() const override;
|
||||
virtual const antlr4::atn::ATN& getATN() const override;
|
||||
|
||||
private:
|
||||
static std::vector<antlr4::dfa::DFA> _decisionToDFA;
|
||||
static antlr4::atn::PredictionContextCache _sharedContextCache;
|
||||
static std::vector<std::string> _ruleNames;
|
||||
static std::vector<std::string> _tokenNames;
|
||||
static std::vector<std::string> _channelNames;
|
||||
static std::vector<std::string> _modeNames;
|
||||
|
||||
static std::vector<std::string> _literalNames;
|
||||
static std::vector<std::string> _symbolicNames;
|
||||
static antlr4::dfa::Vocabulary _vocabulary;
|
||||
static antlr4::atn::ATN _atn;
|
||||
static std::vector<uint16_t> _serializedATN;
|
||||
|
||||
|
||||
// Individual action functions triggered by action() above.
|
||||
|
||||
// Individual semantic predicate functions triggered by sempred() above.
|
||||
|
||||
struct Initializer {
|
||||
Initializer();
|
||||
};
|
||||
static Initializer _init;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
token literal names:
|
||||
null
|
||||
'+'
|
||||
'-'
|
||||
null
|
||||
null
|
||||
'~('
|
||||
'('
|
||||
')'
|
||||
null
|
||||
'.'
|
||||
null
|
||||
null
|
||||
null
|
||||
|
||||
token symbolic names:
|
||||
null
|
||||
PLUS
|
||||
MINUS
|
||||
FLOAT
|
||||
INT
|
||||
RAND_L_PAREN
|
||||
L_PAREN
|
||||
R_PAREN
|
||||
IDENTIFIER
|
||||
DOT
|
||||
STRING
|
||||
SPACE
|
||||
OTHER
|
||||
|
||||
rule names:
|
||||
PLUS
|
||||
MINUS
|
||||
FLOAT
|
||||
INT
|
||||
RAND_L_PAREN
|
||||
L_PAREN
|
||||
R_PAREN
|
||||
IDENTIFIER
|
||||
DOT
|
||||
STRING
|
||||
SPACE
|
||||
OTHER
|
||||
|
||||
channel names:
|
||||
DEFAULT_TOKEN_CHANNEL
|
||||
HIDDEN
|
||||
|
||||
mode names:
|
||||
DEFAULT_MODE
|
||||
|
||||
atn:
|
||||
[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 14, 84, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 5, 4, 33, 10, 4, 3, 4, 6, 4, 36, 10, 4, 13, 4, 14, 4, 37, 3, 4, 3, 4, 6, 4, 42, 10, 4, 13, 4, 14, 4, 43, 3, 5, 5, 5, 47, 10, 5, 3, 5, 6, 5, 50, 10, 5, 13, 5, 14, 5, 51, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 7, 9, 63, 10, 9, 12, 9, 14, 9, 66, 11, 9, 3, 10, 3, 10, 3, 11, 3, 11, 7, 11, 72, 10, 11, 12, 11, 14, 11, 75, 11, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 73, 2, 14, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 3, 2, 6, 3, 2, 50, 59, 4, 2, 67, 92, 99, 124, 5, 2, 50, 59, 67, 92, 99, 124, 5, 2, 11, 12, 15, 15, 34, 34, 2, 90, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 3, 27, 3, 2, 2, 2, 5, 29, 3, 2, 2, 2, 7, 32, 3, 2, 2, 2, 9, 46, 3, 2, 2, 2, 11, 53, 3, 2, 2, 2, 13, 56, 3, 2, 2, 2, 15, 58, 3, 2, 2, 2, 17, 60, 3, 2, 2, 2, 19, 67, 3, 2, 2, 2, 21, 69, 3, 2, 2, 2, 23, 78, 3, 2, 2, 2, 25, 82, 3, 2, 2, 2, 27, 28, 7, 45, 2, 2, 28, 4, 3, 2, 2, 2, 29, 30, 7, 47, 2, 2, 30, 6, 3, 2, 2, 2, 31, 33, 7, 47, 2, 2, 32, 31, 3, 2, 2, 2, 32, 33, 3, 2, 2, 2, 33, 35, 3, 2, 2, 2, 34, 36, 9, 2, 2, 2, 35, 34, 3, 2, 2, 2, 36, 37, 3, 2, 2, 2, 37, 35, 3, 2, 2, 2, 37, 38, 3, 2, 2, 2, 38, 39, 3, 2, 2, 2, 39, 41, 7, 48, 2, 2, 40, 42, 9, 2, 2, 2, 41, 40, 3, 2, 2, 2, 42, 43, 3, 2, 2, 2, 43, 41, 3, 2, 2, 2, 43, 44, 3, 2, 2, 2, 44, 8, 3, 2, 2, 2, 45, 47, 7, 47, 2, 2, 46, 45, 3, 2, 2, 2, 46, 47, 3, 2, 2, 2, 47, 49, 3, 2, 2, 2, 48, 50, 9, 2, 2, 2, 49, 48, 3, 2, 2, 2, 50, 51, 3, 2, 2, 2, 51, 49, 3, 2, 2, 2, 51, 52, 3, 2, 2, 2, 52, 10, 3, 2, 2, 2, 53, 54, 7, 128, 2, 2, 54, 55, 7, 42, 2, 2, 55, 12, 3, 2, 2, 2, 56, 57, 7, 42, 2, 2, 57, 14, 3, 2, 2, 2, 58, 59, 7, 43, 2, 2, 59, 16, 3, 2, 2, 2, 60, 64, 9, 3, 2, 2, 61, 63, 9, 4, 2, 2, 62, 61, 3, 2, 2, 2, 63, 66, 3, 2, 2, 2, 64, 62, 3, 2, 2, 2, 64, 65, 3, 2, 2, 2, 65, 18, 3, 2, 2, 2, 66, 64, 3, 2, 2, 2, 67, 68, 7, 48, 2, 2, 68, 20, 3, 2, 2, 2, 69, 73, 7, 36, 2, 2, 70, 72, 11, 2, 2, 2, 71, 70, 3, 2, 2, 2, 72, 75, 3, 2, 2, 2, 73, 74, 3, 2, 2, 2, 73, 71, 3, 2, 2, 2, 74, 76, 3, 2, 2, 2, 75, 73, 3, 2, 2, 2, 76, 77, 7, 36, 2, 2, 77, 22, 3, 2, 2, 2, 78, 79, 9, 5, 2, 2, 79, 80, 3, 2, 2, 2, 80, 81, 8, 12, 2, 2, 81, 24, 3, 2, 2, 2, 82, 83, 11, 2, 2, 2, 83, 26, 3, 2, 2, 2, 10, 2, 32, 37, 43, 46, 51, 64, 73, 3, 8, 2, 2]
|
||||
@@ -0,0 +1,18 @@
|
||||
PLUS=1
|
||||
MINUS=2
|
||||
FLOAT=3
|
||||
INT=4
|
||||
RAND_L_PAREN=5
|
||||
L_PAREN=6
|
||||
R_PAREN=7
|
||||
IDENTIFIER=8
|
||||
DOT=9
|
||||
STRING=10
|
||||
SPACE=11
|
||||
OTHER=12
|
||||
'+'=1
|
||||
'-'=2
|
||||
'~('=5
|
||||
'('=6
|
||||
')'=7
|
||||
'.'=9
|
||||
@@ -0,0 +1,732 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
|
||||
#include "ActionExpressionVisitor.h"
|
||||
|
||||
#include "ActionExpressionParser.h"
|
||||
|
||||
|
||||
using namespace antlrcpp;
|
||||
using namespace antlr4;
|
||||
|
||||
ActionExpressionParser::ActionExpressionParser(TokenStream *input) : Parser(input) {
|
||||
_interpreter = new atn::ParserATNSimulator(this, _atn, _decisionToDFA, _sharedContextCache);
|
||||
}
|
||||
|
||||
ActionExpressionParser::~ActionExpressionParser() {
|
||||
delete _interpreter;
|
||||
}
|
||||
|
||||
std::string ActionExpressionParser::getGrammarFileName() const {
|
||||
return "ActionExpression.g4";
|
||||
}
|
||||
|
||||
const std::vector<std::string>& ActionExpressionParser::getRuleNames() const {
|
||||
return _ruleNames;
|
||||
}
|
||||
|
||||
dfa::Vocabulary& ActionExpressionParser::getVocabulary() const {
|
||||
return _vocabulary;
|
||||
}
|
||||
|
||||
|
||||
//----------------- Expression_mainContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Expression_mainContext::Expression_mainContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::Expression_mainContext::expression() {
|
||||
return getRuleContext<ActionExpressionParser::ExpressionContext>(0);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Expression_mainContext::EOF() {
|
||||
return getToken(ActionExpressionParser::EOF, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Expression_mainContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleExpression_main;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Expression_mainContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitExpression_main(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Expression_mainContext* ActionExpressionParser::expression_main() {
|
||||
Expression_mainContext *_localctx = _tracker.createInstance<Expression_mainContext>(_ctx, getState());
|
||||
enterRule(_localctx, 0, ActionExpressionParser::RuleExpression_main);
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(16);
|
||||
expression(0);
|
||||
setState(17);
|
||||
match(ActionExpressionParser::EOF);
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- ExpressionContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::ExpressionContext::ExpressionContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
ActionExpressionParser::Value_expressionContext* ActionExpressionParser::ExpressionContext::value_expression() {
|
||||
return getRuleContext<ActionExpressionParser::Value_expressionContext>(0);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Random_range_expressionContext* ActionExpressionParser::ExpressionContext::random_range_expression() {
|
||||
return getRuleContext<ActionExpressionParser::Random_range_expressionContext>(0);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Parenthesis_expressionContext* ActionExpressionParser::ExpressionContext::parenthesis_expression() {
|
||||
return getRuleContext<ActionExpressionParser::Parenthesis_expressionContext>(0);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Variable_reference_expressionContext* ActionExpressionParser::ExpressionContext::variable_reference_expression() {
|
||||
return getRuleContext<ActionExpressionParser::Variable_reference_expressionContext>(0);
|
||||
}
|
||||
|
||||
std::vector<ActionExpressionParser::ExpressionContext *> ActionExpressionParser::ExpressionContext::expression() {
|
||||
return getRuleContexts<ActionExpressionParser::ExpressionContext>();
|
||||
}
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::ExpressionContext::expression(size_t i) {
|
||||
return getRuleContext<ActionExpressionParser::ExpressionContext>(i);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::ExpressionContext::PLUS() {
|
||||
return getToken(ActionExpressionParser::PLUS, 0);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::ExpressionContext::MINUS() {
|
||||
return getToken(ActionExpressionParser::MINUS, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::ExpressionContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleExpression;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::ExpressionContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitExpression(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::expression() {
|
||||
return expression(0);
|
||||
}
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::expression(int precedence) {
|
||||
ParserRuleContext *parentContext = _ctx;
|
||||
size_t parentState = getState();
|
||||
ActionExpressionParser::ExpressionContext *_localctx = _tracker.createInstance<ExpressionContext>(_ctx, parentState);
|
||||
ActionExpressionParser::ExpressionContext *previousContext = _localctx;
|
||||
(void)previousContext; // Silence compiler, in case the context is not used by generated code.
|
||||
size_t startState = 2;
|
||||
enterRecursionRule(_localctx, 2, ActionExpressionParser::RuleExpression, precedence);
|
||||
|
||||
size_t _la = 0;
|
||||
|
||||
auto onExit = finally([=] {
|
||||
unrollRecursionContexts(parentContext);
|
||||
});
|
||||
try {
|
||||
size_t alt;
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(24);
|
||||
_errHandler->sync(this);
|
||||
switch (getInterpreter<atn::ParserATNSimulator>()->adaptivePredict(_input, 0, _ctx)) {
|
||||
case 1: {
|
||||
setState(20);
|
||||
value_expression();
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
setState(21);
|
||||
random_range_expression();
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
setState(22);
|
||||
parenthesis_expression();
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
setState(23);
|
||||
variable_reference_expression();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
_ctx->stop = _input->LT(-1);
|
||||
setState(31);
|
||||
_errHandler->sync(this);
|
||||
alt = getInterpreter<atn::ParserATNSimulator>()->adaptivePredict(_input, 1, _ctx);
|
||||
while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) {
|
||||
if (alt == 1) {
|
||||
if (!_parseListeners.empty())
|
||||
triggerExitRuleEvent();
|
||||
previousContext = _localctx;
|
||||
_localctx = _tracker.createInstance<ExpressionContext>(parentContext, parentState);
|
||||
pushNewRecursionContext(_localctx, startState, RuleExpression);
|
||||
setState(26);
|
||||
|
||||
if (!(precpred(_ctx, 1))) throw FailedPredicateException(this, "precpred(_ctx, 1)");
|
||||
setState(27);
|
||||
_la = _input->LA(1);
|
||||
if (!(_la == ActionExpressionParser::PLUS
|
||||
|
||||
|| _la == ActionExpressionParser::MINUS)) {
|
||||
_errHandler->recoverInline(this);
|
||||
}
|
||||
else {
|
||||
_errHandler->reportMatch(this);
|
||||
consume();
|
||||
}
|
||||
setState(28);
|
||||
expression(2);
|
||||
}
|
||||
setState(33);
|
||||
_errHandler->sync(this);
|
||||
alt = getInterpreter<atn::ParserATNSimulator>()->adaptivePredict(_input, 1, _ctx);
|
||||
}
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- Parenthesis_expressionContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Parenthesis_expressionContext::Parenthesis_expressionContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Parenthesis_expressionContext::L_PAREN() {
|
||||
return getToken(ActionExpressionParser::L_PAREN, 0);
|
||||
}
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::Parenthesis_expressionContext::expression() {
|
||||
return getRuleContext<ActionExpressionParser::ExpressionContext>(0);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Parenthesis_expressionContext::R_PAREN() {
|
||||
return getToken(ActionExpressionParser::R_PAREN, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Parenthesis_expressionContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleParenthesis_expression;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Parenthesis_expressionContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitParenthesis_expression(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Parenthesis_expressionContext* ActionExpressionParser::parenthesis_expression() {
|
||||
Parenthesis_expressionContext *_localctx = _tracker.createInstance<Parenthesis_expressionContext>(_ctx, getState());
|
||||
enterRule(_localctx, 4, ActionExpressionParser::RuleParenthesis_expression);
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(34);
|
||||
match(ActionExpressionParser::L_PAREN);
|
||||
setState(35);
|
||||
expression(0);
|
||||
setState(36);
|
||||
match(ActionExpressionParser::R_PAREN);
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- Value_expressionContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Value_expressionContext::Value_expressionContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
ActionExpressionParser::Literal_expressionContext* ActionExpressionParser::Value_expressionContext::literal_expression() {
|
||||
return getRuleContext<ActionExpressionParser::Literal_expressionContext>(0);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Vec3d_constructorContext* ActionExpressionParser::Value_expressionContext::vec3d_constructor() {
|
||||
return getRuleContext<ActionExpressionParser::Vec3d_constructorContext>(0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Value_expressionContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleValue_expression;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Value_expressionContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitValue_expression(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Value_expressionContext* ActionExpressionParser::value_expression() {
|
||||
Value_expressionContext *_localctx = _tracker.createInstance<Value_expressionContext>(_ctx, getState());
|
||||
enterRule(_localctx, 6, ActionExpressionParser::RuleValue_expression);
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
setState(40);
|
||||
_errHandler->sync(this);
|
||||
switch (_input->LA(1)) {
|
||||
case ActionExpressionParser::FLOAT:
|
||||
case ActionExpressionParser::INT:
|
||||
case ActionExpressionParser::STRING: {
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(38);
|
||||
literal_expression();
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionExpressionParser::L_PAREN: {
|
||||
enterOuterAlt(_localctx, 2);
|
||||
setState(39);
|
||||
vec3d_constructor();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw NoViableAltException(this);
|
||||
}
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- Literal_expressionContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Literal_expressionContext::Literal_expressionContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Literal_expressionContext::FLOAT() {
|
||||
return getToken(ActionExpressionParser::FLOAT, 0);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Literal_expressionContext::INT() {
|
||||
return getToken(ActionExpressionParser::INT, 0);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Literal_expressionContext::STRING() {
|
||||
return getToken(ActionExpressionParser::STRING, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Literal_expressionContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleLiteral_expression;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Literal_expressionContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitLiteral_expression(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Literal_expressionContext* ActionExpressionParser::literal_expression() {
|
||||
Literal_expressionContext *_localctx = _tracker.createInstance<Literal_expressionContext>(_ctx, getState());
|
||||
enterRule(_localctx, 8, ActionExpressionParser::RuleLiteral_expression);
|
||||
size_t _la = 0;
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(42);
|
||||
_la = _input->LA(1);
|
||||
if (!((((_la & ~ 0x3fULL) == 0) &&
|
||||
((1ULL << _la) & ((1ULL << ActionExpressionParser::FLOAT)
|
||||
| (1ULL << ActionExpressionParser::INT)
|
||||
| (1ULL << ActionExpressionParser::STRING))) != 0))) {
|
||||
_errHandler->recoverInline(this);
|
||||
}
|
||||
else {
|
||||
_errHandler->reportMatch(this);
|
||||
consume();
|
||||
}
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- Variable_reference_expressionContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Variable_reference_expressionContext::Variable_reference_expressionContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
std::vector<tree::TerminalNode *> ActionExpressionParser::Variable_reference_expressionContext::IDENTIFIER() {
|
||||
return getTokens(ActionExpressionParser::IDENTIFIER);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Variable_reference_expressionContext::IDENTIFIER(size_t i) {
|
||||
return getToken(ActionExpressionParser::IDENTIFIER, i);
|
||||
}
|
||||
|
||||
std::vector<tree::TerminalNode *> ActionExpressionParser::Variable_reference_expressionContext::DOT() {
|
||||
return getTokens(ActionExpressionParser::DOT);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Variable_reference_expressionContext::DOT(size_t i) {
|
||||
return getToken(ActionExpressionParser::DOT, i);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Variable_reference_expressionContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleVariable_reference_expression;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Variable_reference_expressionContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitVariable_reference_expression(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Variable_reference_expressionContext* ActionExpressionParser::variable_reference_expression() {
|
||||
Variable_reference_expressionContext *_localctx = _tracker.createInstance<Variable_reference_expressionContext>(_ctx, getState());
|
||||
enterRule(_localctx, 10, ActionExpressionParser::RuleVariable_reference_expression);
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
size_t alt;
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(44);
|
||||
match(ActionExpressionParser::IDENTIFIER);
|
||||
setState(49);
|
||||
_errHandler->sync(this);
|
||||
alt = getInterpreter<atn::ParserATNSimulator>()->adaptivePredict(_input, 3, _ctx);
|
||||
while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) {
|
||||
if (alt == 1) {
|
||||
setState(45);
|
||||
match(ActionExpressionParser::DOT);
|
||||
setState(46);
|
||||
match(ActionExpressionParser::IDENTIFIER);
|
||||
}
|
||||
setState(51);
|
||||
_errHandler->sync(this);
|
||||
alt = getInterpreter<atn::ParserATNSimulator>()->adaptivePredict(_input, 3, _ctx);
|
||||
}
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- Random_range_expressionContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Random_range_expressionContext::Random_range_expressionContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Random_range_expressionContext::RAND_L_PAREN() {
|
||||
return getToken(ActionExpressionParser::RAND_L_PAREN, 0);
|
||||
}
|
||||
|
||||
std::vector<ActionExpressionParser::ExpressionContext *> ActionExpressionParser::Random_range_expressionContext::expression() {
|
||||
return getRuleContexts<ActionExpressionParser::ExpressionContext>();
|
||||
}
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::Random_range_expressionContext::expression(size_t i) {
|
||||
return getRuleContext<ActionExpressionParser::ExpressionContext>(i);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Random_range_expressionContext::R_PAREN() {
|
||||
return getToken(ActionExpressionParser::R_PAREN, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Random_range_expressionContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleRandom_range_expression;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Random_range_expressionContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitRandom_range_expression(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Random_range_expressionContext* ActionExpressionParser::random_range_expression() {
|
||||
Random_range_expressionContext *_localctx = _tracker.createInstance<Random_range_expressionContext>(_ctx, getState());
|
||||
enterRule(_localctx, 12, ActionExpressionParser::RuleRandom_range_expression);
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(52);
|
||||
match(ActionExpressionParser::RAND_L_PAREN);
|
||||
setState(53);
|
||||
expression(0);
|
||||
setState(54);
|
||||
expression(0);
|
||||
setState(55);
|
||||
match(ActionExpressionParser::R_PAREN);
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
//----------------- Vec3d_constructorContext ------------------------------------------------------------------
|
||||
|
||||
ActionExpressionParser::Vec3d_constructorContext::Vec3d_constructorContext(ParserRuleContext *parent, size_t invokingState)
|
||||
: ParserRuleContext(parent, invokingState) {
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Vec3d_constructorContext::L_PAREN() {
|
||||
return getToken(ActionExpressionParser::L_PAREN, 0);
|
||||
}
|
||||
|
||||
std::vector<ActionExpressionParser::ExpressionContext *> ActionExpressionParser::Vec3d_constructorContext::expression() {
|
||||
return getRuleContexts<ActionExpressionParser::ExpressionContext>();
|
||||
}
|
||||
|
||||
ActionExpressionParser::ExpressionContext* ActionExpressionParser::Vec3d_constructorContext::expression(size_t i) {
|
||||
return getRuleContext<ActionExpressionParser::ExpressionContext>(i);
|
||||
}
|
||||
|
||||
tree::TerminalNode* ActionExpressionParser::Vec3d_constructorContext::R_PAREN() {
|
||||
return getToken(ActionExpressionParser::R_PAREN, 0);
|
||||
}
|
||||
|
||||
|
||||
size_t ActionExpressionParser::Vec3d_constructorContext::getRuleIndex() const {
|
||||
return ActionExpressionParser::RuleVec3d_constructor;
|
||||
}
|
||||
|
||||
|
||||
antlrcpp::Any ActionExpressionParser::Vec3d_constructorContext::accept(tree::ParseTreeVisitor *visitor) {
|
||||
if (auto parserVisitor = dynamic_cast<ActionExpressionVisitor*>(visitor))
|
||||
return parserVisitor->visitVec3d_constructor(this);
|
||||
else
|
||||
return visitor->visitChildren(this);
|
||||
}
|
||||
|
||||
ActionExpressionParser::Vec3d_constructorContext* ActionExpressionParser::vec3d_constructor() {
|
||||
Vec3d_constructorContext *_localctx = _tracker.createInstance<Vec3d_constructorContext>(_ctx, getState());
|
||||
enterRule(_localctx, 14, ActionExpressionParser::RuleVec3d_constructor);
|
||||
|
||||
auto onExit = finally([=] {
|
||||
exitRule();
|
||||
});
|
||||
try {
|
||||
enterOuterAlt(_localctx, 1);
|
||||
setState(57);
|
||||
match(ActionExpressionParser::L_PAREN);
|
||||
setState(58);
|
||||
expression(0);
|
||||
setState(59);
|
||||
expression(0);
|
||||
setState(60);
|
||||
expression(0);
|
||||
setState(61);
|
||||
match(ActionExpressionParser::R_PAREN);
|
||||
|
||||
}
|
||||
catch (RecognitionException &e) {
|
||||
_errHandler->reportError(this, e);
|
||||
_localctx->exception = std::current_exception();
|
||||
_errHandler->recover(this, _localctx->exception);
|
||||
}
|
||||
|
||||
return _localctx;
|
||||
}
|
||||
|
||||
bool ActionExpressionParser::sempred(RuleContext *context, size_t ruleIndex, size_t predicateIndex) {
|
||||
switch (ruleIndex) {
|
||||
case 1: return expressionSempred(dynamic_cast<ExpressionContext *>(context), predicateIndex);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActionExpressionParser::expressionSempred(ExpressionContext *_localctx, size_t predicateIndex) {
|
||||
switch (predicateIndex) {
|
||||
case 0: return precpred(_ctx, 1);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Static vars and initialization.
|
||||
std::vector<dfa::DFA> ActionExpressionParser::_decisionToDFA;
|
||||
atn::PredictionContextCache ActionExpressionParser::_sharedContextCache;
|
||||
|
||||
// We own the ATN which in turn owns the ATN states.
|
||||
atn::ATN ActionExpressionParser::_atn;
|
||||
std::vector<uint16_t> ActionExpressionParser::_serializedATN;
|
||||
|
||||
std::vector<std::string> ActionExpressionParser::_ruleNames = {
|
||||
"expression_main", "expression", "parenthesis_expression", "value_expression",
|
||||
"literal_expression", "variable_reference_expression", "random_range_expression",
|
||||
"vec3d_constructor"
|
||||
};
|
||||
|
||||
std::vector<std::string> ActionExpressionParser::_literalNames = {
|
||||
"", "'+'", "'-'", "", "", "'~('", "'('", "')'", "", "'.'"
|
||||
};
|
||||
|
||||
std::vector<std::string> ActionExpressionParser::_symbolicNames = {
|
||||
"", "PLUS", "MINUS", "FLOAT", "INT", "RAND_L_PAREN", "L_PAREN", "R_PAREN",
|
||||
"IDENTIFIER", "DOT", "STRING", "SPACE", "OTHER"
|
||||
};
|
||||
|
||||
dfa::Vocabulary ActionExpressionParser::_vocabulary(_literalNames, _symbolicNames);
|
||||
|
||||
std::vector<std::string> ActionExpressionParser::_tokenNames;
|
||||
|
||||
ActionExpressionParser::Initializer::Initializer() {
|
||||
for (size_t i = 0; i < _symbolicNames.size(); ++i) {
|
||||
std::string name = _vocabulary.getLiteralName(i);
|
||||
if (name.empty()) {
|
||||
name = _vocabulary.getSymbolicName(i);
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
_tokenNames.push_back("<INVALID>");
|
||||
} else {
|
||||
_tokenNames.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
_serializedATN = {
|
||||
0x3, 0x608b, 0xa72a, 0x8133, 0xb9ed, 0x417c, 0x3be7, 0x7786, 0x5964,
|
||||
0x3, 0xe, 0x42, 0x4, 0x2, 0x9, 0x2, 0x4, 0x3, 0x9, 0x3, 0x4, 0x4, 0x9,
|
||||
0x4, 0x4, 0x5, 0x9, 0x5, 0x4, 0x6, 0x9, 0x6, 0x4, 0x7, 0x9, 0x7, 0x4,
|
||||
0x8, 0x9, 0x8, 0x4, 0x9, 0x9, 0x9, 0x3, 0x2, 0x3, 0x2, 0x3, 0x2, 0x3,
|
||||
0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x5, 0x3, 0x1b, 0xa, 0x3,
|
||||
0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x7, 0x3, 0x20, 0xa, 0x3, 0xc, 0x3, 0xe,
|
||||
0x3, 0x23, 0xb, 0x3, 0x3, 0x4, 0x3, 0x4, 0x3, 0x4, 0x3, 0x4, 0x3, 0x5,
|
||||
0x3, 0x5, 0x5, 0x5, 0x2b, 0xa, 0x5, 0x3, 0x6, 0x3, 0x6, 0x3, 0x7, 0x3,
|
||||
0x7, 0x3, 0x7, 0x7, 0x7, 0x32, 0xa, 0x7, 0xc, 0x7, 0xe, 0x7, 0x35, 0xb,
|
||||
0x7, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x8, 0x3, 0x9, 0x3,
|
||||
0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0x9, 0x3, 0x9, 0x2, 0x3, 0x4,
|
||||
0xa, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x2, 0x4, 0x3, 0x2, 0x3,
|
||||
0x4, 0x4, 0x2, 0x5, 0x6, 0xc, 0xc, 0x2, 0x3f, 0x2, 0x12, 0x3, 0x2, 0x2,
|
||||
0x2, 0x4, 0x1a, 0x3, 0x2, 0x2, 0x2, 0x6, 0x24, 0x3, 0x2, 0x2, 0x2, 0x8,
|
||||
0x2a, 0x3, 0x2, 0x2, 0x2, 0xa, 0x2c, 0x3, 0x2, 0x2, 0x2, 0xc, 0x2e,
|
||||
0x3, 0x2, 0x2, 0x2, 0xe, 0x36, 0x3, 0x2, 0x2, 0x2, 0x10, 0x3b, 0x3,
|
||||
0x2, 0x2, 0x2, 0x12, 0x13, 0x5, 0x4, 0x3, 0x2, 0x13, 0x14, 0x7, 0x2,
|
||||
0x2, 0x3, 0x14, 0x3, 0x3, 0x2, 0x2, 0x2, 0x15, 0x16, 0x8, 0x3, 0x1,
|
||||
0x2, 0x16, 0x1b, 0x5, 0x8, 0x5, 0x2, 0x17, 0x1b, 0x5, 0xe, 0x8, 0x2,
|
||||
0x18, 0x1b, 0x5, 0x6, 0x4, 0x2, 0x19, 0x1b, 0x5, 0xc, 0x7, 0x2, 0x1a,
|
||||
0x15, 0x3, 0x2, 0x2, 0x2, 0x1a, 0x17, 0x3, 0x2, 0x2, 0x2, 0x1a, 0x18,
|
||||
0x3, 0x2, 0x2, 0x2, 0x1a, 0x19, 0x3, 0x2, 0x2, 0x2, 0x1b, 0x21, 0x3,
|
||||
0x2, 0x2, 0x2, 0x1c, 0x1d, 0xc, 0x3, 0x2, 0x2, 0x1d, 0x1e, 0x9, 0x2,
|
||||
0x2, 0x2, 0x1e, 0x20, 0x5, 0x4, 0x3, 0x4, 0x1f, 0x1c, 0x3, 0x2, 0x2,
|
||||
0x2, 0x20, 0x23, 0x3, 0x2, 0x2, 0x2, 0x21, 0x1f, 0x3, 0x2, 0x2, 0x2,
|
||||
0x21, 0x22, 0x3, 0x2, 0x2, 0x2, 0x22, 0x5, 0x3, 0x2, 0x2, 0x2, 0x23,
|
||||
0x21, 0x3, 0x2, 0x2, 0x2, 0x24, 0x25, 0x7, 0x8, 0x2, 0x2, 0x25, 0x26,
|
||||
0x5, 0x4, 0x3, 0x2, 0x26, 0x27, 0x7, 0x9, 0x2, 0x2, 0x27, 0x7, 0x3,
|
||||
0x2, 0x2, 0x2, 0x28, 0x2b, 0x5, 0xa, 0x6, 0x2, 0x29, 0x2b, 0x5, 0x10,
|
||||
0x9, 0x2, 0x2a, 0x28, 0x3, 0x2, 0x2, 0x2, 0x2a, 0x29, 0x3, 0x2, 0x2,
|
||||
0x2, 0x2b, 0x9, 0x3, 0x2, 0x2, 0x2, 0x2c, 0x2d, 0x9, 0x3, 0x2, 0x2,
|
||||
0x2d, 0xb, 0x3, 0x2, 0x2, 0x2, 0x2e, 0x33, 0x7, 0xa, 0x2, 0x2, 0x2f,
|
||||
0x30, 0x7, 0xb, 0x2, 0x2, 0x30, 0x32, 0x7, 0xa, 0x2, 0x2, 0x31, 0x2f,
|
||||
0x3, 0x2, 0x2, 0x2, 0x32, 0x35, 0x3, 0x2, 0x2, 0x2, 0x33, 0x31, 0x3,
|
||||
0x2, 0x2, 0x2, 0x33, 0x34, 0x3, 0x2, 0x2, 0x2, 0x34, 0xd, 0x3, 0x2,
|
||||
0x2, 0x2, 0x35, 0x33, 0x3, 0x2, 0x2, 0x2, 0x36, 0x37, 0x7, 0x7, 0x2,
|
||||
0x2, 0x37, 0x38, 0x5, 0x4, 0x3, 0x2, 0x38, 0x39, 0x5, 0x4, 0x3, 0x2,
|
||||
0x39, 0x3a, 0x7, 0x9, 0x2, 0x2, 0x3a, 0xf, 0x3, 0x2, 0x2, 0x2, 0x3b,
|
||||
0x3c, 0x7, 0x8, 0x2, 0x2, 0x3c, 0x3d, 0x5, 0x4, 0x3, 0x2, 0x3d, 0x3e,
|
||||
0x5, 0x4, 0x3, 0x2, 0x3e, 0x3f, 0x5, 0x4, 0x3, 0x2, 0x3f, 0x40, 0x7,
|
||||
0x9, 0x2, 0x2, 0x40, 0x11, 0x3, 0x2, 0x2, 0x2, 0x6, 0x1a, 0x21, 0x2a,
|
||||
0x33,
|
||||
};
|
||||
|
||||
atn::ATNDeserializer deserializer;
|
||||
_atn = deserializer.deserialize(_serializedATN);
|
||||
|
||||
size_t count = _atn.getNumberOfDecisions();
|
||||
_decisionToDFA.reserve(count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
_decisionToDFA.emplace_back(_atn.getDecisionState(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
ActionExpressionParser::Initializer ActionExpressionParser::_init;
|
||||
@@ -0,0 +1,192 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class ActionExpressionParser : public antlr4::Parser {
|
||||
public:
|
||||
enum {
|
||||
PLUS = 1, MINUS = 2, FLOAT = 3, INT = 4, RAND_L_PAREN = 5, L_PAREN = 6,
|
||||
R_PAREN = 7, IDENTIFIER = 8, DOT = 9, STRING = 10, SPACE = 11, OTHER = 12
|
||||
};
|
||||
|
||||
enum {
|
||||
RuleExpression_main = 0, RuleExpression = 1, RuleParenthesis_expression = 2,
|
||||
RuleValue_expression = 3, RuleLiteral_expression = 4, RuleVariable_reference_expression = 5,
|
||||
RuleRandom_range_expression = 6, RuleVec3d_constructor = 7
|
||||
};
|
||||
|
||||
ActionExpressionParser(antlr4::TokenStream *input);
|
||||
~ActionExpressionParser();
|
||||
|
||||
virtual std::string getGrammarFileName() const override;
|
||||
virtual const antlr4::atn::ATN& getATN() const override { return _atn; };
|
||||
virtual const std::vector<std::string>& getTokenNames() const override { return _tokenNames; }; // deprecated: use vocabulary instead.
|
||||
virtual const std::vector<std::string>& getRuleNames() const override;
|
||||
virtual antlr4::dfa::Vocabulary& getVocabulary() const override;
|
||||
|
||||
|
||||
class Expression_mainContext;
|
||||
class ExpressionContext;
|
||||
class Parenthesis_expressionContext;
|
||||
class Value_expressionContext;
|
||||
class Literal_expressionContext;
|
||||
class Variable_reference_expressionContext;
|
||||
class Random_range_expressionContext;
|
||||
class Vec3d_constructorContext;
|
||||
|
||||
class Expression_mainContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Expression_mainContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
ExpressionContext *expression();
|
||||
antlr4::tree::TerminalNode *EOF();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Expression_mainContext* expression_main();
|
||||
|
||||
class ExpressionContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
ExpressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
Value_expressionContext *value_expression();
|
||||
Random_range_expressionContext *random_range_expression();
|
||||
Parenthesis_expressionContext *parenthesis_expression();
|
||||
Variable_reference_expressionContext *variable_reference_expression();
|
||||
std::vector<ExpressionContext *> expression();
|
||||
ExpressionContext* expression(size_t i);
|
||||
antlr4::tree::TerminalNode *PLUS();
|
||||
antlr4::tree::TerminalNode *MINUS();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
ExpressionContext* expression();
|
||||
ExpressionContext* expression(int precedence);
|
||||
class Parenthesis_expressionContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Parenthesis_expressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *L_PAREN();
|
||||
ExpressionContext *expression();
|
||||
antlr4::tree::TerminalNode *R_PAREN();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Parenthesis_expressionContext* parenthesis_expression();
|
||||
|
||||
class Value_expressionContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Value_expressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
Literal_expressionContext *literal_expression();
|
||||
Vec3d_constructorContext *vec3d_constructor();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Value_expressionContext* value_expression();
|
||||
|
||||
class Literal_expressionContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Literal_expressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *FLOAT();
|
||||
antlr4::tree::TerminalNode *INT();
|
||||
antlr4::tree::TerminalNode *STRING();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Literal_expressionContext* literal_expression();
|
||||
|
||||
class Variable_reference_expressionContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Variable_reference_expressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
std::vector<antlr4::tree::TerminalNode *> IDENTIFIER();
|
||||
antlr4::tree::TerminalNode* IDENTIFIER(size_t i);
|
||||
std::vector<antlr4::tree::TerminalNode *> DOT();
|
||||
antlr4::tree::TerminalNode* DOT(size_t i);
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Variable_reference_expressionContext* variable_reference_expression();
|
||||
|
||||
class Random_range_expressionContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Random_range_expressionContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *RAND_L_PAREN();
|
||||
std::vector<ExpressionContext *> expression();
|
||||
ExpressionContext* expression(size_t i);
|
||||
antlr4::tree::TerminalNode *R_PAREN();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Random_range_expressionContext* random_range_expression();
|
||||
|
||||
class Vec3d_constructorContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
Vec3d_constructorContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *L_PAREN();
|
||||
std::vector<ExpressionContext *> expression();
|
||||
ExpressionContext* expression(size_t i);
|
||||
antlr4::tree::TerminalNode *R_PAREN();
|
||||
|
||||
|
||||
virtual antlrcpp::Any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
Vec3d_constructorContext* vec3d_constructor();
|
||||
|
||||
|
||||
virtual bool sempred(antlr4::RuleContext *_localctx, size_t ruleIndex, size_t predicateIndex) override;
|
||||
bool expressionSempred(ExpressionContext *_localctx, size_t predicateIndex);
|
||||
|
||||
private:
|
||||
static std::vector<antlr4::dfa::DFA> _decisionToDFA;
|
||||
static antlr4::atn::PredictionContextCache _sharedContextCache;
|
||||
static std::vector<std::string> _ruleNames;
|
||||
static std::vector<std::string> _tokenNames;
|
||||
|
||||
static std::vector<std::string> _literalNames;
|
||||
static std::vector<std::string> _symbolicNames;
|
||||
static antlr4::dfa::Vocabulary _vocabulary;
|
||||
static antlr4::atn::ATN _atn;
|
||||
static std::vector<uint16_t> _serializedATN;
|
||||
|
||||
|
||||
struct Initializer {
|
||||
Initializer();
|
||||
};
|
||||
static Initializer _init;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
|
||||
#include "ActionExpressionVisitor.h"
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
// Generated from /media/cache/code/asarium/fs2open.github.com/parsers/action_expression/ActionExpression.g4 by ANTLR 4.8
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
#include "ActionExpressionParser.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This class defines an abstract visitor for a parse tree
|
||||
* produced by ActionExpressionParser.
|
||||
*/
|
||||
class ActionExpressionVisitor : public antlr4::tree::AbstractParseTreeVisitor {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Visit parse trees produced by ActionExpressionParser.
|
||||
*/
|
||||
virtual antlrcpp::Any visitExpression_main(ActionExpressionParser::Expression_mainContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitExpression(ActionExpressionParser::ExpressionContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitParenthesis_expression(ActionExpressionParser::Parenthesis_expressionContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitValue_expression(ActionExpressionParser::Value_expressionContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitLiteral_expression(ActionExpressionParser::Literal_expressionContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitVariable_reference_expression(ActionExpressionParser::Variable_reference_expressionContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitRandom_range_expression(ActionExpressionParser::Random_range_expressionContext *context) = 0;
|
||||
|
||||
virtual antlrcpp::Any visitVec3d_constructor(ActionExpressionParser::Vec3d_constructorContext *context) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
set(gtest_force_shared_crt "${MSVC_USE_RUNTIME_DLL}" CACHE BOOL "Always use msvcrt.dll" FORCE)
|
||||
|
||||
set(GOOGLETEST_VERSION 1.10.0)
|
||||
add_subdirectory(gtest)
|
||||
|
||||
target_compile_definitions(gtest PUBLIC "$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>")
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
########################################################################
|
||||
# Note: CMake support is community-based. The maintainers do not use CMake
|
||||
# internally.
|
||||
#
|
||||
# CMake build script for Google Test.
|
||||
#
|
||||
# To run the tests for Google Test itself on Linux, use 'make test' or
|
||||
@@ -40,8 +43,12 @@ endif()
|
||||
# as ${gtest_SOURCE_DIR} and to the root binary directory as
|
||||
# ${gtest_BINARY_DIR}.
|
||||
# Language "C" is required for find_package(Threads).
|
||||
|
||||
# Project version:
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS 3.0)
|
||||
project(gtest CXX C)
|
||||
set(PROJECT_VERSION ${GOOGLETEST_VERSION})
|
||||
else()
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
project(gtest VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
||||
@@ -93,7 +100,7 @@ if (INSTALL_GTEST)
|
||||
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated" CACHE INTERNAL "")
|
||||
set(cmake_files_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${cmake_package_name}")
|
||||
set(version_file "${generated_dir}/${cmake_package_name}ConfigVersion.cmake")
|
||||
write_basic_package_version_file(${version_file} COMPATIBILITY AnyNewerVersion)
|
||||
write_basic_package_version_file(${version_file} VERSION ${GOOGLETEST_VERSION} COMPATIBILITY AnyNewerVersion)
|
||||
install(EXPORT ${targets_export_name}
|
||||
NAMESPACE ${cmake_package_name}::
|
||||
DESTINATION ${cmake_files_install_dir})
|
||||
@@ -181,7 +188,7 @@ if (gtest_build_tests)
|
||||
"$project_bin = \"${CMAKE_BINARY_DIR}/bin/$<CONFIG>\"
|
||||
$env:Path = \"$project_bin;$env:Path\"
|
||||
& $args")
|
||||
elseif (MINGW)
|
||||
elseif (MINGW OR CYGWIN)
|
||||
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1"
|
||||
CONTENT
|
||||
"$project_bin = (cygpath --windows ${CMAKE_BINARY_DIR}/bin)
|
||||
@@ -195,7 +202,6 @@ $env:Path = \"$project_bin;$env:Path\"
|
||||
cxx_test(googletest-death-test-test gtest_main)
|
||||
cxx_test(gtest_environment_test gtest)
|
||||
cxx_test(googletest-filepath-test gtest_main)
|
||||
cxx_test(googletest-linked-ptr-test gtest_main)
|
||||
cxx_test(googletest-listener-test gtest_main)
|
||||
cxx_test(gtest_main_unittest gtest_main)
|
||||
cxx_test(googletest-message-test gtest_main)
|
||||
@@ -219,6 +225,7 @@ $env:Path = \"$project_bin;$env:Path\"
|
||||
test/gtest-typed-test2_test.cc)
|
||||
cxx_test(gtest_unittest gtest_main)
|
||||
cxx_test(gtest-unittest-api_test gtest)
|
||||
cxx_test(gtest_skip_in_environment_setup_test gtest_main)
|
||||
cxx_test(gtest_skip_test gtest_main)
|
||||
|
||||
############################################################
|
||||
@@ -259,6 +266,8 @@ $env:Path = \"$project_bin;$env:Path\"
|
||||
cxx_executable(googletest-break-on-failure-unittest_ test gtest)
|
||||
py_test(googletest-break-on-failure-unittest)
|
||||
|
||||
py_test(gtest_skip_environment_check_output_test)
|
||||
|
||||
# Visual Studio .NET 2003 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003
|
||||
cxx_executable_with_flags(
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
Copyright 2008, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,244 @@
|
||||
### Generic Build Instructions
|
||||
|
||||
#### Setup
|
||||
|
||||
To build Google Test and your tests that use it, you need to tell your build
|
||||
system where to find its headers and source files. The exact way to do it
|
||||
depends on which build system you use, and is usually straightforward.
|
||||
|
||||
### Build with CMake
|
||||
|
||||
Google Test comes with a CMake build script (
|
||||
[CMakeLists.txt](https://github.com/google/googletest/blob/master/CMakeLists.txt))
|
||||
that can be used on a wide range of platforms ("C" stands for cross-platform.).
|
||||
If you don't have CMake installed already, you can download it for free from
|
||||
<http://www.cmake.org/>.
|
||||
|
||||
CMake works by generating native makefiles or build projects that can be used in
|
||||
the compiler environment of your choice. You can either build Google Test as a
|
||||
standalone project or it can be incorporated into an existing CMake build for
|
||||
another project.
|
||||
|
||||
#### Standalone CMake Project
|
||||
|
||||
When building Google Test as a standalone project, the typical workflow starts
|
||||
with:
|
||||
|
||||
mkdir mybuild # Create a directory to hold the build output.
|
||||
cd mybuild
|
||||
cmake ${GTEST_DIR} # Generate native build scripts.
|
||||
|
||||
If you want to build Google Test's samples, you should replace the last command
|
||||
with
|
||||
|
||||
cmake -Dgtest_build_samples=ON ${GTEST_DIR}
|
||||
|
||||
If you are on a \*nix system, you should now see a Makefile in the current
|
||||
directory. Just type 'make' to build gtest.
|
||||
|
||||
If you use Windows and have Visual Studio installed, a `gtest.sln` file and
|
||||
several `.vcproj` files will be created. You can then build them using Visual
|
||||
Studio.
|
||||
|
||||
On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated.
|
||||
|
||||
#### Incorporating Into An Existing CMake Project
|
||||
|
||||
If you want to use gtest in a project which already uses CMake, then a more
|
||||
robust and flexible approach is to build gtest as part of that project directly.
|
||||
This is done by making the GoogleTest source code available to the main build
|
||||
and adding it using CMake's `add_subdirectory()` command. This has the
|
||||
significant advantage that the same compiler and linker settings are used
|
||||
between gtest and the rest of your project, so issues associated with using
|
||||
incompatible libraries (eg debug/release), etc. are avoided. This is
|
||||
particularly useful on Windows. Making GoogleTest's source code available to the
|
||||
main build can be done a few different ways:
|
||||
|
||||
* Download the GoogleTest source code manually and place it at a known
|
||||
location. This is the least flexible approach and can make it more difficult
|
||||
to use with continuous integration systems, etc.
|
||||
* Embed the GoogleTest source code as a direct copy in the main project's
|
||||
source tree. This is often the simplest approach, but is also the hardest to
|
||||
keep up to date. Some organizations may not permit this method.
|
||||
* Add GoogleTest as a git submodule or equivalent. This may not always be
|
||||
possible or appropriate. Git submodules, for example, have their own set of
|
||||
advantages and drawbacks.
|
||||
* Use CMake to download GoogleTest as part of the build's configure step. This
|
||||
is just a little more complex, but doesn't have the limitations of the other
|
||||
methods.
|
||||
|
||||
The last of the above methods is implemented with a small piece of CMake code in
|
||||
a separate file (e.g. `CMakeLists.txt.in`) which is copied to the build area and
|
||||
then invoked as a sub-build _during the CMake stage_. That directory is then
|
||||
pulled into the main build with `add_subdirectory()`. For example:
|
||||
|
||||
New file `CMakeLists.txt.in`:
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
```
|
||||
|
||||
Existing build's `CMakeLists.txt`:
|
||||
|
||||
```cmake
|
||||
# Download and unpack googletest at configure time
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker
|
||||
# settings on Windows
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
# Add googletest directly to our build. This defines
|
||||
# the gtest and gtest_main targets.
|
||||
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
# The gtest/gtest_main targets carry header search path
|
||||
# dependencies automatically when using CMake 2.8.11 or
|
||||
# later. Otherwise we have to add them here ourselves.
|
||||
if (CMAKE_VERSION VERSION_LESS 2.8.11)
|
||||
include_directories("${gtest_SOURCE_DIR}/include")
|
||||
endif()
|
||||
|
||||
# Now simply link against gtest or gtest_main as needed. Eg
|
||||
add_executable(example example.cpp)
|
||||
target_link_libraries(example gtest_main)
|
||||
add_test(NAME example_test COMMAND example)
|
||||
```
|
||||
|
||||
Note that this approach requires CMake 2.8.2 or later due to its use of the
|
||||
`ExternalProject_Add()` command. The above technique is discussed in more detail
|
||||
in [this separate article](http://crascit.com/2015/07/25/cmake-gtest/) which
|
||||
also contains a link to a fully generalized implementation of the technique.
|
||||
|
||||
##### Visual Studio Dynamic vs Static Runtimes
|
||||
|
||||
By default, new Visual Studio projects link the C runtimes dynamically but
|
||||
Google Test links them statically. This will generate an error that looks
|
||||
something like the following: gtest.lib(gtest-all.obj) : error LNK2038: mismatch
|
||||
detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value
|
||||
'MDd_DynamicDebug' in main.obj
|
||||
|
||||
Google Test already has a CMake option for this: `gtest_force_shared_crt`
|
||||
|
||||
Enabling this option will make gtest link the runtimes dynamically too, and
|
||||
match the project in which it is included.
|
||||
|
||||
#### C++ Standard Version
|
||||
|
||||
An environment that supports C++11 is required in order to successfully build
|
||||
Google Test. One way to ensure this is to specify the standard in the top-level
|
||||
project, for example by using the `set(CMAKE_CXX_STANDARD 11)` command. If this
|
||||
is not feasible, for example in a C project using Google Test for validation,
|
||||
then it can be specified by adding it to the options for cmake via the
|
||||
`DCMAKE_CXX_FLAGS` option.
|
||||
|
||||
### Tweaking Google Test
|
||||
|
||||
Google Test can be used in diverse environments. The default configuration may
|
||||
not work (or may not work well) out of the box in some environments. However,
|
||||
you can easily tweak Google Test by defining control macros on the compiler
|
||||
command line. Generally, these macros are named like `GTEST_XYZ` and you define
|
||||
them to either 1 or 0 to enable or disable a certain feature.
|
||||
|
||||
We list the most frequently used macros below. For a complete list, see file
|
||||
[include/gtest/internal/gtest-port.h](https://github.com/google/googletest/blob/master/googletest/include/gtest/internal/gtest-port.h).
|
||||
|
||||
### Multi-threaded Tests
|
||||
|
||||
Google Test is thread-safe where the pthread library is available. After
|
||||
`#include "gtest/gtest.h"`, you can check the
|
||||
`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is
|
||||
`#defined` to 1, no if it's undefined.).
|
||||
|
||||
If Google Test doesn't correctly detect whether pthread is available in your
|
||||
environment, you can force it with
|
||||
|
||||
-DGTEST_HAS_PTHREAD=1
|
||||
|
||||
or
|
||||
|
||||
-DGTEST_HAS_PTHREAD=0
|
||||
|
||||
When Google Test uses pthread, you may need to add flags to your compiler and/or
|
||||
linker to select the pthread library, or you'll get link errors. If you use the
|
||||
CMake script or the deprecated Autotools script, this is taken care of for you.
|
||||
If you use your own build script, you'll need to read your compiler and linker's
|
||||
manual to figure out what flags to add.
|
||||
|
||||
### As a Shared Library (DLL)
|
||||
|
||||
Google Test is compact, so most users can build and link it as a static library
|
||||
for the simplicity. You can choose to use Google Test as a shared library (known
|
||||
as a DLL on Windows) if you prefer.
|
||||
|
||||
To compile *gtest* as a shared library, add
|
||||
|
||||
-DGTEST_CREATE_SHARED_LIBRARY=1
|
||||
|
||||
to the compiler flags. You'll also need to tell the linker to produce a shared
|
||||
library instead - consult your linker's manual for how to do it.
|
||||
|
||||
To compile your *tests* that use the gtest shared library, add
|
||||
|
||||
-DGTEST_LINKED_AS_SHARED_LIBRARY=1
|
||||
|
||||
to the compiler flags.
|
||||
|
||||
Note: while the above steps aren't technically necessary today when using some
|
||||
compilers (e.g. GCC), they may become necessary in the future, if we decide to
|
||||
improve the speed of loading the library (see
|
||||
<http://gcc.gnu.org/wiki/Visibility> for details). Therefore you are recommended
|
||||
to always add the above flags when using Google Test as a shared library.
|
||||
Otherwise a future release of Google Test may break your build script.
|
||||
|
||||
### Avoiding Macro Name Clashes
|
||||
|
||||
In C++, macros don't obey namespaces. Therefore two libraries that both define a
|
||||
macro of the same name will clash if you `#include` both definitions. In case a
|
||||
Google Test macro clashes with another library, you can force Google Test to
|
||||
rename its macro to avoid the conflict.
|
||||
|
||||
Specifically, if both Google Test and some other code define macro FOO, you can
|
||||
add
|
||||
|
||||
-DGTEST_DONT_DEFINE_FOO=1
|
||||
|
||||
to the compiler flags to tell Google Test to change the macro's name from `FOO`
|
||||
to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`, or `TEST`. For
|
||||
example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll need to write
|
||||
|
||||
GTEST_TEST(SomeTest, DoesThis) { ... }
|
||||
|
||||
instead of
|
||||
|
||||
TEST(SomeTest, DoesThis) { ... }
|
||||
|
||||
in order to define a test.
|
||||
@@ -12,6 +12,10 @@
|
||||
# Test and Google Mock's option() definitions, and thus must be
|
||||
# called *after* the options have been defined.
|
||||
|
||||
if (POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif (POLICY CMP0054)
|
||||
|
||||
# Tweaks CMake's default compiler/linker settings to suit Google Test's needs.
|
||||
#
|
||||
# This must be a macro(), as inside a function string() can only
|
||||
@@ -22,6 +26,8 @@ macro(fix_default_compiler_settings_)
|
||||
# This replacement code is taken from sample in the CMake Wiki at
|
||||
# https://gitlab.kitware.com/cmake/community/wikis/FAQ#dynamic-replace.
|
||||
foreach (flag_var
|
||||
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
||||
@@ -56,7 +62,6 @@ macro(config_compiler_and_linker)
|
||||
unset(GTEST_HAS_PTHREAD)
|
||||
if (NOT gtest_disable_pthreads AND NOT MINGW)
|
||||
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(GTEST_HAS_PTHREAD ON)
|
||||
@@ -68,36 +73,20 @@ macro(config_compiler_and_linker)
|
||||
# Newlines inside flags variables break CMake's NMake generator.
|
||||
# TODO([email protected]): Add -RTCs and -RTCu to debug builds.
|
||||
set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi")
|
||||
if (MSVC_VERSION LESS 1400) # 1400 is Visual Studio 2005
|
||||
# Suppress spurious warnings MSVC 7.1 sometimes issues.
|
||||
# Forcing value to bool.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4800")
|
||||
# Copy constructor and assignment operator could not be generated.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512")
|
||||
# Compatibility warnings not applicable to Google Test.
|
||||
# Resolved overload was found by argument-dependent lookup.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4675")
|
||||
endif()
|
||||
if (MSVC_VERSION LESS 1500) # 1500 is Visual Studio 2008
|
||||
# Conditional expression is constant.
|
||||
# When compiling with /W4, we get several instances of C4127
|
||||
# (Conditional expression is constant). In our code, we disable that
|
||||
# warning on a case-by-case basis. However, on Visual Studio 2005,
|
||||
# the warning fires on std::list. Therefore on that compiler and earlier,
|
||||
# we disable the warning project-wide.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4127")
|
||||
endif()
|
||||
if (NOT (MSVC_VERSION LESS 1700)) # 1700 is Visual Studio 2012.
|
||||
# Suppress "unreachable code" warning on VS 2012 and later.
|
||||
# http://stackoverflow.com/questions/3232669 explains the issue.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4702")
|
||||
endif()
|
||||
|
||||
set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
|
||||
set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
|
||||
set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
|
||||
set(cxx_no_exception_flags "-EHs-c- -D_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_rtti_flags "-GR-")
|
||||
# Suppress "unreachable code" warning
|
||||
# http://stackoverflow.com/questions/3232669 explains the issue.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4702")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion")
|
||||
set(cxx_exception_flags "-fexceptions")
|
||||
set(cxx_no_exception_flags "-fno-exceptions")
|
||||
set(cxx_strict_flags "-W -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wunused-parameter -Wcast-align -Wchar-subscripts -Winline -Wredundant-decls")
|
||||
set(cxx_no_rtti_flags "-fno-rtti")
|
||||
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(cxx_base_flags "-Wall -Wshadow -Werror")
|
||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0)
|
||||
@@ -219,7 +208,7 @@ endfunction()
|
||||
# is built from the given source files with the given compiler flags.
|
||||
function(cxx_executable_with_flags name cxx_flags libs)
|
||||
add_executable(${name} ${ARGN})
|
||||
if (MSVC AND (NOT (MSVC_VERSION LESS 1700))) # 1700 is Visual Studio 2012.
|
||||
if (MSVC)
|
||||
# BigObj required for tests.
|
||||
set(cxx_flags "${cxx_flags} -bigobj")
|
||||
endif()
|
||||
|
||||
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user