1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// A simple command-line compiler for JTL (JSON Traversal Language).
6//
7// Translates rules from a text-based, human-readable format to an easy-to-parse
8// byte-code format, which then can be interpreted by JtlInterpreter.
9//
10// Example usage:
11//   jtl_compiler --input=blah.txt --hash-seed="foobar" --output=blah.dat
12
13#include <iostream>
14#include <string>
15
16#include "base/command_line.h"
17#include "base/file_util.h"
18#include "base/files/file_path.h"
19#include "chrome/tools/profile_reset/jtl_compiler.h"
20
21namespace {
22
23// Command-line argument name: path to the input text-based JTL source code.
24const char kInputPath[] = "input";
25
26// Command-line argument name: path to the output byte-code.
27const char kOutputPath[] = "output";
28
29// Command-line argument name: the hash seed to use.
30const char kHashSeed[] = "hash-seed";
31
32// Error codes.
33const char kMismatchedDoubleQuotes[] = "Mismatched double-quotes before EOL.";
34const char kParsingError[] = "Parsing error. Input is ill-formed.";
35const char kArgumentCountError[] = "Wrong number of arguments for operation.";
36const char kArgumentTypeError[] = "Wrong argument type(s) for operation.";
37const char kArgumentValueError[] = "Wrong argument value(s) for operation.";
38const char kUnknownOperationError[] = "No operation by this name.";
39const char kUnknownError[] = "Unknown error.";
40
41const char* ResolveErrorCode(JtlCompiler::CompileError::ErrorCode code) {
42  switch (code) {
43    case JtlCompiler::CompileError::MISMATCHED_DOUBLE_QUOTES:
44      return kMismatchedDoubleQuotes;
45    case JtlCompiler::CompileError::PARSING_ERROR:
46      return kParsingError;
47    case JtlCompiler::CompileError::INVALID_ARGUMENT_COUNT:
48      return kArgumentCountError;
49    case JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE:
50      return kArgumentTypeError;
51    case JtlCompiler::CompileError::INVALID_ARGUMENT_VALUE:
52      return kArgumentValueError;
53    case JtlCompiler::CompileError::INVALID_OPERATION_NAME:
54      return kUnknownOperationError;
55    default:
56      return kUnknownError;
57  }
58}
59
60}  // namespace
61
62int main(int argc, char* argv[]) {
63  CommandLine::Init(argc, argv);
64  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
65  if (!cmd_line->HasSwitch(kInputPath) || !cmd_line->HasSwitch(kHashSeed) ||
66      !cmd_line->HasSwitch(kOutputPath)) {
67    std::cerr << "Usage: " << argv[0] << " <required switches>" << std::endl;
68    std::cerr << "\nRequired switches are:" << std::endl;
69    std::cerr << "  --" << kInputPath << "=<file>"
70              << "\t\tPath to the input text-based JTL source code."
71              << std::endl;
72    std::cerr << "  --" << kOutputPath << "=<file>"
73              << "\t\tPath to the output byte-code." << std::endl;
74    std::cerr << "  --" << kHashSeed << "=<value>"
75              << "\t\tThe hash seed to use." << std::endl;
76    return -1;
77  }
78
79  base::FilePath source_code_path =
80      MakeAbsoluteFilePath(cmd_line->GetSwitchValuePath(kInputPath));
81  std::string source_code;
82  if (!base::ReadFileToString(source_code_path, &source_code)) {
83    std::cerr << "ERROR: Cannot read input file." << std::endl;
84    return -3;
85  }
86
87  std::string bytecode;
88  JtlCompiler::CompileError error;
89  std::string hash_seed = cmd_line->GetSwitchValueASCII(kHashSeed);
90  if (!JtlCompiler::Compile(source_code, hash_seed, &bytecode, &error)) {
91    std::cerr << "COMPILE ERROR: " << ResolveErrorCode(error.error_code)
92              << std::endl;
93    std::cerr << "  Line number: " << (error.line_number + 1) << std::endl;
94    std::cerr << "  Context: " << (error.context.size() > 63
95                                       ? error.context.substr(0, 60) + "..."
96                                       : error.context) << std::endl;
97    return -2;
98  }
99
100  base::FilePath bytecode_path =
101      MakeAbsoluteFilePath(cmd_line->GetSwitchValuePath(kOutputPath));
102  int bytes_written =
103      file_util::WriteFile(cmd_line->GetSwitchValuePath(kOutputPath),
104                           bytecode.data(),
105                           static_cast<int>(bytecode.size()));
106  if (bytes_written != static_cast<int>(bytecode.size())) {
107    std::cerr << "ERROR: Cannot write output file." << std::endl;
108    return -3;
109  }
110
111  return 0;
112}
113