summaryrefslogtreecommitdiffstats
path: root/chrome/tools
diff options
context:
space:
mode:
authorengedy@chromium.org <engedy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-25 15:13:49 +0000
committerengedy@chromium.org <engedy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-25 15:13:49 +0000
commit8682d2accd2025287abe1336a158fc2b604cd7ed (patch)
tree30efb2b0a014012c4d3a7d4b07f2853569060d3d /chrome/tools
parent5c023ebb6038cb573e25b3aebd6c2f4bd59b07b5 (diff)
downloadchromium_src-8682d2accd2025287abe1336a158fc2b604cd7ed.zip
chromium_src-8682d2accd2025287abe1336a158fc2b604cd7ed.tar.gz
chromium_src-8682d2accd2025287abe1336a158fc2b604cd7ed.tar.bz2
Improved syntax, and added new instructions to the JTL interpreter.
Added 5 new commands to the JTL interpreter. Also fixed a few nits, typos, tests, and clarified some comments in existing code, as well as changed the syntax so JTL programs became a lot more readable. BUG=298036 Review URL: https://codereview.chromium.org/35353002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231019 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/tools')
-rw-r--r--chrome/tools/profile_reset/jtl_compiler.cc52
-rw-r--r--chrome/tools/profile_reset/jtl_compiler.h6
-rw-r--r--chrome/tools/profile_reset/jtl_compiler_unittest.cc81
-rw-r--r--chrome/tools/profile_reset/jtl_parser.cc2
-rw-r--r--chrome/tools/profile_reset/jtl_parser_unittest.cc59
5 files changed, 127 insertions, 73 deletions
diff --git a/chrome/tools/profile_reset/jtl_compiler.cc b/chrome/tools/profile_reset/jtl_compiler.cc
index 21104e9..f98d3d5 100644
--- a/chrome/tools/profile_reset/jtl_compiler.cc
+++ b/chrome/tools/profile_reset/jtl_compiler.cc
@@ -23,7 +23,7 @@ class ByteCodeWriter {
void WriteUint8(uint8 value) { output_->push_back(static_cast<char>(value)); }
void WriteOpCode(uint8 op_code) { WriteUint8(op_code); }
void WriteHash(const std::string& hash) {
- CHECK_EQ(hash.size(), jtl::kHashSizeInBytes);
+ CHECK(jtl::Hasher::IsHash(hash));
*output_ += hash;
}
void WriteBool(bool value) { WriteUint8(value ? 1u : 0u); }
@@ -40,19 +40,40 @@ class InstructionSet {
public:
InstructionSet() {
// Define each instruction in this list.
- Add(Instruction("node", jtl::NAVIGATE, Arguments(Hash)));
+ // Note:
+ // - Instructions ending in "hash" will write their 'HashString' arguments
+ // directly into the byte-code.
+ // - Instructions ending in "hashed" will first hash their 'String'
+ // arguments, and will write this hash to the byte-code.
+ Add(Instruction("go", jtl::NAVIGATE, Arguments(String)));
Add(Instruction("any", jtl::NAVIGATE_ANY, Arguments()));
Add(Instruction("back", jtl::NAVIGATE_BACK, Arguments()));
- Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(Hash, Bool)));
+ Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(String, Bool)));
+ Add(Instruction("store_hash",
+ jtl::STORE_HASH, Arguments(String, HashString)));
+ Add(Instruction("store_hashed",
+ jtl::STORE_HASH, Arguments(String, String)));
+ Add(Instruction("store_node_bool",
+ jtl::STORE_NODE_BOOL, Arguments(String)));
+ Add(Instruction("store_node_hash",
+ jtl::STORE_NODE_HASH, Arguments(String)));
+ Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool)));
+ Add(Instruction("compare_hashed",
+ jtl::COMPARE_NODE_HASH, Arguments(String)));
+ Add(Instruction("compare_hashed_not",
+ jtl::COMPARE_NODE_HASH_NOT, Arguments(String)));
Add(Instruction("compare_stored_bool",
jtl::COMPARE_STORED_BOOL,
- Arguments(Hash, Bool, Bool)));
- Add(Instruction("store_hash", jtl::STORE_HASH, Arguments(Hash, Hash)));
- Add(Instruction("compare_stored_hash",
+ Arguments(String, Bool, Bool)));
+ Add(Instruction("compare_stored_hashed",
jtl::COMPARE_STORED_HASH,
- Arguments(Hash, Hash, Hash)));
- Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool)));
- Add(Instruction("compare_hash", jtl::COMPARE_NODE_HASH, Arguments(Hash)));
+ Arguments(String, String, String)));
+ Add(Instruction("compare_to_stored_bool",
+ jtl::COMPARE_NODE_TO_STORED_BOOL,
+ Arguments(String)));
+ Add(Instruction("compare_to_stored_hash",
+ jtl::COMPARE_NODE_TO_STORED_HASH,
+ Arguments(String)));
Add(Instruction("break", jtl::STOP_EXECUTING_SENTENCE, Arguments()));
}
@@ -77,13 +98,21 @@ class InstructionSet {
target->WriteBool(value);
break;
}
- case Hash: {
+ case String: {
std::string value;
if (!arguments.GetString(i, &value))
return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
target->WriteHash(hasher.GetHash(value));
break;
}
+ case HashString: {
+ std::string hash_value;
+ if (!arguments.GetString(i, &hash_value) ||
+ !jtl::Hasher::IsHash(hash_value))
+ return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
+ target->WriteHash(hash_value);
+ break;
+ }
default:
NOTREACHED();
return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
@@ -99,7 +128,8 @@ class InstructionSet {
enum ArgumentType {
None,
Bool,
- Hash
+ String,
+ HashString
};
// Encapsulates meta-data about one instruction.
diff --git a/chrome/tools/profile_reset/jtl_compiler.h b/chrome/tools/profile_reset/jtl_compiler.h
index fe3a68d..e5630360 100644
--- a/chrome/tools/profile_reset/jtl_compiler.h
+++ b/chrome/tools/profile_reset/jtl_compiler.h
@@ -16,7 +16,7 @@
//
// The text-based JTL syntax itself much resembles C/C++. A program consists of
// zero or more sentences. Each sentence is terminated by a semi-colon (;), and
-// is composed of *one* or more operations, separated by forward slashes (/).
+// is composed of *one* or more operations, separated by periods (.).
//
// Each operation resembles a C/C++ function call and consists of an instruction
// name, and an optional argument list, which takes Boolean values and/or string
@@ -28,10 +28,10 @@
// Example source code:
//
// // Store "x"=true if path "foo.bar" is found.
-// node("foo")/node("bar")/store_bool("x", true);
+// go("foo").go("bar").store_bool("x", true);
//
// // Store "y"="1" if the above value is set.
-// compare_stored_bool("x", true, false)/store_hash("y", "1");
+// compare_stored_bool("x", true, false).store_hash("y", "1");
//
class JtlCompiler {
public:
diff --git a/chrome/tools/profile_reset/jtl_compiler_unittest.cc b/chrome/tools/profile_reset/jtl_compiler_unittest.cc
index 2eb1d61..6b83774 100644
--- a/chrome/tools/profile_reset/jtl_compiler_unittest.cc
+++ b/chrome/tools/profile_reset/jtl_compiler_unittest.cc
@@ -33,25 +33,36 @@ TEST(JtlCompiler, CompileSingleInstructions) {
std::string source_code;
std::string expected_bytecode;
} cases[] = {
- {"node(\"foo\")/", OP_NAVIGATE(GetHash("foo"))},
- {"node(\"has whitespace\t\")/",
+ {"go(\"foo\").", OP_NAVIGATE(GetHash("foo"))},
+ {"go(\"has whitespace\t\").",
OP_NAVIGATE(GetHash("has whitespace\t"))},
- {"any/", OP_NAVIGATE_ANY},
- {"back/", OP_NAVIGATE_BACK},
- {"store_bool(\"name\", true)/",
+ {"any.", OP_NAVIGATE_ANY},
+ {"back.", OP_NAVIGATE_BACK},
+ {"store_bool(\"name\", true).",
OP_STORE_BOOL(GetHash("name"), VALUE_TRUE)},
- {"compare_stored_bool(\"name\", true, false)/",
+ {"compare_stored_bool(\"name\", true, false).",
OP_COMPARE_STORED_BOOL(GetHash("name"), VALUE_TRUE, VALUE_FALSE)},
- {"store_hash(\"name\", \"value\")/",
+ {"store_hash(\"name\", \"" + GetHash("value") + "\").",
OP_STORE_HASH(GetHash("name"), GetHash("value"))},
- {"compare_stored_hash(\"name\", \"value\", \"default\")/",
+ {"store_hashed(\"name\", \"value\").",
+ OP_STORE_HASH(GetHash("name"), GetHash("value"))},
+ {"store_node_bool(\"name\").",
+ OP_STORE_NODE_BOOL(GetHash("name"))},
+ {"store_node_hash(\"name\").",
+ OP_STORE_NODE_HASH(GetHash("name"))},
+ {"compare_stored_hashed(\"name\", \"value\", \"default\").",
OP_COMPARE_STORED_HASH(
GetHash("name"), GetHash("value"), GetHash("default"))},
- {"compare_bool(false)/", OP_COMPARE_NODE_BOOL(VALUE_FALSE)},
- {"compare_bool(true)/", OP_COMPARE_NODE_BOOL(VALUE_TRUE)},
- {"compare_hash(\"foo\")/", OP_COMPARE_NODE_HASH(GetHash("foo"))},
- {"compare_hash(\"bar\")/", OP_COMPARE_NODE_HASH(GetHash("bar"))},
- {"break/", OP_STOP_EXECUTING_SENTENCE},
+ {"compare_bool(false).", OP_COMPARE_NODE_BOOL(VALUE_FALSE)},
+ {"compare_bool(true).", OP_COMPARE_NODE_BOOL(VALUE_TRUE)},
+ {"compare_hashed(\"foo\").", OP_COMPARE_NODE_HASH(GetHash("foo"))},
+ {"compare_hashed_not(\"foo\").",
+ OP_COMPARE_NODE_HASH_NOT(GetHash("foo"))},
+ {"compare_to_stored_bool(\"name\").",
+ OP_COMPARE_NODE_TO_STORED_BOOL(GetHash("name"))},
+ {"compare_to_stored_hash(\"name\").",
+ OP_COMPARE_NODE_TO_STORED_HASH(GetHash("name"))},
+ {"break.", OP_STOP_EXECUTING_SENTENCE},
{"break;", OP_STOP_EXECUTING_SENTENCE + OP_END_OF_SENTENCE}};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
@@ -66,10 +77,10 @@ TEST(JtlCompiler, CompileSingleInstructions) {
TEST(JtlCompiler, CompileEntireProgram) {
const char kSourceCode[] =
"// Store \"x\"=true if path is found.\n"
- "node(\"foo\")/node(\"bar\")/store_bool(\"x\", true);\n"
+ "go(\"foo\").go(\"bar\").store_bool(\"x\", true);\n"
"// ...\n"
"// Store \"y\"=\"1\" if above value is set.\n"
- "compare_stored_bool(\"x\", true, false)/store_hash(\"y\", \"1\");\n";
+ "compare_stored_bool(\"x\", true, false).store_hashed(\"y\", \"1\");\n";
std::string expected_bytecode =
OP_NAVIGATE(GetHash("foo")) +
@@ -85,7 +96,7 @@ TEST(JtlCompiler, CompileEntireProgram) {
}
TEST(JtlCompiler, InvalidOperationName) {
- const char kSourceCode[] = "any()\n/\nnon_existent_instruction\n(\n)\n;\n";
+ const char kSourceCode[] = "any()\n.\nnon_existent_instruction\n(\n)\n;\n";
std::string bytecode;
JtlCompiler::CompileError error;
@@ -99,8 +110,8 @@ TEST(JtlCompiler, InvalidOperationName) {
TEST(JtlCompiler, InvalidArgumentsCount) {
const char* kSourceCodes[] = {
- "any()/\nstore_bool(\"name\", true, \"superfluous argument\");\n",
- "any()/\nstore_bool(\"name\");"}; // missing argument
+ "any().\nstore_bool(\"name\", true, \"superfluous argument\");\n",
+ "any().\nstore_bool(\"name\");"}; // missing argument
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSourceCodes); ++i) {
SCOPED_TRACE(kSourceCodes[i]);
@@ -116,19 +127,29 @@ TEST(JtlCompiler, InvalidArgumentsCount) {
}
TEST(JtlCompiler, InvalidArgumentType) {
- const char* kSourceCodes[] = {
- "any()\n/\ncompare_stored_bool(true, false, false);", // Arg#1 should be
- // a hash.
- "any()\n/\ncompare_stored_bool(\"name\", \"should be a bool\", false);",
- "any()\n/\ncompare_stored_bool(\"name\", false, \"should be a bool\");"};
+ struct TestCase {
+ std::string expected_context_prefix;
+ std::string source_code;
+ } cases[] = {
+ {"compare_bool", "any()\n.\ncompare_bool(\"foo\");"},
+ {"compare_bool",
+ "any()\n.\ncompare_bool(\"01234567890123456789012345678901\");"},
+ {"compare_hashed", "any()\n.\ncompare_hashed(false);"},
+ {"store_hash", "any()\n.\nstore_hash(\"name\", false);"},
+ {"store_hash", "any()\n.\nstore_hash(\"name\", \"foo\");"},
+ {"compare_stored_bool",
+ "any()\n.\ncompare_stored_bool(\"name\", \"need a bool\", false);"},
+ {"compare_stored_bool",
+ "any()\n.\ncompare_stored_bool(\"name\", false, \"need a bool\");"}};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSourceCodes); ++i) {
- SCOPED_TRACE(kSourceCodes[i]);
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ SCOPED_TRACE(cases[i].source_code);
std::string bytecode;
JtlCompiler::CompileError error;
EXPECT_FALSE(JtlCompiler::Compile(
- kSourceCodes[i], kTestHashSeed, &bytecode, &error));
- EXPECT_THAT(error.context, testing::StartsWith("compare_stored_bool"));
+ cases[i].source_code, kTestHashSeed, &bytecode, &error));
+ EXPECT_THAT(error.context,
+ testing::StartsWith(cases[i].expected_context_prefix));
EXPECT_EQ(2u, error.line_number);
EXPECT_EQ(JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE,
error.error_code);
@@ -136,7 +157,7 @@ TEST(JtlCompiler, InvalidArgumentType) {
}
TEST(JtlCompiler, MistmatchedDoubleQuotes) {
- const char kSourceCode[] = "any()/\nnode(\"ok\", \"stray quote)/break();";
+ const char kSourceCode[] = "any().\ngo(\"ok\", \"stray quote).break();";
std::string bytecode;
JtlCompiler::CompileError error;
@@ -148,13 +169,13 @@ TEST(JtlCompiler, MistmatchedDoubleQuotes) {
}
TEST(JtlCompiler, ParsingError) {
- const char kSourceCode[] = "any()/\nnode()missing_separator();";
+ const char kSourceCode[] = "any().\ngo()missing_separator();";
std::string bytecode;
JtlCompiler::CompileError error;
EXPECT_FALSE(
JtlCompiler::Compile(kSourceCode, kTestHashSeed, &bytecode, &error));
- EXPECT_THAT(error.context, testing::StartsWith("node"));
+ EXPECT_THAT(error.context, testing::StartsWith("go"));
EXPECT_EQ(1u, error.line_number);
EXPECT_EQ(JtlCompiler::CompileError::PARSING_ERROR, error.error_code);
}
diff --git a/chrome/tools/profile_reset/jtl_parser.cc b/chrome/tools/profile_reset/jtl_parser.cc
index 9a4e1d2..9c9bdbb 100644
--- a/chrome/tools/profile_reset/jtl_parser.cc
+++ b/chrome/tools/profile_reset/jtl_parser.cc
@@ -50,7 +50,7 @@ const char kMaybeArgumentListRE[] =
"(?:\\(" // Opening parenthesis.
"((?:\"[^\"]*\"|[^\")])*)" // Capture: anything inside, quote-aware.
"\\))?"; // Closing parenthesis + everything optional.
-const char kOperationSeparatorRE[] = "(;|/)";
+const char kOperationSeparatorRE[] = "(;|\\.)";
} // namespace
diff --git a/chrome/tools/profile_reset/jtl_parser_unittest.cc b/chrome/tools/profile_reset/jtl_parser_unittest.cc
index 58ee3d6..1868df8 100644
--- a/chrome/tools/profile_reset/jtl_parser_unittest.cc
+++ b/chrome/tools/profile_reset/jtl_parser_unittest.cc
@@ -215,12 +215,12 @@ TEST(JtlParser, ParsingOneWellFormedOperation) {
const bool expected_ends_sentence;
} cases[] = {
{"foo1;", "foo1", "[]", true},
- {"foo2()/", "foo2", "[]", false},
+ {"foo2().", "foo2", "[]", false},
{"foo3(true);", "foo3", "[true]", true},
- {"foo4(false)/", "foo4", "[false]", false},
- {"foo5(\"bar\")/", "foo5", "[\"bar\"]", false},
- {"foo6(\" b a r \")/", "foo6", "[\" b a r \"]", false},
- {"foo7(true, \"bar\")/", "foo7", "[true,\"bar\"]", false},
+ {"foo4(false).", "foo4", "[false]", false},
+ {"foo5(\"bar\").", "foo5", "[\"bar\"]", false},
+ {"foo6(\" b a r \").", "foo6", "[\" b a r \"]", false},
+ {"foo7(true, \"bar\").", "foo7", "[true,\"bar\"]", false},
{"foo8(\"bar\", false, true);", "foo8", "[\"bar\",false,true]", true},
{"foo9(\"bar\", \" b a r \");", "foo9", "[\"bar\",\" b a r \"]", true}
};
@@ -239,7 +239,7 @@ TEST(JtlParser, ParsingOneWellFormedOperation) {
TEST(JtlParser, ParsingMultipleWellFormedOperations) {
const char kSourceCode[] =
- "foo1(true)/foo2/foo3(\"bar\");"
+ "foo1(true).foo2.foo3(\"bar\");"
"foo4(\"bar\", false);";
scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode));
@@ -257,13 +257,14 @@ TEST(JtlParser, ParsingTrickyStringLiterals) {
const char* expected_args;
const bool expected_ends_sentence;
} cases[] = {
- {"prev()/foo1(\"\");next(true);", "foo1", "[\"\"]", true},
- {"prev()/foo2(\" \");next(true);", "foo2", "[\" \"]", true},
- {"prev()/foo3(\",\",true);next(true);", "foo3", "[\",\",true]", true},
- {"prev()/foo4(\")\",true);next(true);", "foo4", "[\")\",true]", true},
- {"prev()/foo5(\";\",true);next(true);", "foo5", "[\";\",true]", true},
- {"prev()/foo6(\"/\",true)/next(true);", "foo6", "[\"/\",true]", false},
- {"prev()/foo7(\"//\",true)/next(true);", "foo7", "[\"//\",true]", false},
+ {"prev().foo1(\"\");next(true);", "foo1", "[\"\"]", true},
+ {"prev().foo2(\" \");next(true);", "foo2", "[\" \"]", true},
+ {"prev().foo3(\",\",true);next(true);", "foo3", "[\",\",true]", true},
+ {"prev().foo4(\")\",true);next(true);", "foo4", "[\")\",true]", true},
+ {"prev().foo5(\";\",true);next(true);", "foo5", "[\";\",true]", true},
+ {"prev().foo6(\"/\",true).next(true);", "foo6", "[\"/\",true]", false},
+ {"prev().foo7(\"//\",true).next(true);", "foo7", "[\"//\",true]", false},
+ {"prev().foo8(\".\",true).next(true);", "foo8", "[\".\",true]", false},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
@@ -294,14 +295,14 @@ TEST(JtlParser, FirstOperationIsIllFormed) {
{"bad_args6([\"bar\"]);", "bad_args6"},
{"bad_args7(False);", "bad_args7"},
{"bad_args8(True);", "bad_args8"},
- {"bad_quotes1(missing both, true)/good();", "bad_quotes1"},
- {"bad_quotes2(true, \"missing one)/good(); //\"", "bad_quotes2"},
- {"bad_quotes3(\"too\" \"much\", true)/good();", "bad_quotes3"},
+ {"bad_quotes1(missing both, true).good();", "bad_quotes1"},
+ {"bad_quotes2(true, \"missing one).good(); //\"", "bad_quotes2"},
+ {"bad_quotes3(\"too\" \"much\", true).good();", "bad_quotes3"},
{"bad_missing_separator1", "bad_missing_separator1"},
{"bad_missing_separator2()good();", "bad_missing_separator2"},
- {"bad_parenthesis1(true/good();", "bad_parenthesis1"},
- {"bad_parenthesis2(true/good());", "bad_parenthesis2"},
- {"bad_parenthesis3)/good();", "bad_parenthesis3"}
+ {"bad_parenthesis1(true.good();", "bad_parenthesis1"},
+ {"bad_parenthesis2(true.good());", "bad_parenthesis2"},
+ {"bad_parenthesis3).good();", "bad_parenthesis3"}
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
@@ -317,18 +318,20 @@ TEST(JtlParser, SecondOperationIsIllFormed) {
const char* source_code;
const char* bad_operation_name;
} cases[] = {
- {"\ngood(true,false)\n/bad_args(,);", "bad_args"},
- {"\ngood(true,false)\n/bad_quotes1(missing both, true)/good();",
+ {"\ngood(true,false)\n.bad_args(,);", "bad_args"},
+ {"\ngood(true,false)\n.bad_quotes1(missing both, true).good();",
"bad_quotes1"},
- {"\ngood(true,false)\n/bad_quotes2(\"missing one, true)/good(); //\"",
+ {"\ngood(true,false)\n.bad_quotes2(\"missing one, true).good(); //\"",
"bad_quotes2"},
- {"\ngood(true,false)\n/bad_quotes3(\"too\" \"many\", true)/good();",
+ {"\ngood(true,false)\n.bad_quotes3(\"too\" \"many\", true).good();",
"bad_quotes3"},
- {"\ngood(true,false)\n/missing_separator1", "missing_separator1"},
- {"\ngood(true,false)\n/missing_separator2()good()", "missing_separator2"},
- {"\ngood(true,false)\n/bad_parens1(true/good();", "bad_parens1"},
- {"\ngood(true,false)\n/bad_parens2(true/good());", "bad_parens2"},
- {"\ngood(true,false)\n/bad_parens3)/good();", "bad_parens3"}
+ {"\ngood(true,false)\n.bad_separator1()/good();", "bad_separator1"},
+ {"\ngood(true,false)\n.missing_separator1", "missing_separator1"},
+ {"\ngood(true,false)\n.missing_separator2()good();",
+ "missing_separator2"},
+ {"\ngood(true,false)\n.bad_parens1(true.good();", "bad_parens1"},
+ {"\ngood(true,false)\n.bad_parens2(true.good());", "bad_parens2"},
+ {"\ngood(true,false)\n.bad_parens3).good();", "bad_parens3"}
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {