File: EngineSEXP.cpp

package info (click to toggle)
freespace2 24.2.0%2Brepack-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 43,716 kB
  • sloc: cpp: 595,001; ansic: 21,741; python: 1,174; sh: 457; makefile: 248; xml: 181
file content (252 lines) | stat: -rw-r--r-- 7,898 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#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(),
				  EngineSEXPFactory::isArgumentOptional) == _parent->_arguments.end(),
		"Optional marker was already added!");
	Assertion(std::find_if(_parent->_arguments.begin(),
				  _parent->_arguments.end(),
				  EngineSEXPFactory::isArgumentVarargsMarker) == _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(),
				  EngineSEXPFactory::isArgumentVarargsMarker) == _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;
}
bool EngineSEXPFactory::isArgumentOptional(const EngineSEXPFactory::argument& arg)
{
	return arg.optional_marker;
}
bool EngineSEXPFactory::isArgumentVarargsMarker(const EngineSEXPFactory::argument& arg)
{
	return arg.varargs_marker;
}
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