diff options
author | dan sinclair <dj2@everburning.com> | 2019-03-25 11:25:17 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-25 11:25:17 -0400 |
commit | d7926a5f1eca75f848be1a4c7757ed4fd70a5da0 (patch) | |
tree | 5abe86a562fa77fa10639c63f2777281256b62f6 | |
parent | 11d47964eedc0a69a686237e3caa3b7d1408b263 (diff) | |
download | amber-d7926a5f1eca75f848be1a4c7757ed4fd70a5da0.tar.gz |
Add EXPECT EQ (#411)
This CL adds the EXPECT EQ command into amber script.
-rw-r--r-- | docs/amber_script.md | 8 | ||||
-rw-r--r-- | src/amber.cc | 6 | ||||
-rw-r--r-- | src/amberscript/parser.cc | 101 | ||||
-rw-r--r-- | src/amberscript/parser.h | 9 | ||||
-rw-r--r-- | src/amberscript/parser_test.cc | 62 | ||||
-rw-r--r-- | src/executor.cc | 18 | ||||
-rw-r--r-- | tests/cases/expect_eq.amber | 17 |
7 files changed, 201 insertions, 20 deletions
diff --git a/docs/amber_script.md b/docs/amber_script.md index 5c29110..de63afd 100644 --- a/docs/amber_script.md +++ b/docs/amber_script.md @@ -313,14 +313,14 @@ CLEAR <pipeline> * EQ\_RGBA ``` -# Checks that |buffer_name| at |x|, |y| has the given |value|s when compared +# Checks that |buffer_name| at |x| has the given |value|s when compared # with the given |comparator|. -EXPECT <buffer_name> IDX <x> <y> <comparator> <value>+ +EXPECT <buffer_name> IDX <x> <comparator> <value>+ -# Checks that |buffer_name| at |x|, |y| has values within |tolerance| of |value| +# Checks that |buffer_name| at |x| has values within |tolerance| of |value| # when compared with the given |comparator|. The |tolerance| can be specified # as 1-4 float values separated by spaces. -EXPECT <buffer_name> IDX <x> <y> TOLERANCE \ +EXPECT <buffer_name> IDX <x> TOLERANCE \ <tolerance>{1,4} <comparator> <value>+ # Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the diff --git a/src/amber.cc b/src/amber.cc index 1227c81..2b9e496 100644 --- a/src/amber.cc +++ b/src/amber.cc @@ -175,6 +175,12 @@ amber::Result Amber::ExecuteWithShaderData(const amber::Recipe* recipe, // Hold the executor result until the extractions are complete. This will let // us dump any buffers requested even on failure. + if (script->GetPipelines().empty()) { + if (!executor_result.IsSuccess()) + return executor_result; + return {}; + } + // TODO(dsinclair): Figure out how extractions work with multiple pipelines. auto* pipeline = script->GetPipelines()[0].get(); diff --git a/src/amberscript/parser.cc b/src/amberscript/parser.cc index f0573fe..0d45040 100644 --- a/src/amberscript/parser.cc +++ b/src/amberscript/parser.cc @@ -27,6 +27,30 @@ namespace amber { namespace amberscript { +namespace { + +bool IsComparator(const std::string& in) { + return in == "EQ" || in == "NE" || in == "GT" || in == "LT" || in == "GE" || + in == "LE"; +} + +ProbeSSBOCommand::Comparator ToComparator(const std::string& in) { + if (in == "EQ") + return ProbeSSBOCommand::Comparator::kEqual; + if (in == "NE") + return ProbeSSBOCommand::Comparator::kNotEqual; + if (in == "GT") + return ProbeSSBOCommand::Comparator::kGreater; + if (in == "LT") + return ProbeSSBOCommand::Comparator::kLess; + if (in == "GE") + return ProbeSSBOCommand::Comparator::kGreaterOrEqual; + + assert(in == "LE"); + return ProbeSSBOCommand::Comparator::kLessOrEqual; +} + +} // namespace Parser::Parser() : amber::Parser() {} @@ -995,6 +1019,41 @@ Result Parser::ParseClear() { return ValidateEndOfStatement("CLEAR command"); } +Result Parser::ParseValues(const std::string& name, + const DatumType& type, + std::vector<Value>* values) { + assert(values); + + auto token = tokenizer_->NextToken(); + while (!token->IsEOL() && !token->IsEOS()) { + Value v; + + if ((type.IsFloat() || type.IsDouble())) { + if (!token->IsInteger() && !token->IsDouble()) { + return Result(std::string("Invalid value provided to ") + name + + " command: " + token->ToOriginalString()); + } + + Result r = token->ConvertToDouble(); + if (!r.IsSuccess()) + return r; + + v.SetDoubleValue(token->AsDouble()); + } else { + if (!token->IsInteger()) { + return Result(std::string("Invalid value provided to ") + name + + " command: " + token->ToOriginalString()); + } + + v.SetIntValue(token->AsUint64()); + } + + values->push_back(v); + token = tokenizer_->NextToken(); + } + return {}; +} + Result Parser::ParseExpect() { auto token = tokenizer_->NextToken(); if (!token->IsString()) @@ -1014,16 +1073,24 @@ Result Parser::ParseExpect() { token->ConvertToDouble(); float x = token->AsFloat(); + bool has_y_val = false; + float y = 0; token = tokenizer_->NextToken(); - if (!token->IsInteger() || token->AsInt32() < 0) - return Result("invalid Y value in EXPECT command"); - token->ConvertToDouble(); - float y = token->AsFloat(); + if (token->IsInteger()) { + has_y_val = true; - // TODO(dsinclair): Handle comparator && TOLERANCE + if (token->AsInt32() < 0) + return Result("invalid Y value in EXPECT command"); + token->ConvertToDouble(); + y = token->AsFloat(); + + token = tokenizer_->NextToken(); + } - token = tokenizer_->NextToken(); if (token->IsString() && token->AsString() == "SIZE") { + if (!has_y_val) + return Result("invalid Y value in EXPECT command"); + auto probe = MakeUnique<ProbeCommand>(buffer); probe->SetX(x); probe->SetY(y); @@ -1081,6 +1148,28 @@ Result Parser::ParseExpect() { } script_->AddCommand(std::move(probe)); + } else if (token->IsString() && IsComparator(token->AsString())) { + if (has_y_val) + return Result("Y value not needed for non-color comparator"); + if (!buffer->IsDataBuffer()) + return Result("comparator must be provided a data buffer"); + + auto probe = MakeUnique<ProbeSSBOCommand>(buffer); + probe->SetComparator(ToComparator(token->AsString())); + probe->SetDatumType(buffer->AsDataBuffer()->GetDatumType()); + probe->SetOffset(static_cast<uint32_t>(x)); + + std::vector<Value> values; + Result r = + ParseValues("EXPECT", buffer->AsDataBuffer()->GetDatumType(), &values); + if (!r.IsSuccess()) + return r; + + if (values.empty()) + return Result("missing comparison values for EXPECT command"); + probe->SetValues(std::move(values)); + script_->AddCommand(std::move(probe)); + return {}; } else { return Result("unexpected token in EXPECT command: " + token->ToOriginalString()); diff --git a/src/amberscript/parser.h b/src/amberscript/parser.h index 49aefd2..14f38bc 100644 --- a/src/amberscript/parser.h +++ b/src/amberscript/parser.h @@ -18,6 +18,7 @@ #include <memory> #include <string> #include <utility> +#include <vector> #include "amber/result.h" #include "src/parser.h" @@ -64,6 +65,14 @@ class Parser : public amber::Parser { Result ParseClear(); Result ParseExpect(); + // Parses a set of values out of the token stream. |name| is the name of the + // current command we're parsing for error purposes. The |type| is the type + // of data we expect for the current buffer. |values| will be appended to with + // the parsed values. + Result ParseValues(const std::string& name, + const DatumType& type, + std::vector<Value>* values); + std::unique_ptr<Tokenizer> tokenizer_; }; diff --git a/src/amberscript/parser_test.cc b/src/amberscript/parser_test.cc index 441071c..5c7fc7f 100644 --- a/src/amberscript/parser_test.cc +++ b/src/amberscript/parser_test.cc @@ -3733,7 +3733,7 @@ EXPECT my_fb IDX 0 INVALID SIZE 250 250 EQ_RGB 0 128 255)"; Parser parser; Result r = parser.Parse(in); ASSERT_FALSE(r.IsSuccess()); - EXPECT_EQ("15: invalid Y value in EXPECT command", r.Error()); + EXPECT_EQ("15: unexpected token in EXPECT command: INVALID", r.Error()); } TEST_F(AmberScriptParserTest, ExpectRGBMissingSize) { @@ -4104,5 +4104,65 @@ EXPECT my_fb IDX 0 0 SIZE 250 250 EQ_RGBA 0 128 255 99 EXTRA)"; EXPECT_EQ("15: extra parameters after EXPECT command", r.Error()); } +TEST_F(AmberScriptParserTest, ExpectEQ) { + std::string in = R"( +BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11 +EXPECT orig_buf IDX 5 EQ 11)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); + + auto script = parser.GetScript(); + const auto& commands = script->GetCommands(); + ASSERT_EQ(1U, commands.size()); + + auto* cmd = commands[0].get(); + ASSERT_TRUE(cmd->IsProbeSSBO()); + + auto* probe = cmd->AsProbeSSBO(); + EXPECT_EQ(ProbeSSBOCommand::Comparator::kEqual, probe->GetComparator()); + EXPECT_EQ(5U, probe->GetOffset()); + EXPECT_TRUE(probe->GetDatumType().IsInt32()); + ASSERT_EQ(1U, probe->GetValues().size()); + EXPECT_EQ(11U, probe->GetValues()[0].AsInt32()); +} + +TEST_F(AmberScriptParserTest, ExpectEqMissingValue) { + std::string in = R"( +BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11 +EXPECT orig_buf IDX 5 EQ)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: missing comparison values for EXPECT command", r.Error()); +} + +TEST_F(AmberScriptParserTest, ExpectEQExtraParams) { + std::string in = R"( +BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11 +EXPECT orig_buf IDX 5 EQ 11 EXTRA)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_FALSE(r.IsSuccess()); + EXPECT_EQ("3: Invalid value provided to EXPECT command: EXTRA", r.Error()); +} + +TEST_F(AmberScriptParserTest, MultipleExpect) { + std::string in = R"( +BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11 +BUFFER dest_buf DATA_TYPE int32 SIZE 100 FILL 22 + +EXPECT orig_buf IDX 0 EQ 11 +EXPECT dest_buf IDX 0 EQ 22 +)"; + + Parser parser; + Result r = parser.Parse(in); + ASSERT_TRUE(r.IsSuccess()) << r.Error(); +} + } // namespace amberscript } // namespace amber diff --git a/src/executor.cc b/src/executor.cc index eda60f0..8bcc315 100644 --- a/src/executor.cc +++ b/src/executor.cc @@ -53,17 +53,16 @@ Result Executor::Execute(Engine* engine, ExecutionType executionType) { engine->SetEngineData(script->GetEngineData()); - if (script->GetPipelines().empty()) - return Result("no pipelines defined"); - - Result r = CompileShaders(script, shader_map); - if (!r.IsSuccess()) - return r; - - for (auto& pipeline : script->GetPipelines()) { - r = engine->CreatePipeline(pipeline.get()); + if (!script->GetPipelines().empty()) { + Result r = CompileShaders(script, shader_map); if (!r.IsSuccess()) return r; + + for (auto& pipeline : script->GetPipelines()) { + r = engine->CreatePipeline(pipeline.get()); + if (!r.IsSuccess()) + return r; + } } if (executionType == ExecutionType::kPipelineCreateOnly) @@ -71,6 +70,7 @@ Result Executor::Execute(Engine* engine, // Process Commands for (const auto& cmd : script->GetCommands()) { + Result r; if (cmd->IsProbe()) { assert(cmd->AsProbe()->GetBuffer()->IsFormatBuffer()); diff --git a/tests/cases/expect_eq.amber b/tests/cases/expect_eq.amber new file mode 100644 index 0000000..f9affc6 --- /dev/null +++ b/tests/cases/expect_eq.amber @@ -0,0 +1,17 @@ +#!amber +# Copyright 2019 The Amber Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +BUFFER orig_buf DATA_TYPE int32 SIZE 100 FILL 11 +EXPECT orig_buf IDX 0 EQ 11 |