Parse the back parameter and additional ones for opcodes
This commit is contained in:
parent
e723b3d6c7
commit
09479091d8
5 changed files with 141 additions and 61 deletions
|
|
@ -6,21 +6,37 @@
|
||||||
|
|
||||||
#include "Opcode.h"
|
#include "Opcode.h"
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
|
#include "absl/strings/charconv.h"
|
||||||
|
#include <cctype>
|
||||||
sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
|
sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
|
||||||
: opcode(inputOpcode)
|
: opcode(inputOpcode)
|
||||||
, value(inputValue)
|
, value(inputValue)
|
||||||
{
|
{
|
||||||
const auto lastCharIndex = inputOpcode.find_last_not_of("1234567890");
|
|
||||||
if (lastCharIndex != inputOpcode.npos) {
|
|
||||||
int returnedValue;
|
|
||||||
absl::string_view parameterView = inputOpcode;
|
|
||||||
parameterView.remove_prefix(lastCharIndex + 1);
|
|
||||||
if (absl::SimpleAtoi(parameterView, &returnedValue)) {
|
|
||||||
parameter = returnedValue;
|
|
||||||
opcode.remove_suffix(opcode.size() - lastCharIndex - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trimInPlace(value);
|
trimInPlace(value);
|
||||||
trimInPlace(opcode);
|
trimInPlace(opcode);
|
||||||
|
size_t firstCharIndex { 0 };
|
||||||
|
auto firstNumIndex = opcode.find_first_of("1234567890");
|
||||||
|
while (firstNumIndex != opcode.npos) {
|
||||||
|
lettersOnlyHash = hash(opcode.substr(firstCharIndex, firstNumIndex - firstCharIndex), lettersOnlyHash);
|
||||||
|
firstCharIndex = opcode.find_first_not_of("1234567890", firstNumIndex);
|
||||||
|
|
||||||
|
uint32_t returnedValue;
|
||||||
|
if (firstCharIndex == absl::string_view::npos) {
|
||||||
|
if (absl::SimpleAtoi(opcode.substr(firstNumIndex), &returnedValue)) {
|
||||||
|
ASSERT(returnedValue < std::numeric_limits<uint8_t>::max());
|
||||||
|
backParameter = static_cast<uint8_t>(returnedValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (absl::SimpleAtoi(opcode.substr(firstNumIndex, firstCharIndex - firstNumIndex), &returnedValue)) {
|
||||||
|
ASSERT(returnedValue < std::numeric_limits<uint8_t>::max());
|
||||||
|
parameters.push_back(static_cast<uint8_t>(returnedValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
firstNumIndex = opcode.find_first_of("1234567890", firstCharIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstCharIndex != opcode.npos)
|
||||||
|
lettersOnlyHash = hash(opcode.substr(firstCharIndex), lettersOnlyHash);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "StringViewHelpers.h"
|
#include "StringViewHelpers.h"
|
||||||
#include <absl/types/optional.h>
|
#include <absl/types/optional.h>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
// charconv support is still sketchy with clang/gcc so we use abseil's numbers
|
// charconv support is still sketchy with clang/gcc so we use abseil's numbers
|
||||||
|
|
@ -29,8 +30,10 @@ struct Opcode {
|
||||||
Opcode(absl::string_view inputOpcode, absl::string_view inputValue);
|
Opcode(absl::string_view inputOpcode, absl::string_view inputValue);
|
||||||
absl::string_view opcode {};
|
absl::string_view opcode {};
|
||||||
absl::string_view value {};
|
absl::string_view value {};
|
||||||
// This is to handle the integer parameter of some opcodes
|
uint64_t lettersOnlyHash { Fnv1aBasis };
|
||||||
absl::optional<uint8_t> parameter;
|
// This is to handle the integer parameters of some opcodes
|
||||||
|
std::vector<uint8_t> parameters;
|
||||||
|
absl::optional<uint8_t> backParameter {};
|
||||||
LEAK_DETECTOR(Opcode);
|
LEAK_DETECTOR(Opcode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -186,8 +189,8 @@ template <class ValueType>
|
||||||
inline void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCValuePair>& target, const Range<ValueType>& validRange)
|
inline void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCValuePair>& target, const Range<ValueType>& validRange)
|
||||||
{
|
{
|
||||||
auto value = readOpcode(opcode.value, validRange);
|
auto value = readOpcode(opcode.value, validRange);
|
||||||
if (value && opcode.parameter && Default::ccNumberRange.containsWithEnd(*opcode.parameter))
|
if (value && opcode.backParameter && Default::ccNumberRange.containsWithEnd(*opcode.backParameter))
|
||||||
target = std::make_pair(*opcode.parameter, *value);
|
target = std::make_pair(*opcode.backParameter, *value);
|
||||||
else
|
else
|
||||||
target = {};
|
target = {};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@
|
||||||
bool sfz::Region::parseOpcode(const Opcode& opcode)
|
bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
{
|
{
|
||||||
// Check that the parameter is well formed
|
// Check that the parameter is well formed
|
||||||
if (opcode.parameter && !sfz::Default::ccNumberRange.containsWithEnd(*opcode.parameter)) {
|
if (opcode.backParameter && !sfz::Default::ccNumberRange.containsWithEnd(*opcode.backParameter)) {
|
||||||
DBG("Wrong parameter value (" << std::to_string(*opcode.parameter) << ") for opcode " << opcode.opcode);
|
DBG("Wrong parameter value (" << std::to_string(*opcode.backParameter) << ") for opcode " << opcode.opcode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (hash(opcode.opcode)) {
|
switch (opcode.lettersOnlyHash) {
|
||||||
// Sound source: sample playback
|
// Sound source: sample playback
|
||||||
case hash("sample"):
|
case hash("sample"):
|
||||||
{
|
{
|
||||||
|
|
@ -135,13 +135,13 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
setRangeEndFromOpcode(opcode, bendRange, Default::bendRange);
|
setRangeEndFromOpcode(opcode, bendRange, Default::bendRange);
|
||||||
break;
|
break;
|
||||||
case hash("locc"):
|
case hash("locc"):
|
||||||
if (opcode.parameter) {
|
if (opcode.backParameter) {
|
||||||
setRangeStartFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccValueRange);
|
setRangeStartFromOpcode(opcode, ccConditions[*opcode.backParameter], Default::ccValueRange);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("hicc"):
|
case hash("hicc"):
|
||||||
if (opcode.parameter)
|
if (opcode.backParameter)
|
||||||
setRangeEndFromOpcode(opcode, ccConditions[*opcode.parameter], Default::ccValueRange);
|
setRangeEndFromOpcode(opcode, ccConditions[*opcode.backParameter], Default::ccValueRange);
|
||||||
break;
|
break;
|
||||||
case hash("sw_lokey"):
|
case hash("sw_lokey"):
|
||||||
setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange);
|
setRangeStartFromOpcode(opcode, keyswitchRange, Default::keyRange);
|
||||||
|
|
@ -233,13 +233,13 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
break;
|
break;
|
||||||
case hash("on_locc"):
|
case hash("on_locc"):
|
||||||
case hash("start_locc"):
|
case hash("start_locc"):
|
||||||
if (opcode.parameter)
|
if (opcode.backParameter)
|
||||||
setRangeStartFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccTriggerValueRange);
|
setRangeStartFromOpcode(opcode, ccTriggers[*opcode.backParameter], Default::ccTriggerValueRange);
|
||||||
break;
|
break;
|
||||||
case hash("on_hicc"):
|
case hash("on_hicc"):
|
||||||
case hash("start_hicc"):
|
case hash("start_hicc"):
|
||||||
if (opcode.parameter)
|
if (opcode.backParameter)
|
||||||
setRangeEndFromOpcode(opcode, ccTriggers[*opcode.parameter], Default::ccTriggerValueRange);
|
setRangeEndFromOpcode(opcode, ccTriggers[*opcode.backParameter], Default::ccTriggerValueRange);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Performance parameters: amplifier
|
// Performance parameters: amplifier
|
||||||
|
|
@ -293,7 +293,7 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
{
|
{
|
||||||
auto value = readOpcode(opcode.value, Default::ampVelcurveRange);
|
auto value = readOpcode(opcode.value, Default::ampVelcurveRange);
|
||||||
if (value)
|
if (value)
|
||||||
velocityPoints.emplace_back(*opcode.parameter, *value);
|
velocityPoints.emplace_back(*opcode.backParameter, *value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("xfin_lokey"):
|
case hash("xfin_lokey"):
|
||||||
|
|
@ -345,23 +345,23 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("xfin_locc"):
|
case hash("xfin_locc"):
|
||||||
if (opcode.parameter) {
|
if (opcode.backParameter) {
|
||||||
setRangeStartFromOpcode(opcode, crossfadeCCInRange[*opcode.parameter], Default::ccValueRange);
|
setRangeStartFromOpcode(opcode, crossfadeCCInRange[*opcode.backParameter], Default::ccValueRange);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("xfin_hicc"):
|
case hash("xfin_hicc"):
|
||||||
if (opcode.parameter) {
|
if (opcode.backParameter) {
|
||||||
setRangeEndFromOpcode(opcode, crossfadeCCInRange[*opcode.parameter], Default::ccValueRange);
|
setRangeEndFromOpcode(opcode, crossfadeCCInRange[*opcode.backParameter], Default::ccValueRange);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("xfout_locc"):
|
case hash("xfout_locc"):
|
||||||
if (opcode.parameter) {
|
if (opcode.backParameter) {
|
||||||
setRangeStartFromOpcode(opcode, crossfadeCCOutRange[*opcode.parameter], Default::ccValueRange);
|
setRangeStartFromOpcode(opcode, crossfadeCCOutRange[*opcode.backParameter], Default::ccValueRange);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("xfout_hicc"):
|
case hash("xfout_hicc"):
|
||||||
if (opcode.parameter) {
|
if (opcode.backParameter) {
|
||||||
setRangeEndFromOpcode(opcode, crossfadeCCOutRange[*opcode.parameter], Default::ccValueRange);
|
setRangeEndFromOpcode(opcode, crossfadeCCOutRange[*opcode.backParameter], Default::ccValueRange);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("xf_cccurve"):
|
case hash("xf_cccurve"):
|
||||||
|
|
@ -433,23 +433,29 @@ bool sfz::Region::parseOpcode(const Opcode& opcode)
|
||||||
case hash("ampeg_sustain"):
|
case hash("ampeg_sustain"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.sustain, Default::egPercentRange);
|
setValueFromOpcode(opcode, amplitudeEG.sustain, Default::egPercentRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_vel2attack"):
|
case hash("ampeg_velattack"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.vel2attack, Default::egOnCCTimeRange);
|
if (!opcode.parameters.empty() && opcode.parameters.front() == 2)
|
||||||
|
setValueFromOpcode(opcode, amplitudeEG.vel2attack, Default::egOnCCTimeRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_vel2decay"):
|
case hash("ampeg_veldecay"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.vel2decay, Default::egOnCCTimeRange);
|
if (!opcode.parameters.empty() && opcode.parameters.front() == 2)
|
||||||
|
setValueFromOpcode(opcode, amplitudeEG.vel2decay, Default::egOnCCTimeRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_vel2delay"):
|
case hash("ampeg_veldelay"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.vel2delay, Default::egOnCCTimeRange);
|
if (!opcode.parameters.empty() && opcode.parameters.front() == 2)
|
||||||
|
setValueFromOpcode(opcode, amplitudeEG.vel2delay, Default::egOnCCTimeRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_vel2hold"):
|
case hash("ampeg_velhold"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.vel2hold, Default::egOnCCTimeRange);
|
if (!opcode.parameters.empty() && opcode.parameters.front() == 2)
|
||||||
|
setValueFromOpcode(opcode, amplitudeEG.vel2hold, Default::egOnCCTimeRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_vel2release"):
|
case hash("ampeg_velrelease"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.vel2release, Default::egOnCCTimeRange);
|
if (!opcode.parameters.empty() && opcode.parameters.front() == 2)
|
||||||
|
setValueFromOpcode(opcode, amplitudeEG.vel2release, Default::egOnCCTimeRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_vel2sustain"):
|
case hash("ampeg_velsustain"):
|
||||||
setValueFromOpcode(opcode, amplitudeEG.vel2sustain, Default::egOnCCPercentRange);
|
if (!opcode.parameters.empty() && opcode.parameters.front() == 2)
|
||||||
|
setValueFromOpcode(opcode, amplitudeEG.vel2sustain, Default::egOnCCPercentRange);
|
||||||
break;
|
break;
|
||||||
case hash("ampeg_attackcc"):
|
case hash("ampeg_attackcc"):
|
||||||
case hash("ampeg_attack_oncc"):
|
case hash("ampeg_attack_oncc"):
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ void sfz::Synth::clear()
|
||||||
void sfz::Synth::handleGlobalOpcodes(const std::vector<Opcode>& members)
|
void sfz::Synth::handleGlobalOpcodes(const std::vector<Opcode>& members)
|
||||||
{
|
{
|
||||||
for (auto& member : members) {
|
for (auto& member : members) {
|
||||||
switch (hash(member.opcode)) {
|
switch (member.lettersOnlyHash) {
|
||||||
case hash("sw_default"):
|
case hash("sw_default"):
|
||||||
setValueFromOpcode(member, defaultSwitch, Default::keyRange);
|
setValueFromOpcode(member, defaultSwitch, Default::keyRange);
|
||||||
break;
|
break;
|
||||||
|
|
@ -152,20 +152,20 @@ void sfz::Synth::handleGlobalOpcodes(const std::vector<Opcode>& members)
|
||||||
void sfz::Synth::handleControlOpcodes(const std::vector<Opcode>& members)
|
void sfz::Synth::handleControlOpcodes(const std::vector<Opcode>& members)
|
||||||
{
|
{
|
||||||
for (auto& member : members) {
|
for (auto& member : members) {
|
||||||
switch (hash(member.opcode)) {
|
switch (member.lettersOnlyHash) {
|
||||||
case hash("Set_cc"):
|
case hash("Set_cc"):
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case hash("set_cc"):
|
case hash("set_cc"):
|
||||||
if (member.parameter && Default::ccNumberRange.containsWithEnd(*member.parameter)) {
|
if (member.backParameter && Default::ccNumberRange.containsWithEnd(*member.backParameter)) {
|
||||||
const auto ccValue = readOpcode(member.value, Default::ccValueRange).value_or(0);
|
const auto ccValue = readOpcode(member.value, Default::ccValueRange).value_or(0);
|
||||||
midiState.ccEvent(*member.parameter, ccValue);
|
midiState.ccEvent(*member.backParameter, ccValue);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case hash("Label_cc"):
|
case hash("Label_cc"):
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case hash("label_cc"):
|
case hash("label_cc"):
|
||||||
if (member.parameter && Default::ccNumberRange.containsWithEnd(*member.parameter))
|
if (member.backParameter && Default::ccNumberRange.containsWithEnd(*member.backParameter))
|
||||||
ccNames.emplace_back(*member.parameter, std::string(member.value));
|
ccNames.emplace_back(*member.backParameter, std::string(member.value));
|
||||||
break;
|
break;
|
||||||
case hash("Default_path"):
|
case hash("Default_path"):
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
|
||||||
|
|
@ -14,34 +14,89 @@ TEST_CASE("[Opcode] Construction")
|
||||||
{
|
{
|
||||||
sfz::Opcode opcode { "sample", "dummy" };
|
sfz::Opcode opcode { "sample", "dummy" };
|
||||||
REQUIRE(opcode.opcode == "sample");
|
REQUIRE(opcode.opcode == "sample");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample"));
|
||||||
|
REQUIRE(opcode.parameters.empty());
|
||||||
REQUIRE(opcode.value == "dummy");
|
REQUIRE(opcode.value == "dummy");
|
||||||
REQUIRE(!opcode.parameter);
|
REQUIRE(!opcode.backParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Normal construction with underscore")
|
SECTION("Normal construction with underscore")
|
||||||
{
|
{
|
||||||
sfz::Opcode opcode { "sample_underscore", "dummy" };
|
sfz::Opcode opcode { "sample_underscore", "dummy" };
|
||||||
REQUIRE(opcode.opcode == "sample_underscore");
|
REQUIRE(opcode.opcode == "sample_underscore");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore"));
|
||||||
|
REQUIRE(opcode.parameters.empty());
|
||||||
REQUIRE(opcode.value == "dummy");
|
REQUIRE(opcode.value == "dummy");
|
||||||
REQUIRE(!opcode.parameter);
|
REQUIRE(!opcode.backParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Parameterized opcode")
|
SECTION("Parameterized opcode")
|
||||||
{
|
{
|
||||||
sfz::Opcode opcode { "sample123", "dummy" };
|
sfz::Opcode opcode { "sample123", "dummy" };
|
||||||
REQUIRE(opcode.opcode == "sample");
|
REQUIRE(opcode.opcode == "sample123");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample"));
|
||||||
REQUIRE(opcode.value == "dummy");
|
REQUIRE(opcode.value == "dummy");
|
||||||
REQUIRE(opcode.parameter);
|
REQUIRE(opcode.parameters.empty());
|
||||||
REQUIRE(*opcode.parameter == 123);
|
REQUIRE(opcode.backParameter);
|
||||||
|
REQUIRE(*opcode.backParameter == 123);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Parameterized opcode with underscore")
|
SECTION("Parameterized opcode with underscore")
|
||||||
{
|
{
|
||||||
sfz::Opcode opcode { "sample_underscore123", "dummy" };
|
sfz::Opcode opcode { "sample_underscore123", "dummy" };
|
||||||
REQUIRE(opcode.opcode == "sample_underscore");
|
REQUIRE(opcode.opcode == "sample_underscore123");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore"));
|
||||||
REQUIRE(opcode.value == "dummy");
|
REQUIRE(opcode.value == "dummy");
|
||||||
REQUIRE(opcode.parameter);
|
REQUIRE(opcode.parameters.empty());
|
||||||
REQUIRE(*opcode.parameter == 123);
|
REQUIRE(opcode.backParameter);
|
||||||
|
REQUIRE(*opcode.backParameter == 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parameterized opcode within the opcode")
|
||||||
|
{
|
||||||
|
sfz::Opcode opcode { "sample1_underscore", "dummy" };
|
||||||
|
REQUIRE(opcode.opcode == "sample1_underscore");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore"));
|
||||||
|
REQUIRE(opcode.value == "dummy");
|
||||||
|
REQUIRE(opcode.parameters.size() == 1);
|
||||||
|
REQUIRE(opcode.parameters[0] == 1);
|
||||||
|
REQUIRE(!opcode.backParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parameterized opcode within the opcode")
|
||||||
|
{
|
||||||
|
sfz::Opcode opcode { "sample123_underscore", "dummy" };
|
||||||
|
REQUIRE(opcode.opcode == "sample123_underscore");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore"));
|
||||||
|
REQUIRE(opcode.value == "dummy");
|
||||||
|
REQUIRE(opcode.parameters.size() == 1);
|
||||||
|
REQUIRE(opcode.parameters[0] == 123);
|
||||||
|
REQUIRE(!opcode.backParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parameterized opcode within the opcode twice")
|
||||||
|
{
|
||||||
|
sfz::Opcode opcode { "sample123_double44_underscore", "dummy" };
|
||||||
|
REQUIRE(opcode.opcode == "sample123_double44_underscore");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample_double_underscore"));
|
||||||
|
REQUIRE(opcode.value == "dummy");
|
||||||
|
REQUIRE(opcode.parameters.size() == 2);
|
||||||
|
REQUIRE(opcode.parameters[0] == 123);
|
||||||
|
REQUIRE(opcode.parameters[1] == 44);
|
||||||
|
REQUIRE(!opcode.backParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Parameterized opcode within the opcode twice, with a back parameter")
|
||||||
|
{
|
||||||
|
sfz::Opcode opcode { "sample123_double44_underscore23", "dummy" };
|
||||||
|
REQUIRE(opcode.opcode == "sample123_double44_underscore23");
|
||||||
|
REQUIRE(opcode.lettersOnlyHash == hash("sample_double_underscore"));
|
||||||
|
REQUIRE(opcode.value == "dummy");
|
||||||
|
REQUIRE(opcode.parameters.size() == 2);
|
||||||
|
REQUIRE(opcode.parameters[0] == 123);
|
||||||
|
REQUIRE(opcode.parameters[1] == 44);
|
||||||
|
REQUIRE(opcode.backParameter);
|
||||||
|
REQUIRE(*opcode.backParameter == 23);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue