capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

capnp.c++ (72002B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #ifndef _GNU_SOURCE
     23 #define _GNU_SOURCE
     24 #endif
     25 
     26 #if _WIN32
     27 #include <kj/win32-api-version.h>
     28 #endif
     29 
     30 #include "lexer.h"
     31 #include "parser.h"
     32 #include "compiler.h"
     33 #include "module-loader.h"
     34 #include "node-translator.h"
     35 #include <capnp/pretty-print.h>
     36 #include <capnp/schema.capnp.h>
     37 #include <kj/vector.h>
     38 #include <kj/io.h>
     39 #include <kj/miniposix.h>
     40 #include <kj/debug.h>
     41 #include "../message.h"
     42 #include <iostream>
     43 #include <kj/main.h>
     44 #include <kj/parse/char.h>
     45 #include <sys/stat.h>
     46 #include <sys/types.h>
     47 #include <capnp/serialize.h>
     48 #include <capnp/serialize-packed.h>
     49 #include <capnp/serialize-text.h>
     50 #include <capnp/compat/json.h>
     51 #include <errno.h>
     52 #include <stdlib.h>
     53 #include <kj/map.h>
     54 
     55 #if _WIN32
     56 #include <process.h>
     57 #include <windows.h>
     58 #include <kj/windows-sanity.h>
     59 #undef CONST
     60 #else
     61 #include <sys/wait.h>
     62 #endif
     63 
     64 #if HAVE_CONFIG_H
     65 #include "config.h"
     66 #endif
     67 
     68 #ifndef VERSION
     69 #define VERSION "(unknown)"
     70 #endif
     71 
     72 namespace capnp {
     73 namespace compiler {
     74 
     75 static const char VERSION_STRING[] = "Cap'n Proto version " VERSION;
     76 
     77 class CompilerMain final: public GlobalErrorReporter {
     78 public:
     79   explicit CompilerMain(kj::ProcessContext& context)
     80       : context(context), disk(kj::newDiskFilesystem()), loader(*this) {}
     81 
     82   kj::MainFunc getMain() {
     83     if (context.getProgramName().endsWith("capnpc") || context.getProgramName().endsWith("capnpc.exe")) {
     84       kj::MainBuilder builder(context, VERSION_STRING,
     85             "Compiles Cap'n Proto schema files and generates corresponding source code in one or "
     86             "more languages.");
     87       addGlobalOptions(builder);
     88       addCompileOptions(builder);
     89       builder.addOption({'i', "generate-id"}, KJ_BIND_METHOD(*this, generateId),
     90                         "Generate a new 64-bit unique ID for use in a Cap'n Proto schema.");
     91       return builder.build();
     92     } else {
     93       kj::MainBuilder builder(context, VERSION_STRING,
     94             "Command-line tool for Cap'n Proto development and debugging.");
     95       builder.addSubCommand("compile", KJ_BIND_METHOD(*this, getCompileMain),
     96                             "Generate source code from schema files.")
     97              .addSubCommand("id", KJ_BIND_METHOD(*this, getGenIdMain),
     98                             "Generate a new unique ID.")
     99              .addSubCommand("convert", KJ_BIND_METHOD(*this, getConvertMain),
    100                             "Convert messages between binary, text, JSON, etc.")
    101              .addSubCommand("decode", KJ_BIND_METHOD(*this, getDecodeMain),
    102                             "DEPRECATED (use `convert`)")
    103              .addSubCommand("encode", KJ_BIND_METHOD(*this, getEncodeMain),
    104                             "DEPRECATED (use `convert`)")
    105              .addSubCommand("eval", KJ_BIND_METHOD(*this, getEvalMain),
    106                             "Evaluate a const from a schema file.");
    107       addGlobalOptions(builder);
    108       return builder.build();
    109     }
    110   }
    111 
    112   kj::MainFunc getCompileMain() {
    113     kj::MainBuilder builder(context, VERSION_STRING,
    114           "Compiles Cap'n Proto schema files and generates corresponding source code in one or "
    115           "more languages.");
    116     addGlobalOptions(builder);
    117     addCompileOptions(builder);
    118     return builder.build();
    119   }
    120 
    121   kj::MainFunc getGenIdMain() {
    122     return kj::MainBuilder(context, VERSION_STRING,
    123           "Generates a new 64-bit unique ID for use in a Cap'n Proto schema.")
    124         .callAfterParsing(KJ_BIND_METHOD(*this, generateId))
    125         .build();
    126   }
    127 
    128   kj::MainFunc getConvertMain() {
    129     // Only parse the schemas we actually need for decoding.
    130     compileEagerness = Compiler::NODE;
    131 
    132     // Drop annotations since we don't need them.  This avoids importing files like c++.capnp.
    133     annotationFlag = Compiler::DROP_ANNOTATIONS;
    134 
    135     kj::MainBuilder builder(context, VERSION_STRING,
    136           "Converts messages between formats. Reads a stream of messages from stdin in format "
    137           "<from> and writes them to stdout in format <to>. Valid formats are:\n"
    138           "    binary      standard binary format\n"
    139           "    packed      packed binary format (deflates zeroes)\n"
    140           "    flat        binary single segment, no segment table (rare)\n"
    141           "    flat-packed flat and packed\n"
    142           "    canonical   canonicalized binary single segment, no segment table\n"
    143           "    text        schema language struct literal format\n"
    144           "    json        JSON format\n"
    145           "When using \"text\" or \"json\" format, you must specify <schema-file> and <type> "
    146           "(but they are ignored and can be omitted for binary-to-binary conversions). "
    147           "<type> names names a struct type defined in <schema-file>, which is the root type "
    148           "of the message(s).");
    149     addGlobalOptions(builder);
    150     builder.addOption({"short"}, KJ_BIND_METHOD(*this, printShort),
    151                "Write text or JSON output in short (non-pretty) format. Each message will "
    152                "be printed on one line, without using whitespace to improve readability.")
    153            .addOptionWithArg({"segment-size"}, KJ_BIND_METHOD(*this, setSegmentSize), "<n>",
    154                "For binary output, sets the preferred segment size on the MallocMessageBuilder to <n> "
    155                "words and turns off heuristic growth.  This flag is mainly useful "
    156                "for testing.  Without it, each message will be written as a single "
    157                "segment.")
    158            .addOption({"quiet"}, KJ_BIND_METHOD(*this, setQuiet),
    159                "Do not print warning messages about the input being in the wrong format.  "
    160                "Use this if you find the warnings are wrong (but also let us know so "
    161                "we can improve them).")
    162            .expectArg("<from>:<to>", KJ_BIND_METHOD(*this, setConversion))
    163            .expectOptionalArg("<schema-file>", KJ_BIND_METHOD(*this, addSource))
    164            .expectOptionalArg("<type>", KJ_BIND_METHOD(*this, setRootType))
    165            .callAfterParsing(KJ_BIND_METHOD(*this, convert));
    166     return builder.build();
    167   }
    168 
    169   kj::MainFunc getDecodeMain() {
    170     // Only parse the schemas we actually need for decoding.
    171     compileEagerness = Compiler::NODE;
    172 
    173     // Drop annotations since we don't need them.  This avoids importing files like c++.capnp.
    174     annotationFlag = Compiler::DROP_ANNOTATIONS;
    175 
    176     kj::MainBuilder builder(context, VERSION_STRING,
    177           "Decodes one or more encoded Cap'n Proto messages as text.  The messages have root "
    178           "type <type> defined in <schema-file>.  Messages are read from standard input and "
    179           "by default are expected to be in standard Cap'n Proto serialization format.");
    180     addGlobalOptions(builder);
    181     builder.addOption({"flat"}, KJ_BIND_METHOD(*this, codeFlat),
    182                       "Interpret the input as one large single-segment message rather than a "
    183                       "stream in standard serialization format.  (Rarely used.)")
    184            .addOption({'p', "packed"}, KJ_BIND_METHOD(*this, codePacked),
    185                       "Expect the input to be packed using standard Cap'n Proto packing, which "
    186                       "deflates zero-valued bytes.  (This reads messages written with "
    187                       "capnp::writePackedMessage*() from <capnp/serialize-packed.h>.  Do not use "
    188                       "this for messages written with capnp::writeMessage*() from "
    189                       "<capnp/serialize.h>.)")
    190            .addOption({"short"}, KJ_BIND_METHOD(*this, printShort),
    191                       "Print in short (non-pretty) format.  Each message will be printed on one "
    192                       "line, without using whitespace to improve readability.")
    193            .addOption({"quiet"}, KJ_BIND_METHOD(*this, setQuiet),
    194                       "Do not print warning messages about the input being in the wrong format.  "
    195                       "Use this if you find the warnings are wrong (but also let us know so "
    196                       "we can improve them).")
    197            .expectArg("<schema-file>", KJ_BIND_METHOD(*this, addSource))
    198            .expectArg("<type>", KJ_BIND_METHOD(*this, setRootType))
    199            .callAfterParsing(KJ_BIND_METHOD(*this, decode));
    200     return builder.build();
    201   }
    202 
    203   kj::MainFunc getEncodeMain() {
    204     // Only parse the schemas we actually need for decoding.
    205     compileEagerness = Compiler::NODE;
    206 
    207     // Drop annotations since we don't need them.  This avoids importing files like c++.capnp.
    208     annotationFlag = Compiler::DROP_ANNOTATIONS;
    209 
    210     kj::MainBuilder builder(context, VERSION_STRING,
    211           "Encodes one or more textual Cap'n Proto messages to binary.  The messages have root "
    212           "type <type> defined in <schema-file>.  Messages are read from standard input.  Each "
    213           "message is a parenthesized struct literal, like the format used to specify constants "
    214           "and default values of struct type in the schema language.  For example:\n"
    215           "    (foo = 123, bar = \"hello\", baz = [true, false, true])\n"
    216           "The input may contain any number of such values; each will be encoded as a separate "
    217           "message.",
    218 
    219           "Note that the current implementation reads the entire input into memory before "
    220           "beginning to encode.  A better implementation would read and encode one message at "
    221           "a time.");
    222     addGlobalOptions(builder);
    223     builder.addOption({"flat"}, KJ_BIND_METHOD(*this, codeFlat),
    224                       "Expect only one input value, serializing it as a single-segment message "
    225                       "with no framing.")
    226            .addOption({'p', "packed"}, KJ_BIND_METHOD(*this, codePacked),
    227                       "Pack the output message with standard Cap'n Proto packing, which "
    228                       "deflates zero-valued bytes.  (This writes messages using "
    229                       "capnp::writePackedMessage() from <capnp/serialize-packed.h>.  Without "
    230                       "this, capnp::writeMessage() from <capnp/serialize.h> is used.)")
    231            .addOptionWithArg({"segment-size"}, KJ_BIND_METHOD(*this, setSegmentSize), "<n>",
    232                              "Sets the preferred segment size on the MallocMessageBuilder to <n> "
    233                              "words and turns off heuristic growth.  This flag is mainly useful "
    234                              "for testing.  Without it, each message will be written as a single "
    235                              "segment.")
    236            .expectArg("<schema-file>", KJ_BIND_METHOD(*this, addSource))
    237            .expectArg("<type>", KJ_BIND_METHOD(*this, setRootType))
    238            .callAfterParsing(KJ_BIND_METHOD(*this, encode));
    239     return builder.build();
    240   }
    241 
    242   kj::MainFunc getEvalMain() {
    243     // Only parse the schemas we actually need for decoding.
    244     compileEagerness = Compiler::NODE;
    245 
    246     // Drop annotations since we don't need them.  This avoids importing files like c++.capnp.
    247     annotationFlag = Compiler::DROP_ANNOTATIONS;
    248 
    249     // Default convert to text unless -o is given.
    250     convertTo = Format::TEXT;
    251 
    252     kj::MainBuilder builder(context, VERSION_STRING,
    253           "Prints (or encodes) the value of <name>, which must be defined in <schema-file>.  "
    254           "<name> must refer to a const declaration, a field of a struct type (prints the default "
    255           "value), or a field or list element nested within some other value.  Examples:\n"
    256           "    capnp eval myschema.capnp MyType.someField\n"
    257           "    capnp eval myschema.capnp someConstant\n"
    258           "    capnp eval myschema.capnp someConstant.someField\n"
    259           "    capnp eval myschema.capnp someConstant.someList[4]\n"
    260           "    capnp eval myschema.capnp someConstant.someList[4].anotherField[1][2][3]\n"
    261           "Since consts can have complex struct types, and since you can define a const using "
    262           "import and variable substitution, this can be a convenient way to write text-format "
    263           "config files which are compiled to binary before deployment.",
    264 
    265           "By default the value is written in text format and can have any type.  The -b, -p, "
    266           "and --flat flags specify binary output, in which case the const must be of struct "
    267           "type.");
    268     addGlobalOptions(builder);
    269     builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setEvalOutputFormat),
    270                       "<format>", "Encode the output in the given format. See `capnp help convert` "
    271                       "for a list of formats. Defaults to \"text\".")
    272            .addOption({'b', "binary"}, KJ_BIND_METHOD(*this, codeBinary),
    273                       "same as -obinary")
    274            .addOption({"flat"}, KJ_BIND_METHOD(*this, codeFlat),
    275                       "same as -oflat")
    276            .addOption({'p', "packed"}, KJ_BIND_METHOD(*this, codePacked),
    277                       "same as -opacked")
    278            .addOption({"short"}, KJ_BIND_METHOD(*this, printShort),
    279                       "If output format is text or JSON, write in short (non-pretty) format. The "
    280                       "message will be printed on one line, without using whitespace to improve "
    281                       "readability.")
    282            .expectArg("<schema-file>", KJ_BIND_METHOD(*this, addSource))
    283            .expectArg("<name>", KJ_BIND_METHOD(*this, evalConst));
    284     return builder.build();
    285   }
    286 
    287   void addGlobalOptions(kj::MainBuilder& builder) {
    288     builder.addOptionWithArg({'I', "import-path"}, KJ_BIND_METHOD(*this, addImportPath), "<dir>",
    289                              "Add <dir> to the list of directories searched for non-relative "
    290                              "imports (ones that start with a '/').")
    291            .addOption({"no-standard-import"}, KJ_BIND_METHOD(*this, noStandardImport),
    292                       "Do not add any default import paths; use only those specified by -I.  "
    293                       "Otherwise, typically /usr/include and /usr/local/include are added by "
    294                       "default.");
    295   }
    296 
    297   void addCompileOptions(kj::MainBuilder& builder) {
    298     builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, addOutput), "<lang>[:<dir>]",
    299                              "Generate source code for language <lang> in directory <dir> "
    300                              "(default: current directory).  <lang> actually specifies a plugin "
    301                              "to use.  If <lang> is a simple word, the compiler searches for a plugin "
    302                              "called 'capnpc-<lang>' in $PATH.  If <lang> is a file path "
    303                              "containing slashes, it is interpreted as the exact plugin "
    304                              "executable file name, and $PATH is not searched.  If <lang> is '-', "
    305                              "the compiler dumps the request to standard output.")
    306            .addOptionWithArg({"src-prefix"}, KJ_BIND_METHOD(*this, addSourcePrefix), "<prefix>",
    307                              "If a file specified for compilation starts with <prefix>, remove "
    308                              "the prefix for the purpose of deciding the names of output files.  "
    309                              "For example, the following command:\n"
    310                              "    capnp compile --src-prefix=foo/bar -oc++:corge foo/bar/baz/qux.capnp\n"
    311                              "would generate the files corge/baz/qux.capnp.{h,c++}.")
    312            .expectOneOrMoreArgs("<source>", KJ_BIND_METHOD(*this, addSource))
    313            .callAfterParsing(KJ_BIND_METHOD(*this, generateOutput));
    314   }
    315 
    316   // =====================================================================================
    317   // shared options
    318 
    319   kj::MainBuilder::Validity addImportPath(kj::StringPtr path) {
    320     KJ_IF_MAYBE(dir, getSourceDirectory(path, false)) {
    321       loader.addImportPath(*dir);
    322       return true;
    323     } else {
    324       return "no such directory";
    325     }
    326   }
    327 
    328   kj::MainBuilder::Validity noStandardImport() {
    329     addStandardImportPaths = false;
    330     return true;
    331   }
    332 
    333   kj::MainBuilder::Validity addSource(kj::StringPtr file) {
    334     if (!compilerConstructed) {
    335       compiler = compilerSpace.construct(annotationFlag);
    336       compilerConstructed = true;
    337     }
    338 
    339     if (addStandardImportPaths) {
    340       static constexpr kj::StringPtr STANDARD_IMPORT_PATHS[] = {
    341         "/usr/local/include"_kj,
    342         "/usr/include"_kj,
    343 #ifdef CAPNP_INCLUDE_DIR
    344         KJ_CONCAT(CAPNP_INCLUDE_DIR, _kj),
    345 #endif
    346       };
    347       for (auto path: STANDARD_IMPORT_PATHS) {
    348         KJ_IF_MAYBE(dir, getSourceDirectory(path, false)) {
    349           loader.addImportPath(*dir);
    350         } else {
    351           // ignore standard path that doesn't exist
    352         }
    353       }
    354 
    355       addStandardImportPaths = false;
    356     }
    357 
    358     auto dirPathPair = interpretSourceFile(file);
    359     KJ_IF_MAYBE(module, loader.loadModule(dirPathPair.dir, dirPathPair.path)) {
    360       auto compiled = compiler->add(*module);
    361       compiler->eagerlyCompile(compiled.getId(), compileEagerness);
    362       sourceFiles.add(SourceFile { compiled.getId(), compiled, module->getSourceName(), &*module });
    363     } else {
    364       return "no such file";
    365     }
    366 
    367     return true;
    368   }
    369 
    370 public:
    371   // =====================================================================================
    372   // "id" command
    373 
    374   kj::MainBuilder::Validity generateId() {
    375     context.exitInfo(kj::str("@0x", kj::hex(generateRandomId())));
    376     KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT;
    377   }
    378 
    379   // =====================================================================================
    380   // "compile" command
    381 
    382   kj::MainBuilder::Validity addOutput(kj::StringPtr spec) {
    383     KJ_IF_MAYBE(split, spec.findFirst(':')) {
    384       kj::StringPtr dir = spec.slice(*split + 1);
    385       auto plugin = spec.slice(0, *split);
    386 
    387       if (*split == 1 && (dir.startsWith("/") || dir.startsWith("\\"))) {
    388         // The colon is the second character and is immediately followed by a slash or backslash.
    389         // So, the user passed something like `-o c:/foo`. Is this a request to run the C plugin
    390         // and output to `/foo`? Or are we on Windows, and is this a request to run the plugin
    391         // `c:/foo`?
    392         KJ_IF_MAYBE(split2, dir.findFirst(':')) {
    393           // There are two colons. The first ':' was the second char, and was followed by '/' or
    394           // '\', e.g.:
    395           //     capnp compile -o c:/foo.exe:bar
    396           //
    397           // In this case we can conclude that the second colon is actually meant to be the
    398           // plugin/location separator, and the first colon was simply signifying a drive letter.
    399           //
    400           // Proof by contradiction:
    401           // - Say that none of the colons were meant to be plugin/location separators; i.e. the
    402           //   whole argument is meant to be a plugin indicator and the location defaults to ".".
    403           //   -> In this case, the plugin path has two colons, which is not valid.
    404           //   -> CONTRADICTION
    405           // - Say that the first colon was meant to be the plugin/location separator.
    406           //   -> In this case, the second colon must be the drive letter separator for the
    407           //      output location.
    408           //   -> However, the output location begins with '/' or '\', which is not a drive letter.
    409           //   -> CONTRADICTION
    410           // - Say that there are more colons beyond the first two, and one of these is meant to
    411           //   be the plugin/location separator.
    412           //   -> In this case, the plugin path has two or more colons, which is not valid.
    413           //   -> CONTRADICTION
    414           //
    415           // We therefore conclude that the *second* colon is in fact the plugin/location separator.
    416 
    417           dir = dir.slice(*split2 + 1);
    418           plugin = spec.slice(0, *split2 + 2);
    419 #if _WIN32
    420         } else {
    421           // The user wrote something like:
    422           //
    423           //     capnp compile -o c:/foo/bar
    424           //
    425           // What does this mean? It depends on what system we're on. On a Unix system, the above
    426           // clearly is a request to run the `capnpc-c` plugin (perhaps to output C code) and write
    427           // to the directory /foo/bar. But on Windows, absolute paths do not start with '/', and
    428           // the above is actually a request to run the plugin `c:/foo/bar`, outputting to the
    429           // current directory.
    430 
    431           outputs.add(OutputDirective { spec.asArray(), nullptr });
    432           return true;
    433 #endif
    434         }
    435       }
    436 
    437       struct stat stats;
    438       if (stat(dir.cStr(), &stats) < 0 || !S_ISDIR(stats.st_mode)) {
    439         return "output location is inaccessible or is not a directory";
    440       }
    441       outputs.add(OutputDirective { plugin, disk->getCurrentPath().evalNative(dir) });
    442     } else {
    443       outputs.add(OutputDirective { spec.asArray(), nullptr });
    444     }
    445 
    446     return true;
    447   }
    448 
    449   kj::MainBuilder::Validity addSourcePrefix(kj::StringPtr prefix) {
    450     if (getSourceDirectory(prefix, true) == nullptr) {
    451       return "no such directory";
    452     } else {
    453       return true;
    454     }
    455   }
    456 
    457   kj::MainBuilder::Validity generateOutput() {
    458     if (hadErrors()) {
    459       // Skip output if we had any errors.
    460       return true;
    461     }
    462 
    463     // We require one or more sources and if they failed to compile we quit above, so this should
    464     // pass.  (This assertion also guarantees that `compiler` has been initialized.)
    465     KJ_ASSERT(sourceFiles.size() > 0, "Shouldn't have gotten here without sources.");
    466 
    467     if (outputs.size() == 0) {
    468       return "no outputs specified";
    469     }
    470 
    471     MallocMessageBuilder message;
    472     auto request = message.initRoot<schema::CodeGeneratorRequest>();
    473 
    474     auto version = request.getCapnpVersion();
    475     version.setMajor(CAPNP_VERSION_MAJOR);
    476     version.setMinor(CAPNP_VERSION_MINOR);
    477     version.setMicro(CAPNP_VERSION_MICRO);
    478 
    479     auto schemas = compiler->getLoader().getAllLoaded();
    480     auto nodes = request.initNodes(schemas.size());
    481     for (size_t i = 0; i < schemas.size(); i++) {
    482       nodes.setWithCaveats(i, schemas[i].getProto());
    483     }
    484 
    485     request.adoptSourceInfo(compiler->getAllSourceInfo(message.getOrphanage()));
    486 
    487     auto requestedFiles = request.initRequestedFiles(sourceFiles.size());
    488     for (size_t i = 0; i < sourceFiles.size(); i++) {
    489       auto requestedFile = requestedFiles[i];
    490       requestedFile.setId(sourceFiles[i].id);
    491       requestedFile.setFilename(sourceFiles[i].name);
    492       requestedFile.adoptImports(compiler->getFileImportTable(
    493           *sourceFiles[i].module, Orphanage::getForMessageContaining(requestedFile)));
    494     }
    495 
    496     for (auto& output: outputs) {
    497       if (kj::str(output.name) == "-") {
    498         writeMessageToFd(STDOUT_FILENO, message);
    499         continue;
    500       }
    501 
    502       int pipeFds[2];
    503       KJ_SYSCALL(kj::miniposix::pipe(pipeFds));
    504 
    505       kj::String exeName;
    506       bool shouldSearchPath = true;
    507       for (char c: output.name) {
    508 #if _WIN32
    509         if (c == '/' || c == '\\') {
    510 #else
    511         if (c == '/') {
    512 #endif
    513           shouldSearchPath = false;
    514           break;
    515         }
    516       }
    517       if (shouldSearchPath) {
    518         exeName = kj::str("capnpc-", output.name);
    519       } else {
    520         exeName = kj::heapString(output.name);
    521       }
    522 
    523       kj::Array<char> pwd = kj::heapArray<char>(256);
    524       while (getcwd(pwd.begin(), pwd.size()) == nullptr) {
    525         KJ_REQUIRE(pwd.size() < 8192, "WTF your working directory path is more than 8k?");
    526         pwd = kj::heapArray<char>(pwd.size() * 2);
    527       }
    528 
    529 #if _WIN32
    530       int oldStdin;
    531       KJ_SYSCALL(oldStdin = dup(STDIN_FILENO));
    532       intptr_t child;
    533 
    534 #else  // _WIN32
    535       pid_t child;
    536       KJ_SYSCALL(child = fork());
    537       if (child == 0) {
    538         // I am the child!
    539 
    540         KJ_SYSCALL(close(pipeFds[1]));
    541 #endif  // _WIN32, else
    542 
    543         KJ_SYSCALL(dup2(pipeFds[0], STDIN_FILENO));
    544         KJ_SYSCALL(close(pipeFds[0]));
    545 
    546         KJ_IF_MAYBE(d, output.dir) {
    547 #if _WIN32
    548           KJ_SYSCALL(SetCurrentDirectoryW(d->forWin32Api(true).begin()), d->toWin32String(true));
    549 #else
    550           auto wd = d->toString(true);
    551           KJ_SYSCALL(chdir(wd.cStr()), wd);
    552           KJ_SYSCALL(setenv("PWD", wd.cStr(), true));
    553 #endif
    554         }
    555 
    556 #if _WIN32
    557         // MSVCRT's spawn*() don't correctly escape arguments, which is necessary on Windows
    558         // since the underlying system call takes a single command line string rather than
    559         // an arg list. We do the escaping ourselves by wrapping the name in quotes. We know
    560         // that exeName itself can't contain quotes (since filenames aren't allowed to contain
    561         // quotes on Windows), so we don't have to account for those.
    562         KJ_ASSERT(exeName.findFirst('\"') == nullptr,
    563             "Windows filenames can't contain quotes", exeName);
    564         auto escapedExeName = kj::str("\"", exeName, "\"");
    565 #endif
    566 
    567         if (shouldSearchPath) {
    568 #if _WIN32
    569           child = _spawnlp(_P_NOWAIT, exeName.cStr(), escapedExeName.cStr(), nullptr);
    570 #else
    571           execlp(exeName.cStr(), exeName.cStr(), nullptr);
    572 #endif
    573         } else {
    574 #if _WIN32
    575           if (!exeName.startsWith("/") && !exeName.startsWith("\\") &&
    576               !(exeName.size() >= 2 && exeName[1] == ':')) {
    577 #else
    578           if (!exeName.startsWith("/")) {
    579 #endif
    580             // The name is relative.  Prefix it with our original working directory path.
    581             exeName = kj::str(pwd.begin(), "/", exeName);
    582           }
    583 
    584 #if _WIN32
    585           child = _spawnl(_P_NOWAIT, exeName.cStr(), escapedExeName.cStr(), nullptr);
    586 #else
    587           execl(exeName.cStr(), exeName.cStr(), nullptr);
    588 #endif
    589         }
    590 
    591 #if _WIN32
    592         if (child == -1) {
    593 #endif
    594           int error = errno;
    595           if (error == ENOENT) {
    596             context.exitError(kj::str(output.name, ": no such plugin (executable should be '",
    597                                       exeName, "')"));
    598           } else {
    599 #if _WIN32
    600             KJ_FAIL_SYSCALL("spawn()", error);
    601 #else
    602             KJ_FAIL_SYSCALL("exec()", error);
    603 #endif
    604           }
    605 #if _WIN32
    606         }
    607 
    608         // Restore stdin.
    609         KJ_SYSCALL(dup2(oldStdin, STDIN_FILENO));
    610         KJ_SYSCALL(close(oldStdin));
    611 
    612         // Restore current directory.
    613         KJ_SYSCALL(chdir(pwd.begin()), pwd.begin());
    614 #else  // _WIN32
    615       }
    616 
    617       KJ_SYSCALL(close(pipeFds[0]));
    618 #endif  // _WIN32, else
    619 
    620       writeMessageToFd(pipeFds[1], message);
    621       KJ_SYSCALL(close(pipeFds[1]));
    622 
    623 #if _WIN32
    624       int status;
    625       if (_cwait(&status, child, 0) == -1) {
    626         KJ_FAIL_SYSCALL("_cwait()", errno);
    627       }
    628 
    629       if (status != 0) {
    630         context.error(kj::str(output.name, ": plugin failed: exit code ", status));
    631       }
    632 
    633 #else  // _WIN32
    634       int status;
    635       KJ_SYSCALL(waitpid(child, &status, 0));
    636       if (WIFSIGNALED(status)) {
    637         context.error(kj::str(output.name, ": plugin failed: ", strsignal(WTERMSIG(status))));
    638       } else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
    639         context.error(kj::str(output.name, ": plugin failed: exit code ", WEXITSTATUS(status)));
    640       }
    641 #endif  // _WIN32, else
    642     }
    643 
    644     return true;
    645   }
    646 
    647   // =====================================================================================
    648   // "convert" command
    649 
    650 private:
    651   enum class Format {
    652     BINARY,
    653     PACKED,
    654     FLAT,
    655     FLAT_PACKED,
    656     CANONICAL,
    657     TEXT,
    658     JSON
    659   };
    660 
    661   kj::Maybe<Format> parseFormatName(kj::StringPtr name) {
    662     if (name == "binary"     ) return Format::BINARY;
    663     if (name == "packed"     ) return Format::PACKED;
    664     if (name == "flat"       ) return Format::FLAT;
    665     if (name == "flat-packed") return Format::FLAT_PACKED;
    666     if (name == "canonical"  ) return Format::CANONICAL;
    667     if (name == "text"       ) return Format::TEXT;
    668     if (name == "json"       ) return Format::JSON;
    669 
    670     return nullptr;
    671   }
    672 
    673   kj::StringPtr toString(Format format) {
    674     switch (format) {
    675       case Format::BINARY     : return "binary";
    676       case Format::PACKED     : return "packed";
    677       case Format::FLAT       : return "flat";
    678       case Format::FLAT_PACKED: return "flat-packed";
    679       case Format::CANONICAL  : return "canonical";
    680       case Format::TEXT       : return "text";
    681       case Format::JSON       : return "json";
    682     }
    683     KJ_UNREACHABLE;
    684   }
    685 
    686   Format formatFromDeprecatedFlags(Format defaultFormat) {
    687     // For deprecated commands "decode" and "encode".
    688     if (flat) {
    689       if (packed) {
    690         return Format::FLAT_PACKED;
    691       } else {
    692         return Format::FLAT;
    693       }
    694     } if (packed) {
    695       return Format::PACKED;
    696     } else if (binary) {
    697       return Format::BINARY;
    698     } else {
    699       return defaultFormat;
    700     }
    701   }
    702 
    703   kj::MainBuilder::Validity verifyRequirements(Format format) {
    704     if ((format == Format::TEXT || format == Format::JSON) && rootType == StructSchema()) {
    705       return kj::str("format requires schema: ", toString(format));
    706     } else {
    707       return true;
    708     }
    709   }
    710 
    711 public:
    712   kj::MainBuilder::Validity setConversion(kj::StringPtr conversion) {
    713     KJ_IF_MAYBE(colon, conversion.findFirst(':')) {
    714       auto from = kj::str(conversion.slice(0, *colon));
    715       auto to = conversion.slice(*colon + 1);
    716 
    717       KJ_IF_MAYBE(f, parseFormatName(from)) {
    718         convertFrom = *f;
    719       } else {
    720         return kj::str("unknown format: ", from);
    721       }
    722 
    723       KJ_IF_MAYBE(t, parseFormatName(to)) {
    724         convertTo = *t;
    725       } else {
    726         return kj::str("unknown format: ", to);
    727       }
    728 
    729       if (convertFrom == Format::JSON || convertTo == Format::JSON) {
    730         // We need annotations to process JSON.
    731         // TODO(someday): Find a way that we can process annotations from json.capnp without
    732         //   requiring other annotation-only imports like c++.capnp
    733         annotationFlag = Compiler::COMPILE_ANNOTATIONS;
    734       }
    735 
    736       return true;
    737     } else {
    738       return "invalid conversion, format is: <from>:<to>";
    739     }
    740   }
    741 
    742   kj::MainBuilder::Validity convert() {
    743     {
    744       auto result = verifyRequirements(convertFrom);
    745       if (result.getError() != nullptr) return result;
    746     }
    747     {
    748       auto result = verifyRequirements(convertTo);
    749       if (result.getError() != nullptr) return result;
    750     }
    751 
    752     kj::FdInputStream rawInput(STDIN_FILENO);
    753     kj::BufferedInputStreamWrapper input(rawInput);
    754 
    755     kj::FdOutputStream output(STDOUT_FILENO);
    756 
    757     if (!quiet) {
    758       auto result = checkPlausibility(convertFrom, input.getReadBuffer());
    759       if (result.getError() != nullptr) {
    760         return kj::mv(result);
    761       }
    762     }
    763 
    764     while (input.tryGetReadBuffer().size() > 0) {
    765       readOneAndConvert(input, output);
    766     }
    767 
    768     context.exit();
    769     KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT;
    770   }
    771 
    772 private:
    773   kj::Vector<byte> readAll(kj::BufferedInputStreamWrapper& input) {
    774     kj::Vector<byte> allBytes;
    775     for (;;) {
    776       auto buffer = input.tryGetReadBuffer();
    777       if (buffer.size() == 0) break;
    778       allBytes.addAll(buffer);
    779       input.skip(buffer.size());
    780     }
    781     return allBytes;
    782   }
    783 
    784   kj::String readOneText(kj::BufferedInputStreamWrapper& input) {
    785     // Consume and return one parentheses-delimited message from the input.
    786     //
    787     // Accounts for nested parentheses, comments, and string literals.
    788 
    789     enum {
    790       NORMAL,
    791       COMMENT,
    792       QUOTE,
    793       QUOTE_ESCAPE,
    794       DQUOTE,
    795       DQUOTE_ESCAPE
    796     } state = NORMAL;
    797     uint depth = 0;
    798     bool sawClose = false;
    799 
    800     kj::Vector<char> chars;
    801 
    802     for (;;) {
    803       auto buffer = input.tryGetReadBuffer();
    804 
    805       if (buffer == nullptr) {
    806         // EOF
    807         chars.add('\0');
    808         return kj::String(chars.releaseAsArray());
    809       }
    810 
    811       for (auto i: kj::indices(buffer)) {
    812         char c = buffer[i];
    813         switch (state) {
    814           case NORMAL:
    815             switch (c) {
    816               case '#': state = COMMENT; break;
    817               case '(':
    818                 if (depth == 0 && sawClose) {
    819                   // We already got one complete message. This is the start of the next message.
    820                   // Stop here.
    821                   chars.addAll(buffer.slice(0, i));
    822                   chars.add('\0');
    823                   input.skip(i);
    824                   return kj::String(chars.releaseAsArray());
    825                 }
    826                 ++depth;
    827                 break;
    828               case ')':
    829                 if (depth > 0) {
    830                   if (--depth == 0) {
    831                     sawClose = true;
    832                   }
    833                 }
    834                 break;
    835               default: break;
    836             }
    837             break;
    838           case COMMENT:
    839             switch (c) {
    840               case '\n': state = NORMAL; break;
    841               default: break;
    842             }
    843             break;
    844           case QUOTE:
    845             switch (c) {
    846               case '\'': state = NORMAL; break;
    847               case '\\': state = QUOTE_ESCAPE; break;
    848               default: break;
    849             }
    850             break;
    851           case QUOTE_ESCAPE:
    852             break;
    853           case DQUOTE:
    854             switch (c) {
    855               case '\"': state = NORMAL; break;
    856               case '\\': state = DQUOTE_ESCAPE; break;
    857               default: break;
    858             }
    859             break;
    860           case DQUOTE_ESCAPE:
    861             break;
    862         }
    863       }
    864 
    865       chars.addAll(buffer);
    866       input.skip(buffer.size());
    867     }
    868   }
    869 
    870   kj::String readOneJson(kj::BufferedInputStreamWrapper& input) {
    871     // Consume and return one brace-delimited message from the input.
    872     //
    873     // Accounts for nested braces, string literals, and comments starting with # or //. Technically
    874     // JSON does not permit comments but this code is lenient in case we change things later.
    875 
    876     enum {
    877       NORMAL,
    878       SLASH,
    879       COMMENT,
    880       QUOTE,
    881       QUOTE_ESCAPE,
    882       DQUOTE,
    883       DQUOTE_ESCAPE
    884     } state = NORMAL;
    885     uint depth = 0;
    886     bool sawClose = false;
    887 
    888     kj::Vector<char> chars;
    889 
    890     for (;;) {
    891       auto buffer = input.tryGetReadBuffer();
    892 
    893       if (buffer == nullptr) {
    894         // EOF
    895         chars.add('\0');
    896         return kj::String(chars.releaseAsArray());
    897       }
    898 
    899       for (auto i: kj::indices(buffer)) {
    900         char c = buffer[i];
    901         switch (state) {
    902           case SLASH:
    903             if (c == '/') {
    904               state = COMMENT;
    905               break;
    906             }
    907             KJ_FALLTHROUGH;
    908           case NORMAL:
    909             switch (c) {
    910               case '#': state = COMMENT; break;
    911               case '/': state = SLASH; break;
    912               case '{':
    913                 if (depth == 0 && sawClose) {
    914                   // We already got one complete message. This is the start of the next message.
    915                   // Stop here.
    916                   chars.addAll(buffer.slice(0, i));
    917                   chars.add('\0');
    918                   input.skip(i);
    919                   return kj::String(chars.releaseAsArray());
    920                 }
    921                 ++depth;
    922                 break;
    923               case '}':
    924                 if (depth > 0) {
    925                   if (--depth == 0) {
    926                     sawClose = true;
    927                   }
    928                 }
    929                 break;
    930               default: break;
    931             }
    932             break;
    933           case COMMENT:
    934             switch (c) {
    935               case '\n': state = NORMAL; break;
    936               default: break;
    937             }
    938             break;
    939           case QUOTE:
    940             switch (c) {
    941               case '\'': state = NORMAL; break;
    942               case '\\': state = QUOTE_ESCAPE; break;
    943               default: break;
    944             }
    945             break;
    946           case QUOTE_ESCAPE:
    947             break;
    948           case DQUOTE:
    949             switch (c) {
    950               case '\"': state = NORMAL; break;
    951               case '\\': state = DQUOTE_ESCAPE; break;
    952               default: break;
    953             }
    954             break;
    955           case DQUOTE_ESCAPE:
    956             break;
    957         }
    958       }
    959 
    960       chars.addAll(buffer);
    961       input.skip(buffer.size());
    962     }
    963   }
    964 
    965   class ParseErrorCatcher: public kj::ExceptionCallback {
    966   public:
    967     ParseErrorCatcher(kj::ProcessContext& context): context(context) {}
    968     ~ParseErrorCatcher() noexcept(false) {
    969       if (!unwindDetector.isUnwinding()) {
    970         KJ_IF_MAYBE(e, exception) {
    971           context.error(kj::str(
    972               "*** ERROR CONVERTING PREVIOUS MESSAGE ***\n"
    973               "The following error occurred while converting the message above.\n"
    974               "This probably means the input data is invalid/corrupted.\n",
    975               "Exception description: ", e->getDescription(), "\n"
    976               "Code location: ", e->getFile(), ":", e->getLine(), "\n"
    977               "*** END ERROR ***"));
    978         }
    979       }
    980     }
    981 
    982     void onRecoverableException(kj::Exception&& e) {
    983       // Only capture the first exception, on the assumption that later exceptions are probably
    984       // just cascading problems.
    985       if (exception == nullptr) {
    986         exception = kj::mv(e);
    987       }
    988     }
    989 
    990   private:
    991     kj::ProcessContext& context;
    992     kj::Maybe<kj::Exception> exception;
    993     kj::UnwindDetector unwindDetector;
    994   };
    995 
    996   void readOneAndConvert(kj::BufferedInputStreamWrapper& input, kj::OutputStream& output) {
    997     // Since this is a debug tool, lift the usual security limits.  Worse case is the process
    998     // crashes or has to be killed.
    999     ReaderOptions options;
   1000     options.nestingLimit = kj::maxValue;
   1001     options.traversalLimitInWords = kj::maxValue;
   1002 
   1003     ParseErrorCatcher parseErrorCatcher(context);
   1004 
   1005     switch (convertFrom) {
   1006       case Format::BINARY: {
   1007         capnp::InputStreamMessageReader message(input, options);
   1008         return writeConversion(message.getRoot<AnyStruct>(), output);
   1009       }
   1010       case Format::PACKED: {
   1011         capnp::PackedMessageReader message(input, options);
   1012         return writeConversion(message.getRoot<AnyStruct>(), output);
   1013       }
   1014       case Format::FLAT:
   1015       case Format::CANONICAL: {
   1016         auto allBytes = readAll(input);
   1017 
   1018         // Technically we don't know if the bytes are aligned so we'd better copy them to a new
   1019         // array. Note that if we have a non-whole number of words we chop off the straggler
   1020         // bytes. This is fine because if those bytes are actually part of the message we will
   1021         // hit an error later and if they are not then who cares?
   1022         auto words = kj::heapArray<word>(allBytes.size() / sizeof(word));
   1023         memcpy(words.begin(), allBytes.begin(), words.size() * sizeof(word));
   1024 
   1025         kj::ArrayPtr<const word> segments[1] = { words };
   1026         SegmentArrayMessageReader message(segments, options);
   1027         if (convertFrom == Format::CANONICAL) {
   1028           KJ_REQUIRE(message.isCanonical());
   1029         }
   1030         return writeConversion(message.getRoot<AnyStruct>(), output);
   1031       }
   1032       case Format::FLAT_PACKED: {
   1033         auto allBytes = readAll(input);
   1034 
   1035         auto words = kj::heapArray<word>(computeUnpackedSizeInWords(allBytes));
   1036         kj::ArrayInputStream input(allBytes);
   1037         capnp::_::PackedInputStream unpacker(input);
   1038         unpacker.read(words.asBytes().begin(), words.asBytes().size());
   1039         word dummy;
   1040         KJ_ASSERT(unpacker.tryRead(&dummy, sizeof(dummy), sizeof(dummy)) == 0);
   1041 
   1042         kj::ArrayPtr<const word> segments[1] = { words };
   1043         SegmentArrayMessageReader message(segments, options);
   1044         return writeConversion(message.getRoot<AnyStruct>(), output);
   1045       }
   1046       case Format::TEXT: {
   1047         auto text = readOneText(input);
   1048         MallocMessageBuilder message;
   1049         TextCodec codec;
   1050         codec.setPrettyPrint(pretty);
   1051         auto root = message.initRoot<DynamicStruct>(rootType);
   1052         codec.decode(text, root);
   1053         return writeConversion(root.asReader(), output);
   1054       }
   1055       case Format::JSON: {
   1056         auto text = readOneJson(input);
   1057         MallocMessageBuilder message;
   1058         JsonCodec codec;
   1059         codec.setPrettyPrint(pretty);
   1060         codec.handleByAnnotation(rootType);
   1061         auto root = message.initRoot<DynamicStruct>(rootType);
   1062         codec.decode(text, root);
   1063         return writeConversion(root.asReader(), output);
   1064       }
   1065     }
   1066 
   1067     KJ_UNREACHABLE;
   1068   }
   1069 
   1070   void writeConversion(AnyStruct::Reader reader, kj::OutputStream& output) {
   1071     switch (convertTo) {
   1072       case Format::BINARY: {
   1073         MallocMessageBuilder message(
   1074             segmentSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : segmentSize,
   1075             segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE);
   1076         message.setRoot(reader);
   1077         capnp::writeMessage(output, message);
   1078         return;
   1079       }
   1080       case Format::PACKED: {
   1081         MallocMessageBuilder message(
   1082             segmentSize == 0 ? SUGGESTED_FIRST_SEGMENT_WORDS : segmentSize,
   1083             segmentSize == 0 ? SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy::FIXED_SIZE);
   1084         message.setRoot(reader);
   1085         capnp::writePackedMessage(output, message);
   1086         return;
   1087       }
   1088       case Format::FLAT: {
   1089         auto words = kj::heapArray<word>(reader.totalSize().wordCount + 1);
   1090         memset(words.begin(), 0, words.asBytes().size());
   1091         copyToUnchecked(reader, words);
   1092         output.write(words.begin(), words.asBytes().size());
   1093         return;
   1094       }
   1095       case Format::FLAT_PACKED: {
   1096         auto words = kj::heapArray<word>(reader.totalSize().wordCount + 1);
   1097         memset(words.begin(), 0, words.asBytes().size());
   1098         copyToUnchecked(reader, words);
   1099         kj::BufferedOutputStreamWrapper buffered(output);
   1100         capnp::_::PackedOutputStream packed(buffered);
   1101         packed.write(words.begin(), words.asBytes().size());
   1102         return;
   1103       }
   1104       case Format::CANONICAL: {
   1105         auto words = reader.canonicalize();
   1106         output.write(words.begin(), words.asBytes().size());
   1107         return;
   1108       }
   1109       case Format::TEXT: {
   1110         TextCodec codec;
   1111         codec.setPrettyPrint(pretty);
   1112         auto text = codec.encode(reader.as<DynamicStruct>(rootType));
   1113         output.write({text.asBytes(), kj::StringPtr("\n").asBytes()});
   1114         return;
   1115       }
   1116       case Format::JSON: {
   1117         JsonCodec codec;
   1118         codec.setPrettyPrint(pretty);
   1119         codec.handleByAnnotation(rootType);
   1120         auto text = codec.encode(reader.as<DynamicStruct>(rootType));
   1121         output.write({text.asBytes(), kj::StringPtr("\n").asBytes()});
   1122         return;
   1123       }
   1124     }
   1125 
   1126     KJ_UNREACHABLE;
   1127   }
   1128 
   1129 public:
   1130 
   1131   // =====================================================================================
   1132   // "decode" command
   1133 
   1134   kj::MainBuilder::Validity codeBinary() {
   1135     if (packed) return "cannot be used with --packed";
   1136     if (flat) return "cannot be used with --flat";
   1137     binary = true;
   1138     return true;
   1139   }
   1140   kj::MainBuilder::Validity codeFlat() {
   1141     if (binary) return "cannot be used with --binary";
   1142     flat = true;
   1143     return true;
   1144   }
   1145   kj::MainBuilder::Validity codePacked() {
   1146     if (binary) return "cannot be used with --binary";
   1147     packed = true;
   1148     return true;
   1149   }
   1150   kj::MainBuilder::Validity printShort() {
   1151     pretty = false;
   1152     return true;
   1153   }
   1154   kj::MainBuilder::Validity setQuiet() {
   1155     quiet = true;
   1156     return true;
   1157   }
   1158   kj::MainBuilder::Validity setSegmentSize(kj::StringPtr size) {
   1159     if (flat) return "cannot be used with --flat";
   1160     char* end;
   1161     segmentSize = strtol(size.cStr(), &end, 0);
   1162     if (size.size() == 0 || *end != '\0') {
   1163       return "not an integer";
   1164     }
   1165     return true;
   1166   }
   1167 
   1168   kj::MainBuilder::Validity setRootType(kj::StringPtr input) {
   1169     KJ_ASSERT(sourceFiles.size() == 1);
   1170 
   1171     class CliArgumentErrorReporter: public ErrorReporter {
   1172     public:
   1173       void addError(uint32_t startByte, uint32_t endByte, kj::StringPtr message) override {
   1174         if (startByte < endByte) {
   1175           error = kj::str(startByte + 1, "-", endByte, ": ", message);
   1176         } else if (startByte > 0) {
   1177           error = kj::str(startByte + 1, ": ", message);
   1178         } else {
   1179           error = kj::str(message);
   1180         }
   1181       }
   1182 
   1183       bool hadErrors() override {
   1184         return error != nullptr;
   1185       }
   1186 
   1187       kj::MainBuilder::Validity getValidity() {
   1188         KJ_IF_MAYBE(e, error) {
   1189           return kj::mv(*e);
   1190         } else {
   1191           return true;
   1192         }
   1193       }
   1194 
   1195     private:
   1196       kj::Maybe<kj::String> error;
   1197     };
   1198 
   1199     CliArgumentErrorReporter errorReporter;
   1200 
   1201     capnp::MallocMessageBuilder tokenArena;
   1202     auto lexedTokens = tokenArena.initRoot<capnp::compiler::LexedTokens>();
   1203     lex(input, lexedTokens, errorReporter);
   1204 
   1205     CapnpParser parser(tokenArena.getOrphanage(), errorReporter);
   1206     auto tokens = lexedTokens.asReader().getTokens();
   1207     CapnpParser::ParserInput parserInput(tokens.begin(), tokens.end());
   1208 
   1209     bool success = false;
   1210 
   1211     if (parserInput.getPosition() == tokens.end()) {
   1212       // Empty argument?
   1213       errorReporter.addError(0, 0, "Couldn't parse type name.");
   1214     } else {
   1215       KJ_IF_MAYBE(expression, parser.getParsers().expression(parserInput)) {
   1216         // The input is expected to contain a *single* expression.
   1217         if (parserInput.getPosition() == tokens.end()) {
   1218           // Hooray, now parse it.
   1219           KJ_IF_MAYBE(compiledType,
   1220               sourceFiles[0].compiled.evalType(expression->getReader(), errorReporter)) {
   1221             KJ_IF_MAYBE(type, compiledType->getSchema()) {
   1222               if (type->isStruct()) {
   1223                 rootType = type->asStruct();
   1224                 success = true;
   1225               } else {
   1226                 errorReporter.addError(0, 0, "Type is not a struct.");
   1227               }
   1228             } else {
   1229               // Apparently named a file scope.
   1230               errorReporter.addError(0, 0, "Type is not a struct.");
   1231             }
   1232           }
   1233         } else {
   1234           errorReporter.addErrorOn(parserInput.current(), "Couldn't parse type name.");
   1235         }
   1236       } else {
   1237         auto best = parserInput.getBest();
   1238         if (best == tokens.end()) {
   1239           errorReporter.addError(input.size(), input.size(), "Couldn't parse type name.");
   1240         } else {
   1241           errorReporter.addErrorOn(*best, "Couldn't parse type name.");
   1242         }
   1243       }
   1244     }
   1245 
   1246     KJ_ASSERT(success || errorReporter.hadErrors());
   1247     return errorReporter.getValidity();
   1248   }
   1249 
   1250   kj::MainBuilder::Validity decode() {
   1251     convertTo = Format::TEXT;
   1252     convertFrom = formatFromDeprecatedFlags(Format::BINARY);
   1253     return convert();
   1254   }
   1255 
   1256 private:
   1257   enum Plausibility {
   1258     IMPOSSIBLE,
   1259     IMPLAUSIBLE,
   1260     WRONG_TYPE,
   1261     PLAUSIBLE
   1262   };
   1263 
   1264   bool plausibleOrWrongType(Plausibility p) {
   1265     return p == PLAUSIBLE || p == WRONG_TYPE;
   1266   }
   1267 
   1268   Plausibility isPlausiblyFlat(kj::ArrayPtr<const byte> prefix, uint segmentCount = 1) {
   1269     if (prefix.size() < 8) {
   1270       // Not enough prefix to say.
   1271       return PLAUSIBLE;
   1272     }
   1273 
   1274     if ((prefix[0] & 3) == 2) {
   1275       // Far pointer.  Verify the segment ID.
   1276       uint32_t segmentId = prefix[4] | (prefix[5] << 8)
   1277                          | (prefix[6] << 16) | (prefix[7] << 24);
   1278       if (segmentId == 0 || segmentId >= segmentCount) {
   1279         return IMPOSSIBLE;
   1280       } else {
   1281         return PLAUSIBLE;
   1282       }
   1283     }
   1284 
   1285     if ((prefix[0] & 3) != 0) {
   1286       // Not a struct pointer.
   1287       return IMPOSSIBLE;
   1288     }
   1289     if ((prefix[3] & 0x80) != 0) {
   1290       if (prefix[0] == 0xff && prefix[1] == 0xff && prefix[2] == 0xff && prefix[3] == 0xff &&
   1291           prefix[4] == 0    && prefix[5] == 0    && prefix[6] == 0    && prefix[7] == 0) {
   1292         // This is an empty struct with offset of -1. That's valid.
   1293       } else {
   1294         // Offset is negative (invalid).
   1295         return IMPOSSIBLE;
   1296       }
   1297     }
   1298     if ((prefix[3] & 0xe0) != 0) {
   1299       // Offset is over a gigabyte (implausible).
   1300       return IMPLAUSIBLE;
   1301     }
   1302 
   1303     uint data = prefix[4] | (prefix[5] << 8);
   1304     uint pointers = prefix[6] | (prefix[7] << 8);
   1305 
   1306     if (data + pointers > 2048) {
   1307       // Root struct is huge (over 16 KiB).
   1308       return IMPLAUSIBLE;
   1309     }
   1310 
   1311     auto structSchema = rootType.getProto().getStruct();
   1312     if ((data < structSchema.getDataWordCount() && pointers > structSchema.getPointerCount()) ||
   1313         (data > structSchema.getDataWordCount() && pointers < structSchema.getPointerCount())) {
   1314       // Struct is neither older nor newer than the schema.
   1315       return WRONG_TYPE;
   1316     }
   1317 
   1318     if (data > structSchema.getDataWordCount() &&
   1319         data - structSchema.getDataWordCount() > 128) {
   1320       // Data section appears to have grown by 1k (128 words).  This seems implausible.
   1321       return WRONG_TYPE;
   1322     }
   1323     if (pointers > structSchema.getPointerCount() &&
   1324         pointers - structSchema.getPointerCount() > 128) {
   1325       // Pointer section appears to have grown by 1k (128 words).  This seems implausible.
   1326       return WRONG_TYPE;
   1327     }
   1328 
   1329     return PLAUSIBLE;
   1330   }
   1331 
   1332   Plausibility isPlausiblyBinary(kj::ArrayPtr<const byte> prefix) {
   1333     if (prefix.size() < 8) {
   1334       // Not enough prefix to say.
   1335       return PLAUSIBLE;
   1336     }
   1337 
   1338     uint32_t segmentCount = prefix[0] | (prefix[1] << 8)
   1339                           | (prefix[2] << 16) | (prefix[3] << 24);
   1340 
   1341     // Actually, the bytes store segmentCount - 1.
   1342     ++segmentCount;
   1343 
   1344     if (segmentCount > 65536) {
   1345       // While technically possible, this is so implausible that we should mark it impossible.
   1346       // This helps to make sure we fail fast on packed input.
   1347       return IMPOSSIBLE;
   1348     } else if (segmentCount > 256) {
   1349       // Implausible segment count.
   1350       return IMPLAUSIBLE;
   1351     }
   1352 
   1353     uint32_t segment0Size = prefix[4] | (prefix[5] << 8)
   1354                           | (prefix[6] << 16) | (prefix[7] << 24);
   1355 
   1356     if (segment0Size > (1 << 27)) {
   1357       // Segment larger than 1G seems implausible.
   1358       return IMPLAUSIBLE;
   1359     }
   1360 
   1361     uint32_t segment0Offset = 4 + segmentCount * 4;
   1362     if (segment0Offset % 8 != 0) {
   1363       segment0Offset += 4;
   1364     }
   1365     KJ_ASSERT(segment0Offset % 8 == 0);
   1366 
   1367     if (prefix.size() < segment0Offset + 8) {
   1368       // Segment 0 is past our prefix, so we can't check it.
   1369       return PLAUSIBLE;
   1370     }
   1371 
   1372     return isPlausiblyFlat(prefix.slice(segment0Offset, prefix.size()), segmentCount);
   1373   }
   1374 
   1375   Plausibility isPlausiblyPacked(kj::ArrayPtr<const byte> prefix,
   1376       kj::Function<Plausibility(kj::ArrayPtr<const byte>)> checkUnpacked) {
   1377     kj::Vector<byte> unpacked;
   1378 
   1379     // Try to unpack a prefix so that we can check it.
   1380     const byte* pos = prefix.begin();
   1381     const byte* end = prefix.end();
   1382     if (end - pos > 1024) {
   1383       // Don't bother unpacking more than 1k.
   1384       end = pos + 1024;
   1385     }
   1386     while (pos < end) {
   1387       byte tag = *pos++;
   1388       for (uint i = 0; i < 8 && pos < end; i++) {
   1389         if (tag & (1 << i)) {
   1390           byte b = *pos++;
   1391           if (b == 0) {
   1392             // A zero byte should have been deflated away.
   1393             return IMPOSSIBLE;
   1394           }
   1395           unpacked.add(b);
   1396         } else {
   1397           unpacked.add(0);
   1398         }
   1399       }
   1400 
   1401       if (pos == end) {
   1402         break;
   1403       }
   1404 
   1405       if (tag == 0) {
   1406         uint count = *pos++ * 8;
   1407         unpacked.addAll(kj::repeat(byte(0), count));
   1408       } else if (tag == 0xff) {
   1409         uint count = *pos++ * 8;
   1410         size_t available = end - pos;
   1411         uint n = kj::min(count, available);
   1412         unpacked.addAll(pos, pos + n);
   1413         pos += n;
   1414       }
   1415     }
   1416 
   1417     return checkUnpacked(unpacked);
   1418   }
   1419 
   1420   Plausibility isPlausiblyPacked(kj::ArrayPtr<const byte> prefix) {
   1421     return isPlausiblyPacked(prefix, KJ_BIND_METHOD(*this, isPlausiblyBinary));
   1422   }
   1423 
   1424   Plausibility isPlausiblyPackedFlat(kj::ArrayPtr<const byte> prefix) {
   1425     return isPlausiblyPacked(prefix, [this](kj::ArrayPtr<const byte> prefix) {
   1426       return isPlausiblyFlat(prefix);
   1427     });
   1428   }
   1429 
   1430   Plausibility isPlausiblyText(kj::ArrayPtr<const byte> prefix) {
   1431     enum { PREAMBLE, COMMENT, BODY } state = PREAMBLE;
   1432 
   1433     for (char c: prefix.asChars()) {
   1434       switch (state) {
   1435         case PREAMBLE:
   1436           // Before opening parenthesis.
   1437           switch (c) {
   1438             case '(': state = BODY; continue;
   1439             case '#': state = COMMENT; continue;
   1440             case ' ':
   1441             case '\n':
   1442             case '\r':
   1443             case '\t':
   1444             case '\v':
   1445               // whitespace
   1446               break;
   1447             default:
   1448               // Not whitespace, not comment, not open parenthesis. Impossible!
   1449               return IMPOSSIBLE;
   1450           }
   1451           break;
   1452         case COMMENT:
   1453           switch (c) {
   1454             case '\n': state = PREAMBLE; continue;
   1455             default: break;
   1456           }
   1457           break;
   1458         case BODY:
   1459           switch (c) {
   1460             case '\"':
   1461             case '\'':
   1462               // String literal. Let's stop here before things get complicated.
   1463               return PLAUSIBLE;
   1464             default:
   1465               break;
   1466           }
   1467           break;
   1468       }
   1469 
   1470       if ((static_cast<uint8_t>(c) < 0x20 && c != '\n' && c != '\r' && c != '\t' && c != '\v')
   1471           || c == 0x7f) {
   1472         // Unprintable character.
   1473         return IMPOSSIBLE;
   1474       }
   1475     }
   1476 
   1477     return PLAUSIBLE;
   1478   }
   1479 
   1480   Plausibility isPlausiblyJson(kj::ArrayPtr<const byte> prefix) {
   1481     enum { PREAMBLE, COMMENT, BODY } state = PREAMBLE;
   1482 
   1483     for (char c: prefix.asChars()) {
   1484       switch (state) {
   1485         case PREAMBLE:
   1486           // Before opening parenthesis.
   1487           switch (c) {
   1488             case '{': state = BODY; continue;
   1489             case '#': state = COMMENT; continue;
   1490             case '/': state = COMMENT; continue;
   1491             case ' ':
   1492             case '\n':
   1493             case '\r':
   1494             case '\t':
   1495             case '\v':
   1496               // whitespace
   1497               break;
   1498             default:
   1499               // Not whitespace, not comment, not open brace. Impossible!
   1500               return IMPOSSIBLE;
   1501           }
   1502           break;
   1503         case COMMENT:
   1504           switch (c) {
   1505             case '\n': state = PREAMBLE; continue;
   1506             default: break;
   1507           }
   1508           break;
   1509         case BODY:
   1510           switch (c) {
   1511             case '\"':
   1512               // String literal. Let's stop here before things get complicated.
   1513               return PLAUSIBLE;
   1514             default:
   1515               break;
   1516           }
   1517           break;
   1518       }
   1519 
   1520       if ((c > 0 && c < ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\v') || c == 0x7f) {
   1521         // Unprintable character.
   1522         return IMPOSSIBLE;
   1523       }
   1524     }
   1525 
   1526     return PLAUSIBLE;
   1527   }
   1528 
   1529   Plausibility isPlausibly(Format format, kj::ArrayPtr<const byte> prefix) {
   1530     switch (format) {
   1531       case Format::BINARY     : return isPlausiblyBinary    (prefix);
   1532       case Format::PACKED     : return isPlausiblyPacked    (prefix);
   1533       case Format::FLAT       : return isPlausiblyFlat      (prefix);
   1534       case Format::FLAT_PACKED: return isPlausiblyPackedFlat(prefix);
   1535       case Format::CANONICAL  : return isPlausiblyFlat      (prefix);
   1536       case Format::TEXT       : return isPlausiblyText      (prefix);
   1537       case Format::JSON       : return isPlausiblyJson      (prefix);
   1538     }
   1539     KJ_UNREACHABLE;
   1540   }
   1541 
   1542   kj::Maybe<Format> guessFormat(kj::ArrayPtr<const byte> prefix) {
   1543     Format candidates[] = {
   1544       Format::BINARY,
   1545       Format::TEXT,
   1546       Format::PACKED,
   1547       Format::JSON,
   1548       Format::FLAT,
   1549       Format::FLAT_PACKED
   1550     };
   1551 
   1552     for (Format candidate: candidates) {
   1553       if (plausibleOrWrongType(isPlausibly(candidate, prefix))) {
   1554         return candidate;
   1555       }
   1556     }
   1557 
   1558     return nullptr;
   1559   }
   1560 
   1561   kj::MainBuilder::Validity checkPlausibility(Format format, kj::ArrayPtr<const byte> prefix) {
   1562     switch (isPlausibly(format, prefix)) {
   1563       case PLAUSIBLE:
   1564         return true;
   1565 
   1566       case IMPOSSIBLE:
   1567         KJ_IF_MAYBE(guess, guessFormat(prefix)) {
   1568           return kj::str(
   1569              "The input is not in \"", toString(format), "\" format. It looks like it is in \"",
   1570              toString(*guess), "\" format. Try that instead.");
   1571         } else {
   1572           return kj::str(
   1573              "The input is not in \"", toString(format), "\" format.");
   1574         }
   1575 
   1576       case IMPLAUSIBLE:
   1577         KJ_IF_MAYBE(guess, guessFormat(prefix)) {
   1578           context.warning(kj::str(
   1579               "*** WARNING ***\n"
   1580               "The input data does not appear to be in \"", toString(format), "\" format. It\n"
   1581               "looks like it may be in \"", toString(*guess), "\" format. I'll try to parse\n"
   1582               "it in \"", toString(format), "\" format as you requested, but if it doesn't work,\n"
   1583               "try \"", toString(format), "\" instead. Use --quiet to suppress this warning.\n"
   1584               "*** END WARNING ***\n"));
   1585         } else {
   1586           context.warning(kj::str(
   1587               "*** WARNING ***\n"
   1588               "The input data does not appear to be in \"", toString(format), "\" format, nor\n"
   1589               "in any other known format. I'll try to parse it in \"", toString(format), "\"\n"
   1590               "format anyway, as you requested. Use --quiet to suppress this warning.\n"
   1591               "*** END WARNING ***\n"));
   1592         }
   1593         return true;
   1594 
   1595       case WRONG_TYPE:
   1596         if (format == Format::FLAT && plausibleOrWrongType(isPlausiblyBinary(prefix))) {
   1597           context.warning(
   1598               "*** WARNING ***\n"
   1599               "The input data does not appear to match the schema that you specified. I'll try\n"
   1600               "to parse it anyway, but if it doesn't look right, please verify that you\n"
   1601               "have the right schema. This could also be because the input is not in \"flat\"\n"
   1602               "format; indeed, it looks like this input may be in regular binary format,\n"
   1603               "so you might want to try \"binary\" instead.  Use --quiet to suppress this\n"
   1604               "warning.\n"
   1605               "*** END WARNING ***\n");
   1606         } else if (format == Format::FLAT_PACKED &&
   1607                    plausibleOrWrongType(isPlausiblyPacked(prefix))) {
   1608           context.warning(
   1609               "*** WARNING ***\n"
   1610               "The input data does not appear to match the schema that you specified. I'll try\n"
   1611               "to parse it anyway, but if it doesn't look right, please verify that you\n"
   1612               "have the right schema. This could also be because the input is not in \"flat-packed\"\n"
   1613               "format; indeed, it looks like this input may be in regular packed format,\n"
   1614               "so you might want to try \"packed\" instead.  Use --quiet to suppress this\n"
   1615               "warning.\n"
   1616               "*** END WARNING ***\n");
   1617         } else {
   1618           context.warning(
   1619               "*** WARNING ***\n"
   1620               "The input data does not appear to be the type that you specified.  I'll try\n"
   1621               "to parse it anyway, but if it doesn't look right, please verify that you\n"
   1622               "have the right type.  Use --quiet to suppress this warning.\n"
   1623               "*** END WARNING ***\n");
   1624         }
   1625         return true;
   1626     }
   1627 
   1628     KJ_UNREACHABLE;
   1629   }
   1630 
   1631 public:
   1632   // -----------------------------------------------------------------
   1633 
   1634   kj::MainBuilder::Validity encode() {
   1635     convertFrom = Format::TEXT;
   1636     convertTo = formatFromDeprecatedFlags(Format::BINARY);
   1637     return convert();
   1638   }
   1639 
   1640   kj::MainBuilder::Validity setEvalOutputFormat(kj::StringPtr format) {
   1641     KJ_IF_MAYBE(f, parseFormatName(format)) {
   1642       convertTo = *f;
   1643       return true;
   1644     } else {
   1645       return kj::str("unknown format: ", format);
   1646     }
   1647   }
   1648 
   1649   kj::MainBuilder::Validity evalConst(kj::StringPtr name) {
   1650     convertTo = formatFromDeprecatedFlags(convertTo);
   1651 
   1652     KJ_ASSERT(sourceFiles.size() == 1);
   1653 
   1654     auto parser = kj::parse::sequence(
   1655         kj::parse::many(
   1656             kj::parse::sequence(
   1657                 kj::parse::identifier,
   1658                 kj::parse::many(
   1659                     kj::parse::sequence(
   1660                         kj::parse::exactChar<'['>(),
   1661                         kj::parse::integer,
   1662                         kj::parse::exactChar<']'>())),
   1663                 kj::parse::oneOf(
   1664                     kj::parse::endOfInput,
   1665                     kj::parse::sequence(
   1666                         kj::parse::exactChar<'.'>(),
   1667                         kj::parse::notLookingAt(kj::parse::endOfInput))))),
   1668         kj::parse::endOfInput);
   1669 
   1670     kj::parse::IteratorInput<char, const char*> input(name.begin(), name.end());
   1671 
   1672     kj::Array<kj::Tuple<kj::String, kj::Array<uint64_t>>> nameParts;
   1673     KJ_IF_MAYBE(p, parser(input)) {
   1674       nameParts = kj::mv(*p);
   1675     } else {
   1676       return "invalid syntax";
   1677     }
   1678 
   1679     auto pos = nameParts.begin();
   1680 
   1681     // Traverse the path to find a schema.
   1682     uint64_t scopeId = sourceFiles[0].id;
   1683     bool stoppedAtSubscript = false;
   1684     for (; pos != nameParts.end(); ++pos) {
   1685       kj::StringPtr part = kj::get<0>(*pos);
   1686 
   1687       KJ_IF_MAYBE(childId, compiler->lookup(scopeId, part)) {
   1688         scopeId = *childId;
   1689 
   1690         if (kj::get<1>(*pos).size() > 0) {
   1691           stoppedAtSubscript = true;
   1692           break;
   1693         }
   1694       } else {
   1695         break;
   1696       }
   1697     }
   1698     Schema schema = compiler->getLoader().get(scopeId);
   1699 
   1700     // Evaluate this schema to a DynamicValue.
   1701     DynamicValue::Reader value;
   1702     word zeroWord[1];
   1703     memset(&zeroWord, 0, sizeof(zeroWord));
   1704     kj::ArrayPtr<const word> segments[1] = { kj::arrayPtr(zeroWord, 1) };
   1705     SegmentArrayMessageReader emptyMessage(segments);
   1706     switch (schema.getProto().which()) {
   1707       case schema::Node::CONST:
   1708         value = schema.asConst();
   1709         break;
   1710 
   1711       case schema::Node::STRUCT:
   1712         if (pos == nameParts.end()) {
   1713           return kj::str("'", schema.getShortDisplayName(), "' cannot be evaluated.");
   1714         }
   1715 
   1716         // Use the struct's default value.
   1717         value = emptyMessage.getRoot<DynamicStruct>(schema.asStruct());
   1718         break;
   1719 
   1720       default:
   1721         if (stoppedAtSubscript) {
   1722           return kj::str("'", schema.getShortDisplayName(), "' is not a list.");
   1723         } else if (pos != nameParts.end()) {
   1724           return kj::str("'", kj::get<0>(*pos), "' is not defined.");
   1725         } else {
   1726           return kj::str("'", schema.getShortDisplayName(), "' cannot be evaluated.");
   1727         }
   1728     }
   1729 
   1730     // Traverse the rest of the path as struct fields.
   1731     for (; pos != nameParts.end(); ++pos) {
   1732       kj::StringPtr partName = kj::get<0>(*pos);
   1733 
   1734       if (!stoppedAtSubscript) {
   1735         if (value.getType() == DynamicValue::STRUCT) {
   1736           auto structValue = value.as<DynamicStruct>();
   1737           KJ_IF_MAYBE(field, structValue.getSchema().findFieldByName(partName)) {
   1738             value = structValue.get(*field);
   1739           } else {
   1740             return kj::str("'", kj::get<0>(pos[-1]), "' has no member '", partName, "'.");
   1741           }
   1742         } else {
   1743           return kj::str("'", kj::get<0>(pos[-1]), "' is not a struct.");
   1744         }
   1745       }
   1746 
   1747       auto& subscripts = kj::get<1>(*pos);
   1748       for (uint i = 0; i < subscripts.size(); i++) {
   1749         uint64_t subscript = subscripts[i];
   1750         if (value.getType() == DynamicValue::LIST) {
   1751           auto listValue = value.as<DynamicList>();
   1752           if (subscript < listValue.size()) {
   1753             value = listValue[subscript];
   1754           } else {
   1755             return kj::str("'", partName, "[", kj::strArray(subscripts.slice(0, i + 1), "]["),
   1756                            "]' is out-of-bounds.");
   1757           }
   1758         } else {
   1759           if (i > 0) {
   1760             return kj::str("'", partName, "[", kj::strArray(subscripts.slice(0, i), "]["),
   1761                            "]' is not a list.");
   1762           } else {
   1763             return kj::str("'", partName, "' is not a list.");
   1764           }
   1765         }
   1766       }
   1767 
   1768       stoppedAtSubscript = false;
   1769     }
   1770 
   1771     // OK, we have a value.  Print it.
   1772     if (convertTo != Format::TEXT) {
   1773       if (value.getType() != DynamicValue::STRUCT) {
   1774         return "not a struct; binary output is only available on structs";
   1775       }
   1776 
   1777       auto structValue = value.as<DynamicStruct>();
   1778       rootType = structValue.getSchema();
   1779       kj::FdOutputStream output(STDOUT_FILENO);
   1780       writeConversion(structValue, output);
   1781       context.exit();
   1782     } else {
   1783       if (pretty && value.getType() == DynamicValue::STRUCT) {
   1784         context.exitInfo(prettyPrint(value.as<DynamicStruct>()).flatten());
   1785       } else if (pretty && value.getType() == DynamicValue::LIST) {
   1786         context.exitInfo(prettyPrint(value.as<DynamicList>()).flatten());
   1787       } else {
   1788         context.exitInfo(kj::str(value));
   1789       }
   1790     }
   1791 
   1792     KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT;
   1793   }
   1794 
   1795 public:
   1796   // =====================================================================================
   1797 
   1798   void addError(const kj::ReadableDirectory& directory, kj::PathPtr path,
   1799                 SourcePos start, SourcePos end,
   1800                 kj::StringPtr message) override {
   1801     auto file = getDisplayName(directory, path);
   1802 
   1803     kj::String wholeMessage;
   1804     if (end.line == start.line) {
   1805       if (end.column == start.column) {
   1806         wholeMessage = kj::str(file, ":", start.line + 1, ":", start.column + 1,
   1807                                ": error: ", message, "\n");
   1808       } else {
   1809         wholeMessage = kj::str(file, ":", start.line + 1, ":", start.column + 1,
   1810                                "-", end.column + 1, ": error: ", message, "\n");
   1811       }
   1812     } else {
   1813       // The error spans multiple lines, so just report it on the first such line.
   1814       wholeMessage = kj::str(file, ":", start.line + 1, ": error: ", message, "\n");
   1815     }
   1816 
   1817     context.error(wholeMessage);
   1818     hadErrors_ = true;
   1819   }
   1820 
   1821   bool hadErrors() override {
   1822     return hadErrors_;
   1823   }
   1824 
   1825 private:
   1826   kj::ProcessContext& context;
   1827   kj::Own<kj::Filesystem> disk;
   1828   ModuleLoader loader;
   1829   kj::SpaceFor<Compiler> compilerSpace;
   1830   bool compilerConstructed = false;
   1831   kj::Own<Compiler> compiler;
   1832 
   1833   Compiler::AnnotationFlag annotationFlag = Compiler::COMPILE_ANNOTATIONS;
   1834 
   1835   uint compileEagerness = Compiler::NODE | Compiler::CHILDREN |
   1836                           Compiler::DEPENDENCIES | Compiler::DEPENDENCY_PARENTS;
   1837   // By default we compile each explicitly listed schema in full, plus first-level dependencies
   1838   // of those schemas, plus the parent nodes of any dependencies.  This is what most code generators
   1839   // require to function.
   1840 
   1841   struct SourceDirectory {
   1842     kj::Own<const kj::ReadableDirectory> dir;
   1843     bool isSourcePrefix;
   1844   };
   1845 
   1846   kj::HashMap<kj::Path, SourceDirectory> sourceDirectories;
   1847   // For each import path and source prefix, tracks the directory object we opened for it.
   1848   //
   1849   // Use via getSourceDirectory().
   1850 
   1851   kj::HashMap<const kj::ReadableDirectory*, kj::String> dirPrefixes;
   1852   // For each open directory object, maps to a path prefix to add when displaying this path in
   1853   // error messages. This keeps track of the original directory name as given by the user, before
   1854   // canonicalization.
   1855   //
   1856   // Use via getDisplayName().
   1857 
   1858   bool addStandardImportPaths = true;
   1859 
   1860   Format convertFrom = Format::BINARY;
   1861   Format convertTo = Format::BINARY;
   1862   // For the "convert" command.
   1863 
   1864   bool binary = false;
   1865   bool flat = false;
   1866   bool packed = false;
   1867   bool pretty = true;
   1868   bool quiet = false;
   1869   uint segmentSize = 0;
   1870   StructSchema rootType;
   1871   // For the "decode" and "encode" commands.
   1872 
   1873   struct SourceFile {
   1874     uint64_t id;
   1875     Compiler::ModuleScope compiled;
   1876     kj::StringPtr name;
   1877     Module* module;
   1878   };
   1879 
   1880   kj::Vector<SourceFile> sourceFiles;
   1881 
   1882   struct OutputDirective {
   1883     kj::ArrayPtr<const char> name;
   1884     kj::Maybe<kj::Path> dir;
   1885 
   1886     KJ_DISALLOW_COPY(OutputDirective);
   1887     OutputDirective(OutputDirective&&) = default;
   1888     OutputDirective(kj::ArrayPtr<const char> name, kj::Maybe<kj::Path> dir)
   1889         : name(name), dir(kj::mv(dir)) {}
   1890   };
   1891   kj::Vector<OutputDirective> outputs;
   1892 
   1893   bool hadErrors_ = false;
   1894 
   1895   kj::Maybe<const kj::ReadableDirectory&> getSourceDirectory(
   1896       kj::StringPtr pathStr, bool isSourcePrefix) {
   1897     auto cwd = disk->getCurrentPath();
   1898     auto path = cwd.evalNative(pathStr);
   1899 
   1900     if (path.size() == 0) return disk->getRoot();
   1901 
   1902     KJ_IF_MAYBE(sdir, sourceDirectories.find(path)) {
   1903       sdir->isSourcePrefix = sdir->isSourcePrefix || isSourcePrefix;
   1904       return *sdir->dir;
   1905     }
   1906 
   1907     if (path == cwd) {
   1908       // Slight hack if the working directory is explicitly specified:
   1909       // - We want to avoid opening a new copy of the working directory, as tryOpenSubdir() would
   1910       //   do.
   1911       // - If isSourcePrefix is true, we need to add it to sourceDirectories to track that.
   1912       //   Otherwise we don't need to add it at all.
   1913       // - We do not need to add it to dirPrefixes since the cwd is already handled in
   1914       //   getDisplayName().
   1915       auto& result = disk->getCurrent();
   1916       if (isSourcePrefix) {
   1917         kj::Own<const kj::ReadableDirectory> fakeOwn(&result, kj::NullDisposer::instance);
   1918         sourceDirectories.insert(kj::mv(path), { kj::mv(fakeOwn), isSourcePrefix });
   1919       }
   1920       return result;
   1921     }
   1922 
   1923     KJ_IF_MAYBE(dir, disk->getRoot().tryOpenSubdir(path)) {
   1924       auto& result = *dir->get();
   1925       sourceDirectories.insert(kj::mv(path), { kj::mv(*dir), isSourcePrefix });
   1926 #if _WIN32
   1927       kj::String prefix = pathStr.endsWith("/") || pathStr.endsWith("\\")
   1928                         ? kj::str(pathStr) : kj::str(pathStr, '\\');
   1929 #else
   1930       kj::String prefix = pathStr.endsWith("/") ? kj::str(pathStr) : kj::str(pathStr, '/');
   1931 #endif
   1932       dirPrefixes.insert(&result, kj::mv(prefix));
   1933       return result;
   1934     } else {
   1935       return nullptr;
   1936     }
   1937   }
   1938 
   1939   struct DirPathPair {
   1940     const kj::ReadableDirectory& dir;
   1941     kj::Path path;
   1942   };
   1943 
   1944   DirPathPair interpretSourceFile(kj::StringPtr pathStr) {
   1945     auto cwd = disk->getCurrentPath();
   1946     auto path = cwd.evalNative(pathStr);
   1947 
   1948     KJ_REQUIRE(path.size() > 0);
   1949     for (size_t i = path.size() - 1; i > 0; i--) {
   1950       auto prefix = path.slice(0, i);
   1951       auto remainder = path.slice(i, path.size());
   1952 
   1953       KJ_IF_MAYBE(sdir, sourceDirectories.find(prefix)) {
   1954         if (sdir->isSourcePrefix) {
   1955           return { *sdir->dir, remainder.clone() };
   1956         }
   1957       }
   1958     }
   1959 
   1960     // No source prefix matched. Fall back to heuristic: try stripping the current directory,
   1961     // otherwise don't strip anything.
   1962     if (path.startsWith(cwd)) {
   1963       return { disk->getCurrent(), path.slice(cwd.size(), path.size()).clone() };
   1964     } else {
   1965       // Hmm, no src-prefix matched and the file isn't even in the current directory. This might
   1966       // be OK if we aren't generating any output anyway, but otherwise the results will almost
   1967       // certainly not be what the user wanted. Let's print a warning, unless the output directives
   1968       // are ones which we know do not produce output files. This is a hack.
   1969       for (auto& output: outputs) {
   1970         auto name = kj::str(output.name);
   1971         if (name != "-" && name != "capnp") {
   1972           context.warning(kj::str(pathStr,
   1973               ": File is not in the current directory and does not match any prefix defined with "
   1974               "--src-prefix. Please pass an appropriate --src-prefix so I can figure out where to "
   1975               "write the output for this file."));
   1976           break;
   1977         }
   1978       }
   1979 
   1980       return { disk->getRoot(), kj::mv(path) };
   1981     }
   1982   }
   1983 
   1984   kj::String getDisplayName(const kj::ReadableDirectory& dir, kj::PathPtr path) {
   1985     KJ_IF_MAYBE(prefix, dirPrefixes.find(&dir)) {
   1986       return kj::str(*prefix, path.toNativeString());
   1987     } else if (&dir == &disk->getRoot()) {
   1988       return path.toNativeString(true);
   1989     } else if (&dir == &disk->getCurrent()) {
   1990       return path.toNativeString(false);
   1991     } else {
   1992       KJ_FAIL_ASSERT("unrecognized directory");
   1993     }
   1994   }
   1995 };
   1996 
   1997 }  // namespace compiler
   1998 }  // namespace capnp
   1999 
   2000 KJ_MAIN(capnp::compiler::CompilerMain);