mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-12 19:06:09 -10:00
* Add ability for a Lua sexp parameter to require a 'parent' parameter * Add dockpoint as a return type * variable conflicts * var name * qtfred * address feedback
246 lines
7.5 KiB
C++
246 lines
7.5 KiB
C++
#include "EngineSEXP.h"
|
|
|
|
#include "sexp_lookup.h"
|
|
|
|
#include "parse/sexp.h"
|
|
|
|
namespace sexp {
|
|
|
|
EngineSEXPFactory::ArgumentListBuilder::ArgumentListBuilder(EngineSEXPFactory* parent) : _parent(parent) {}
|
|
EngineSEXPFactory::ArgumentListBuilder& EngineSEXPFactory::ArgumentListBuilder::arg(int type, SCP_string help_text)
|
|
{
|
|
argument arg;
|
|
arg.type = type;
|
|
arg.help_text = std::move(help_text);
|
|
|
|
_parent->_arguments.emplace_back(std::move(arg));
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory::ArgumentListBuilder& EngineSEXPFactory::ArgumentListBuilder::beginOptional()
|
|
{
|
|
Assertion(std::find_if(_parent->_arguments.begin(),
|
|
_parent->_arguments.end(),
|
|
[](const argument& arg) { return arg.optional_marker; }) == _parent->_arguments.end(),
|
|
"Optional marker was already added!");
|
|
Assertion(std::find_if(_parent->_arguments.begin(),
|
|
_parent->_arguments.end(),
|
|
[](const argument& arg) { return arg.varargs_marker; }) == _parent->_arguments.end(),
|
|
"Adding optional arguments after varags specifier is not allowed!");
|
|
|
|
argument arg;
|
|
arg.optional_marker = true;
|
|
|
|
_parent->_arguments.emplace_back(std::move(arg));
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory::ArgumentListBuilder& EngineSEXPFactory::ArgumentListBuilder::beginVarargs()
|
|
{
|
|
Assertion(std::find_if(_parent->_arguments.begin(),
|
|
_parent->_arguments.end(),
|
|
[](const argument& arg) { return arg.varargs_marker; }) == _parent->_arguments.end(),
|
|
"Varargs marker was already added!");
|
|
|
|
argument arg;
|
|
arg.varargs_marker = true;
|
|
|
|
_parent->_arguments.emplace_back(std::move(arg));
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::ArgumentListBuilder::finishArguments() { return *_parent; }
|
|
|
|
EngineSEXPFactory::EngineSEXPFactory(std::unique_ptr<EngineSEXP> sexp) : m_sexp(std::move(sexp)) {}
|
|
|
|
EngineSEXPFactory& EngineSEXPFactory::category(int cat)
|
|
{
|
|
_category = cat;
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::category(const SCP_string& cat)
|
|
{
|
|
_categoryName = cat;
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::subcategory(int cat)
|
|
{
|
|
_category = cat;
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::subcategory(const SCP_string& subcat)
|
|
{
|
|
_subcategoryName = subcat;
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory::ArgumentListBuilder EngineSEXPFactory::beginArgList() { return {this}; }
|
|
|
|
dummy_return EngineSEXPFactory::finish()
|
|
{
|
|
Assertion(_returnType >= 0, "Engine SEXP %s: A return type has to be specified!", m_sexp->getName().c_str());
|
|
|
|
if (_category >= 0 && _category != OP_CATEGORY_NONE) {
|
|
m_sexp->setCategory(_category);
|
|
} else {
|
|
Assertion(!_categoryName.empty(), "Engine SEXP %s: A category has to be specified!", m_sexp->getName().c_str());
|
|
m_sexp->setCategoryName(_categoryName);
|
|
}
|
|
|
|
if (_subcategory >= 0 && _subcategory != OP_SUBCATEGORY_NONE) {
|
|
m_sexp->setSubcategory(_subcategory);
|
|
} else {
|
|
Assertion(!_subcategoryName.empty(), "Engine SEXP %s: A subcategory has to be specified!", m_sexp->getName().c_str());
|
|
m_sexp->setSubcategoryName(_subcategoryName);
|
|
}
|
|
|
|
m_sexp->setReturnType(_returnType);
|
|
|
|
SCP_stringstream helpStream;
|
|
helpStream << m_sexp->getName() << "\r\n";
|
|
helpStream << "\t" << _helpText << "\r\n";
|
|
|
|
// Now build the argument help text and min and max argument count
|
|
int min_args_counter = 0;
|
|
int max_args_counter = 0;
|
|
SCP_vector<int> argument_types;
|
|
SCP_vector<int> variable_argument_types;
|
|
|
|
int arg_counter = 1;
|
|
bool varargs = false;
|
|
bool optional = false;
|
|
for (const auto& arg : _arguments) {
|
|
if (arg.varargs_marker) {
|
|
helpStream << "Rest: (The following pattern repeats)\r\n";
|
|
// Number non-vararg and vararg parameters separately
|
|
arg_counter = 1;
|
|
varargs = true;
|
|
continue;
|
|
} else if (arg.optional_marker) {
|
|
optional = true;
|
|
continue;
|
|
}
|
|
|
|
helpStream << arg_counter << ": " << arg.help_text << "\r\n";
|
|
++arg_counter;
|
|
|
|
if (!varargs && !optional) {
|
|
// Keep track of minimum number of arguments. If we are either in the varargs part or the optional part then
|
|
// we have found the minimum number and should not increment it any further.
|
|
min_args_counter++;
|
|
}
|
|
// Always increment max. varargs are handled after the loop
|
|
max_args_counter++;
|
|
|
|
// Collect argument types
|
|
if (varargs) {
|
|
variable_argument_types.push_back(arg.type);
|
|
} else {
|
|
argument_types.push_back(arg.type);
|
|
}
|
|
}
|
|
|
|
if (varargs) {
|
|
max_args_counter = std::numeric_limits<int>::max();
|
|
}
|
|
|
|
m_sexp->initArguments(min_args_counter,
|
|
max_args_counter,
|
|
std::move(argument_types),
|
|
std::move(variable_argument_types));
|
|
m_sexp->setHelpText(helpStream.str());
|
|
m_sexp->setAction(std::move(_action));
|
|
|
|
add_dynamic_sexp(std::move(m_sexp));
|
|
|
|
return {};
|
|
}
|
|
EngineSEXPFactory::~EngineSEXPFactory()
|
|
{
|
|
Assertion(m_sexp == nullptr, "Did not call finish on a EngineSEXP factory!");
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::helpText(SCP_string text)
|
|
{
|
|
_helpText = std::move(text);
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::returnType(int type)
|
|
{
|
|
_returnType = type;
|
|
return *this;
|
|
}
|
|
EngineSEXPFactory& EngineSEXPFactory::action(EngineSexpAction act)
|
|
{
|
|
_action = std::move(act);
|
|
return *this;
|
|
}
|
|
EngineSEXP::EngineSEXP(const SCP_string& name) : DynamicSEXP(name) {}
|
|
|
|
EngineSEXPFactory EngineSEXP::create(const SCP_string& name)
|
|
{
|
|
return { std::unique_ptr<EngineSEXP>(new EngineSEXP(name)) };
|
|
}
|
|
void EngineSEXP::initialize()
|
|
{
|
|
// Initialize category now that we know that it is safe to do so
|
|
if (_category == OP_CATEGORY_NONE) {
|
|
_category = get_category(_categoryName);
|
|
|
|
if (_category == OP_CATEGORY_NONE) {
|
|
_category = add_category(_categoryName);
|
|
}
|
|
}
|
|
|
|
// Initialize subcategory now that we know that it is safe to do so
|
|
if (_subcategory == OP_SUBCATEGORY_NONE) {
|
|
_subcategory = get_subcategory(_subcategoryName, _category);
|
|
|
|
if (_subcategory == OP_SUBCATEGORY_NONE) {
|
|
_subcategory = add_subcategory(_category, _subcategoryName);
|
|
}
|
|
}
|
|
}
|
|
int EngineSEXP::getMinimumArguments() const { return _minArgs; }
|
|
int EngineSEXP::getMaximumArguments() const { return _maxArgs; }
|
|
int EngineSEXP::getArgumentType(int argnum) const
|
|
{
|
|
if (argnum >= static_cast<int>(_argumentTypes.size())) {
|
|
// We are in the varargs part. Adjust the number and then fit it into the varargs types array
|
|
argnum -= static_cast<int>(_argumentTypes.size());
|
|
|
|
// Error checking to avoid division by zero
|
|
if (_variableArgumentsTypes.empty()) {
|
|
return OPF_NONE;
|
|
}
|
|
|
|
argnum = argnum % _variableArgumentsTypes.size();
|
|
|
|
return _variableArgumentsTypes[argnum];
|
|
} else {
|
|
// Normal arguments so just look up the type
|
|
return _argumentTypes[argnum];
|
|
}
|
|
}
|
|
int EngineSEXP::execute(int node, int /*parent_node*/)
|
|
{
|
|
SEXPParameterExtractor extractor(node);
|
|
return _action(&extractor);
|
|
}
|
|
int EngineSEXP::getReturnType() { return _returnType; }
|
|
int EngineSEXP::getSubcategory() { return _subcategory; }
|
|
int EngineSEXP::getCategory() { return _category; }
|
|
|
|
void EngineSEXP::setCategory(int category) { _category = category; }
|
|
void EngineSEXP::setCategoryName(SCP_string category) { _categoryName = std::move(category); }
|
|
void EngineSEXP::setSubcategory(int subcategory) { _subcategory = subcategory; }
|
|
void EngineSEXP::setSubcategoryName(SCP_string subcategory) { _subcategoryName = std::move(subcategory); }
|
|
void EngineSEXP::setHelpText(SCP_string helpText) { _help_text = std::move(helpText); }
|
|
void EngineSEXP::setReturnType(int returnType) { _returnType = returnType; }
|
|
void EngineSEXP::initArguments(int minArgs, int maxArgs, SCP_vector<int> argTypes, SCP_vector<int> varargsTypes)
|
|
{
|
|
_minArgs = minArgs;
|
|
_maxArgs = maxArgs;
|
|
|
|
_argumentTypes = std::move(argTypes);
|
|
_variableArgumentsTypes = std::move(varargsTypes);
|
|
}
|
|
void EngineSEXP::setAction(EngineSexpAction action) { _action = std::move(action); }
|
|
|
|
} // namespace sexp
|