From 9f5697c3d752172128f895bbd0977552aeef04ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Barzowski?= Date: Thu, 20 Jul 2017 12:43:12 -0400 Subject: [PATCH] Reformat code (and add make target to do so) --- .clang-format | 85 +++ Makefile | 8 + cmd/jsonnet.cpp | 131 ++-- core/ast.h | 534 ++++++++++------ core/desugarer.cpp | 480 ++++++++------- core/formatter.cpp | 627 +++++++++---------- core/formatter.h | 25 +- core/json.h | 2 +- core/lexer.cpp | 744 ++++++++++++----------- core/lexer.h | 85 +-- core/lexer_test.cpp | 174 +++--- core/libjsonnet.cpp | 222 ++++--- core/libjsonnet_test.cpp | 2 +- core/parser.cpp | 614 ++++++++++--------- core/parser_test.cpp | 237 +++----- core/pass.cpp | 135 ++--- core/pass.h | 30 +- core/state.h | 137 ++--- core/static_analysis.cpp | 57 +- core/static_error.h | 29 +- core/string_utils.cpp | 150 ++--- core/unicode.h | 66 +- core/vm.cpp | 1212 ++++++++++++++++++------------------- core/vm.h | 60 +- cpp/libjsonnet++.cpp | 41 +- cpp/libjsonnet++_test.cpp | 6 +- include/libjsonnet++.h | 15 +- include/libjsonnet.h | 55 +- 28 files changed, 3097 insertions(+), 2866 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..090d7883c --- /dev/null +++ b/.clang-format @@ -0,0 +1,85 @@ +--- +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: WebKit +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^[*]* [@\\]' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '^TRY$' +MacroBlockEnd: '^CATCH$' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never +... + diff --git a/Makefile b/Makefile index ed5f69fff..8e23a063d 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,12 @@ test: jsonnet libjsonnet.so libjsonnet_test_snippet libjsonnet_test_file cd test_suite ; ./run_fmt_tests.sh cd test_suite ; ./run_fmt_idempotence_tests.sh +reformat: + clang-format -i -style=file **/*.cpp **/*.h + +test-formatting: + test "`clang-format -style=file -output-replacements-xml **/*.cpp **/*.h | grep -c " #include #include -#include #include #include @@ -26,7 +26,7 @@ limitations under the License. #include extern "C" { - #include +#include } std::string next_arg(unsigned &i, const std::vector &args) @@ -43,7 +43,7 @@ std::string next_arg(unsigned &i, const std::vector &args) std::vector simplify_args(int argc, const char **argv) { std::vector r; - for (int i=1 ; i simplify_args(int argc, const char **argv) } // Check if it is of the form -abc and convert to -a -b -c if (arg.length() > 2 && arg[0] == '-' && arg[1] != '-') { - for (unsigned j=1 ; j= \"" - << var_file << "\"." << std::endl; + std::cerr << "ERROR: argument not in form = \"" << var_file << "\"." + << std::endl; return false; } var = var_file.substr(0, eq_pos); @@ -219,10 +220,8 @@ bool get_var_file(const std::string &var_file, std::string &var, std::string &va /** Parse the command line arguments, configuring the Jsonnet VM context and * populating the JsonnetConfig. */ -static bool process_args(int argc, - const char **argv, - JsonnetConfig *config, - JsonnetVm *vm) { +static bool process_args(int argc, const char **argv, JsonnetConfig *config, JsonnetVm *vm) +{ auto args = simplify_args(argc, argv); std::vector remaining_args; @@ -235,7 +234,7 @@ static bool process_args(int argc, i++; } - for (; icmd == FMT && - (config->fmtTest || config->fmtInPlace); + bool multiple_files_allowed = config->cmd == FMT && (config->fmtTest || config->fmtInPlace); if (!multiple_files_allowed) { std::string filename = remaining_args[0]; if (remaining_args.size() > 1) { - std::cerr << "ERROR: Already specified " << want - << " as \"" << filename << "\"\n" + std::cerr << "ERROR: Already specified " << want << " as \"" << filename << "\"\n" << std::endl; usage(std::cerr); return false; @@ -481,11 +473,11 @@ static bool process_args(int argc, } /** Reads from the input file or stdin into the input buffer. */ -static bool read_input_content(std::string filename, std::string *input) { +static bool read_input_content(std::string filename, std::string *input) +{ // Input file "-" tells Jsonnet to read stdin. if (filename == "-") { - input->assign(std::istreambuf_iterator(std::cin), - std::istreambuf_iterator()); + input->assign(std::istreambuf_iterator(std::cin), std::istreambuf_iterator()); } else { std::ifstream f; f.open(filename); @@ -494,8 +486,7 @@ static bool read_input_content(std::string filename, std::string *input) { perror(msg.c_str()); return false; } - input->assign(std::istreambuf_iterator(f), - std::istreambuf_iterator()); + input->assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); if (!f.good()) { std::string msg = "Reading input file: " + filename; perror(msg.c_str()); @@ -505,7 +496,8 @@ static bool read_input_content(std::string filename, std::string *input) { return true; } -void change_special_filename(JsonnetConfig *config, std::string *filename) { +void change_special_filename(JsonnetConfig *config, std::string *filename) +{ if (config->filenameIsCode) { *filename = ""; } else if (*filename == "-") { @@ -514,9 +506,9 @@ void change_special_filename(JsonnetConfig *config, std::string *filename) { } /** Gets Jsonnet code from any source into the input buffer and changes - * the filename if it's not an actual filename (e.g. "-"). */ -static bool read_input(JsonnetConfig* config, std::string *filename, - std::string* input) { + * the filename if it's not an actual filename (e.g. "-"). */ +static bool read_input(JsonnetConfig *config, std::string *filename, std::string *input) +{ bool ok; if (config->filenameIsCode) { *input = *filename; @@ -531,20 +523,21 @@ static bool read_input(JsonnetConfig* config, std::string *filename, } /** Writes output files for multiple file output */ -static bool write_multi_output_files(JsonnetVm* vm, char* output, - const std::string& output_dir) +static bool write_multi_output_files(JsonnetVm *vm, char *output, const std::string &output_dir) { // If multiple file output is used, then iterate over each string from // the sequence of strings returned by jsonnet_evaluate_snippet_multi, // construct pairs of filename and content, and write each output file. std::map r; - for (const char *c=output ; *c!='\0' ; ) { + for (const char *c = output; *c != '\0';) { const char *filename = c; const char *c2 = c; - while (*c2 != '\0') ++c2; + while (*c2 != '\0') + ++c2; ++c2; const char *json = c2; - while (*c2 != '\0') ++c2; + while (*c2 != '\0') + ++c2; ++c2; c = c2; r[filename] = json; @@ -590,15 +583,16 @@ static bool write_multi_output_files(JsonnetVm* vm, char* output, } /** Writes output files for YAML stream output */ -static bool write_output_stream(JsonnetVm* vm, char* output) +static bool write_output_stream(JsonnetVm *vm, char *output) { // If YAML stream output is used, then iterate over each string from // the sequence of strings returned by jsonnet_evaluate_snippet_stream, // and add the --- and ... as defined by the YAML spec. std::vector r; - for (const char *c=output ; *c!='\0' ; ) { + for (const char *c = output; *c != '\0';) { const char *json = c; - while (*c != '\0') ++c; + while (*c != '\0') + ++c; ++c; r.emplace_back(json); } @@ -616,8 +610,8 @@ static bool write_output_stream(JsonnetVm* vm, char* output) /** Writes the output JSON to the specified output file for single-file * output */ -static bool write_output_file(const char* output, - const std::string &output_file) { +static bool write_output_file(const char *output, const std::string &output_file) +{ if (output_file.empty()) { std::cout << output; std::cout.flush(); @@ -701,15 +695,14 @@ int main(int argc, const char **argv) return EXIT_FAILURE; } } - } - break; + } break; case FMT: { std::string output_file = config.outputFile; if (config.fmtInPlace || config.fmtTest) { assert(config.inputFiles.size() >= 1); - for (std::string &inputFile: config.inputFiles) { + for (std::string &inputFile : config.inputFiles) { if (config.fmtInPlace) { output_file = inputFile; @@ -719,7 +712,8 @@ int main(int argc, const char **argv) return EXIT_FAILURE; } if (config.filenameIsCode) { - std::cerr << "ERROR: Cannot use --in-place with --exec" << std::endl; + std::cerr << "ERROR: Cannot use --in-place with --exec" + << std::endl; jsonnet_destroy(vm); return EXIT_FAILURE; } @@ -767,7 +761,8 @@ int main(int argc, const char **argv) return EXIT_FAILURE; } - output = jsonnet_fmt_snippet(vm, config.inputFiles[0].c_str(), input.c_str(), &error); + output = jsonnet_fmt_snippet( + vm, config.inputFiles[0].c_str(), input.c_str(), &error); if (error) { std::cerr << output; @@ -784,8 +779,7 @@ int main(int argc, const char **argv) return EXIT_FAILURE; } } - } - break; + } break; } jsonnet_destroy(vm); @@ -795,12 +789,9 @@ int main(int argc, const char **argv) // Avoid further allocation attempts fputs("Internal out-of-memory error (please report this)\n", stderr); } catch (const std::exception &e) { - std::cerr << "Internal error (please report this): " - << e.what() << std::endl; + std::cerr << "Internal error (please report this): " << e.what() << std::endl; } catch (...) { - std::cerr << "An unknown exception occurred (please report this)." - << std::endl; + std::cerr << "An unknown exception occurred (please report this)." << std::endl; } return EXIT_FAILURE; } - diff --git a/core/ast.h b/core/ast.h index 24a03efee..6ed56a889 100644 --- a/core/ast.h +++ b/core/ast.h @@ -17,12 +17,12 @@ limitations under the License. #ifndef JSONNET_AST_H #define JSONNET_AST_H -#include #include +#include #include -#include #include +#include #include #include "lexer.h" @@ -60,8 +60,9 @@ enum ASTType { AST_VAR }; -static inline std::string ASTTypeToString(ASTType type) { - switch(type) { +static inline std::string ASTTypeToString(ASTType type) +{ + switch (type) { case AST_APPLY: return "AST_APPLY"; case AST_ARRAY: return "AST_ARRAY"; case AST_ARRAY_COMPREHENSION: return "AST_ARRAY_COMPREHENSION"; @@ -92,16 +93,15 @@ static inline std::string ASTTypeToString(ASTType type) { case AST_UNARY: return "AST_UNARY"; case AST_VAR: return "AST_VAR"; } - std::cerr << "Invalid AST type" << "\n"; + std::cerr << "Invalid AST type" + << "\n"; abort(); } /** Represents a variable / parameter / field name. */ struct Identifier { UString name; - Identifier(const UString &name) - : name(name) - { } + Identifier(const UString &name) : name(name) {} }; static inline std::ostream &operator<<(std::ostream &o, const Identifier *id) @@ -112,7 +112,6 @@ static inline std::ostream &operator<<(std::ostream &o, const Identifier *id) typedef std::vector Identifiers; - /** All AST nodes are subtypes of this class. */ struct AST { @@ -121,15 +120,13 @@ struct AST { Fodder openFodder; Identifiers freeVariables; AST(const LocationRange &location, ASTType type, const Fodder &open_fodder) - : location(location), type(type), openFodder(open_fodder) - { - } - virtual ~AST(void) + : location(location), type(type), openFodder(open_fodder) { } + virtual ~AST(void) {} }; -typedef std::vector ASTs; +typedef std::vector ASTs; /** Either an arg in a function apply, or a param in a closure / other function definition. * @@ -142,48 +139,52 @@ typedef std::vector ASTs; * used when no argument is bound to the param. */ struct ArgParam { - Fodder idFodder; // Empty if no id. + Fodder idFodder; // Empty if no id. const Identifier *id; // nullptr if there isn't one - Fodder eqFodder; // Empty if no id or no expr. - AST *expr; // nullptr if there wasn't one. - Fodder commaFodder; // Before the comma (if there is a comma). + Fodder eqFodder; // Empty if no id or no expr. + AST *expr; // nullptr if there wasn't one. + Fodder commaFodder; // Before the comma (if there is a comma). // Only has id - ArgParam (const Fodder &id_fodder, const Identifier *id, const Fodder &comma_fodder) - : idFodder(id_fodder), id(id), expr(nullptr), commaFodder(comma_fodder) - { } + ArgParam(const Fodder &id_fodder, const Identifier *id, const Fodder &comma_fodder) + : idFodder(id_fodder), id(id), expr(nullptr), commaFodder(comma_fodder) + { + } // Only has expr - ArgParam (AST *expr, const Fodder &comma_fodder) - : id(nullptr), expr(expr), commaFodder(comma_fodder) - { } + ArgParam(AST *expr, const Fodder &comma_fodder) + : id(nullptr), expr(expr), commaFodder(comma_fodder) + { + } // Has both id and expr - ArgParam (const Fodder &id_fodder, const Identifier *id, const Fodder &eq_fodder, - AST *expr, const Fodder &comma_fodder) - : idFodder(id_fodder), id(id), eqFodder(eq_fodder), expr(expr), commaFodder(comma_fodder) - { } + ArgParam(const Fodder &id_fodder, const Identifier *id, const Fodder &eq_fodder, AST *expr, + const Fodder &comma_fodder) + : idFodder(id_fodder), id(id), eqFodder(eq_fodder), expr(expr), commaFodder(comma_fodder) + { + } }; typedef std::vector ArgParams; /** Used in Object & Array Comprehensions. */ struct ComprehensionSpec { - enum Kind { - FOR, - IF - }; + enum Kind { FOR, IF }; Kind kind; Fodder openFodder; - Fodder varFodder; // {} when kind != SPEC_FOR. + Fodder varFodder; // {} when kind != SPEC_FOR. const Identifier *var; // Null when kind != SPEC_FOR. - Fodder inFodder; // {} when kind != SPEC_FOR. + Fodder inFodder; // {} when kind != SPEC_FOR. AST *expr; ComprehensionSpec(Kind kind, const Fodder &open_fodder, const Fodder &var_fodder, const Identifier *var, const Fodder &in_fodder, AST *expr) - : kind(kind), openFodder(open_fodder), varFodder(var_fodder), var(var), inFodder(in_fodder), - expr(expr) - { } + : kind(kind), + openFodder(open_fodder), + varFodder(var_fodder), + var(var), + inFodder(in_fodder), + expr(expr) + { + } }; - /** Represents function calls. */ struct Apply : public AST { AST *target; @@ -196,10 +197,16 @@ struct Apply : public AST { Apply(const LocationRange &lr, const Fodder &open_fodder, AST *target, const Fodder &fodder_l, const ArgParams &args, bool trailing_comma, const Fodder &fodder_r, const Fodder &tailstrict_fodder, bool tailstrict) - : AST(lr, AST_APPLY, open_fodder), target(target), fodderL(fodder_l), args(args), - trailingComma(trailing_comma), fodderR(fodder_r), tailstrictFodder(tailstrict_fodder), - tailstrict(tailstrict) - { } + : AST(lr, AST_APPLY, open_fodder), + target(target), + fodderL(fodder_l), + args(args), + trailingComma(trailing_comma), + fodderR(fodder_r), + tailstrictFodder(tailstrict_fodder), + tailstrict(tailstrict) + { + } }; /** Represents e { }. Desugared to e + { }. */ @@ -207,8 +214,9 @@ struct ApplyBrace : public AST { AST *left; AST *right; // This is always an object or object comprehension. ApplyBrace(const LocationRange &lr, const Fodder &open_fodder, AST *left, AST *right) - : AST(lr, AST_BINARY, open_fodder), left(left), right(right) - { } + : AST(lr, AST_BINARY, open_fodder), left(left), right(right) + { + } }; /** Represents array constructors [1, 2, 3]. */ @@ -216,9 +224,7 @@ struct Array : public AST { struct Element { AST *expr; Fodder commaFodder; - Element(AST *expr, const Fodder &comma_fodder) - : expr(expr), commaFodder(comma_fodder) - { } + Element(AST *expr, const Fodder &comma_fodder) : expr(expr), commaFodder(comma_fodder) {} }; typedef std::vector Elements; Elements elements; @@ -226,14 +232,17 @@ struct Array : public AST { Fodder closeFodder; Array(const LocationRange &lr, const Fodder &open_fodder, const Elements &elements, bool trailing_comma, const Fodder &close_fodder) - : AST(lr, AST_ARRAY, open_fodder), elements(elements), trailingComma(trailing_comma), - closeFodder(close_fodder) - { } + : AST(lr, AST_ARRAY, open_fodder), + elements(elements), + trailingComma(trailing_comma), + closeFodder(close_fodder) + { + } }; /** Represents array comprehensions (which are like Python list comprehensions). */ struct ArrayComprehension : public AST { - AST* body; + AST *body; Fodder commaFodder; bool trailingComma; std::vector specs; @@ -241,8 +250,12 @@ struct ArrayComprehension : public AST { ArrayComprehension(const LocationRange &lr, const Fodder &open_fodder, AST *body, const Fodder &comma_fodder, bool trailing_comma, const std::vector &specs, const Fodder &close_fodder) - : AST(lr, AST_ARRAY_COMPREHENSION, open_fodder), body(body), commaFodder(comma_fodder), - trailingComma(trailing_comma), specs(specs), closeFodder(close_fodder) + : AST(lr, AST_ARRAY_COMPREHENSION, open_fodder), + body(body), + commaFodder(comma_fodder), + trailingComma(trailing_comma), + specs(specs), + closeFodder(close_fodder) { assert(specs.size() > 0); } @@ -261,9 +274,14 @@ struct Assert : public AST { AST *rest; Assert(const LocationRange &lr, const Fodder &open_fodder, AST *cond, const Fodder &colon_fodder, AST *message, const Fodder &semicolon_fodder, AST *rest) - : AST(lr, AST_ASSERT, open_fodder), cond(cond), colonFodder(colon_fodder), - message(message), semicolonFodder(semicolon_fodder), rest(rest) - { } + : AST(lr, AST_ASSERT, open_fodder), + cond(cond), + colonFodder(colon_fodder), + message(message), + semicolonFodder(semicolon_fodder), + rest(rest) + { + } }; enum BinaryOp { @@ -294,7 +312,7 @@ enum BinaryOp { BOP_OR }; -static inline std::string bop_string (BinaryOp bop) +static inline std::string bop_string(BinaryOp bop) { switch (bop) { case BOP_MULT: return "*"; @@ -324,8 +342,8 @@ static inline std::string bop_string (BinaryOp bop) case BOP_OR: return "||"; default: - std::cerr << "INTERNAL ERROR: Unrecognised binary operator: " << bop << std::endl; - std::abort(); + std::cerr << "INTERNAL ERROR: Unrecognised binary operator: " << bop << std::endl; + std::abort(); } } @@ -337,8 +355,9 @@ struct Binary : public AST { AST *right; Binary(const LocationRange &lr, const Fodder &open_fodder, AST *left, const Fodder &op_fodder, BinaryOp op, AST *right) - : AST(lr, AST_BINARY, open_fodder), left(left), opFodder(op_fodder), op(op), right(right) - { } + : AST(lr, AST_BINARY, open_fodder), left(left), opFodder(op_fodder), op(op), right(right) + { + } }; /** Represents built-in functions. @@ -349,10 +368,10 @@ struct Binary : public AST { struct BuiltinFunction : public AST { std::string name; Identifiers params; - BuiltinFunction(const LocationRange &lr, const std::string &name, - const Identifiers ¶ms) - : AST(lr, AST_BUILTIN_FUNCTION, Fodder{}), name(name), params(params) - { } + BuiltinFunction(const LocationRange &lr, const std::string &name, const Identifiers ¶ms) + : AST(lr, AST_BUILTIN_FUNCTION, Fodder{}), name(name), params(params) + { + } }; /** Represents if then else. @@ -369,24 +388,28 @@ struct Conditional : public AST { Conditional(const LocationRange &lr, const Fodder &open_fodder, AST *cond, const Fodder &then_fodder, AST *branch_true, const Fodder &else_fodder, AST *branch_false) - : AST(lr, AST_CONDITIONAL, open_fodder), cond(cond), thenFodder(then_fodder), - branchTrue(branch_true), elseFodder(else_fodder), branchFalse(branch_false) - { } + : AST(lr, AST_CONDITIONAL, open_fodder), + cond(cond), + thenFodder(then_fodder), + branchTrue(branch_true), + elseFodder(else_fodder), + branchFalse(branch_false) + { + } }; /** Represents the $ keyword. */ struct Dollar : public AST { - Dollar(const LocationRange &lr, const Fodder &open_fodder) - : AST(lr, AST_DOLLAR, open_fodder) - { } + Dollar(const LocationRange &lr, const Fodder &open_fodder) : AST(lr, AST_DOLLAR, open_fodder) {} }; /** Represents error e. */ struct Error : public AST { AST *expr; Error(const LocationRange &lr, const Fodder &open_fodder, AST *expr) - : AST(lr, AST_ERROR, open_fodder), expr(expr) - { } + : AST(lr, AST_ERROR, open_fodder), expr(expr) + { + } }; /** Represents closures. */ @@ -399,10 +422,14 @@ struct Function : public AST { Function(const LocationRange &lr, const Fodder &open_fodder, const Fodder &paren_left_fodder, const ArgParams ¶ms, bool trailing_comma, const Fodder &paren_right_fodder, AST *body) - : AST(lr, AST_FUNCTION, open_fodder), parenLeftFodder(paren_left_fodder), - params(params), trailingComma(trailing_comma), parenRightFodder(paren_right_fodder), - body(body) - { } + : AST(lr, AST_FUNCTION, open_fodder), + parenLeftFodder(paren_left_fodder), + params(params), + trailingComma(trailing_comma), + parenRightFodder(paren_right_fodder), + body(body) + { + } }; struct LiteralString; @@ -411,16 +438,18 @@ struct LiteralString; struct Import : public AST { LiteralString *file; Import(const LocationRange &lr, const Fodder &open_fodder, LiteralString *file) - : AST(lr, AST_IMPORT, open_fodder), file(file) - { } + : AST(lr, AST_IMPORT, open_fodder), file(file) + { + } }; /** Represents importstr "file". */ struct Importstr : public AST { LiteralString *file; Importstr(const LocationRange &lr, const Fodder &open_fodder, LiteralString *file) - : AST(lr, AST_IMPORTSTR, open_fodder), file(file) - { } + : AST(lr, AST_IMPORTSTR, open_fodder), file(file) + { + } }; /** Represents both e[e] and the syntax sugar e.f. @@ -441,17 +470,34 @@ struct Index : public AST { // Use this constructor for e.f Index(const LocationRange &lr, const Fodder &open_fodder, AST *target, const Fodder &dot_fodder, const Fodder &id_fodder, const Identifier *id) - : AST(lr, AST_INDEX, open_fodder), target(target), dotFodder(dot_fodder), isSlice(false), - index(nullptr), end(nullptr), step(nullptr), idFodder(id_fodder), id(id) - { } + : AST(lr, AST_INDEX, open_fodder), + target(target), + dotFodder(dot_fodder), + isSlice(false), + index(nullptr), + end(nullptr), + step(nullptr), + idFodder(id_fodder), + id(id) + { + } // Use this constructor for e[x:y:z] with nullptr for index, end or step if not present. Index(const LocationRange &lr, const Fodder &open_fodder, AST *target, const Fodder &dot_fodder, bool is_slice, AST *index, const Fodder &end_colon_fodder, AST *end, const Fodder &step_colon_fodder, AST *step, const Fodder &id_fodder) - : AST(lr, AST_INDEX, open_fodder), target(target), dotFodder(dot_fodder), isSlice(is_slice), - index(index), endColonFodder(end_colon_fodder), end(end), - stepColonFodder(step_colon_fodder), step(step), idFodder(id_fodder), id(nullptr) - { } + : AST(lr, AST_INDEX, open_fodder), + target(target), + dotFodder(dot_fodder), + isSlice(is_slice), + index(index), + endColonFodder(end_colon_fodder), + end(end), + stepColonFodder(step_colon_fodder), + step(step), + idFodder(id_fodder), + id(nullptr) + { + } }; /** Represents local x = e; e. After desugaring, functionSugar is false. */ @@ -470,33 +516,43 @@ struct Local : public AST { Bind(const Fodder &var_fodder, const Identifier *var, const Fodder &op_fodder, AST *body, bool function_sugar, const Fodder &paren_left_fodder, const ArgParams ¶ms, bool trailing_comma, const Fodder &paren_right_fodder, const Fodder &close_fodder) - : varFodder(var_fodder), var(var), opFodder(op_fodder), body(body), - functionSugar(function_sugar), parenLeftFodder(paren_left_fodder), params(params), - trailingComma(trailing_comma), parenRightFodder(paren_right_fodder), - closeFodder(close_fodder) - { } + : varFodder(var_fodder), + var(var), + opFodder(op_fodder), + body(body), + functionSugar(function_sugar), + parenLeftFodder(paren_left_fodder), + params(params), + trailingComma(trailing_comma), + parenRightFodder(paren_right_fodder), + closeFodder(close_fodder) + { + } }; typedef std::vector Binds; Binds binds; AST *body; Local(const LocationRange &lr, const Fodder &open_fodder, const Binds &binds, AST *body) - : AST(lr, AST_LOCAL, open_fodder), binds(binds), body(body) - { } + : AST(lr, AST_LOCAL, open_fodder), binds(binds), body(body) + { + } }; /** Represents true and false. */ struct LiteralBoolean : public AST { bool value; LiteralBoolean(const LocationRange &lr, const Fodder &open_fodder, bool value) - : AST(lr, AST_LITERAL_BOOLEAN, open_fodder), value(value) - { } + : AST(lr, AST_LITERAL_BOOLEAN, open_fodder), value(value) + { + } }; /** Represents the null keyword. */ struct LiteralNull : public AST { LiteralNull(const LocationRange &lr, const Fodder &open_fodder) - : AST(lr, AST_LITERAL_NULL, open_fodder) - { } + : AST(lr, AST_LITERAL_NULL, open_fodder) + { + } }; /** Represents JSON numbers. */ @@ -504,9 +560,11 @@ struct LiteralNumber : public AST { double value; std::string originalString; LiteralNumber(const LocationRange &lr, const Fodder &open_fodder, const std::string &str) - : AST(lr, AST_LITERAL_NUMBER, open_fodder), value(strtod(str.c_str(), nullptr)), - originalString(str) - { } + : AST(lr, AST_LITERAL_NUMBER, open_fodder), + value(strtod(str.c_str(), nullptr)), + originalString(str) + { + } }; /** Represents JSON strings. */ @@ -514,17 +572,20 @@ struct LiteralString : public AST { UString value; enum TokenKind { SINGLE, DOUBLE, BLOCK, VERBATIM_SINGLE, VERBATIM_DOUBLE }; TokenKind tokenKind; - std::string blockIndent; // Only contains ' ' and '\t'. + std::string blockIndent; // Only contains ' ' and '\t'. std::string blockTermIndent; // Only contains ' ' and '\t'. LiteralString(const LocationRange &lr, const Fodder &open_fodder, const UString &value, TokenKind token_kind, const std::string &block_indent, const std::string &block_term_indent) - : AST(lr, AST_LITERAL_STRING, open_fodder), value(value), tokenKind(token_kind), - blockIndent(block_indent), blockTermIndent(block_term_indent) - { } + : AST(lr, AST_LITERAL_STRING, open_fodder), + value(value), + tokenKind(token_kind), + blockIndent(block_indent), + blockTermIndent(block_term_indent) + { + } }; - struct ObjectField { // Depending on the kind of Jsonnet field, the fields of this C++ class are used for storing // different parts of the AST. @@ -563,32 +624,44 @@ struct ObjectField { // NOTE TO SELF: sort out fodder1-4, then modify desugarer (maybe) parser and unparser. enum Hide { - HIDDEN, // f:: e + HIDDEN, // f:: e INHERIT, // f: e VISIBLE, // f::: e }; enum Kind kind; Fodder fodder1, fodder2, fodderL, fodderR; - enum Hide hide; // (ignore if kind != FIELD_something - bool superSugar; // +: (ignore if kind != FIELD_something) + enum Hide hide; // (ignore if kind != FIELD_something + bool superSugar; // +: (ignore if kind != FIELD_something) bool methodSugar; // f(x, y, z): ... (ignore if kind == ASSERT) - AST *expr1; // Not in scope of the object + AST *expr1; // Not in scope of the object const Identifier *id; - ArgParams params; // If methodSugar == true then holds the params. + ArgParams params; // If methodSugar == true then holds the params. bool trailingComma; // If methodSugar == true then remembers the trailing comma. - Fodder opFodder; // Before the : or = + Fodder opFodder; // Before the : or = AST *expr2, *expr3; // In scope of the object (can see self). Fodder commaFodder; // If this field is followed by a comma, this is its fodder. - ObjectField( - enum Kind kind, const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, - const Fodder &fodder_r, enum Hide hide, bool super_sugar, bool method_sugar, AST *expr1, - const Identifier *id, const ArgParams ¶ms, bool trailing_comma, const Fodder &op_fodder, - AST *expr2, AST *expr3, const Fodder &comma_fodder) - : kind(kind), fodder1(fodder1), fodder2(fodder2), fodderL(fodder_l), fodderR(fodder_r), - hide(hide), superSugar(super_sugar), methodSugar(method_sugar), expr1(expr1), id(id), - params(params), trailingComma(trailing_comma), opFodder(op_fodder), expr2(expr2), - expr3(expr3), commaFodder(comma_fodder) + ObjectField(enum Kind kind, const Fodder &fodder1, const Fodder &fodder2, + const Fodder &fodder_l, const Fodder &fodder_r, enum Hide hide, bool super_sugar, + bool method_sugar, AST *expr1, const Identifier *id, const ArgParams ¶ms, + bool trailing_comma, const Fodder &op_fodder, AST *expr2, AST *expr3, + const Fodder &comma_fodder) + : kind(kind), + fodder1(fodder1), + fodder2(fodder2), + fodderL(fodder_l), + fodderR(fodder_r), + hide(hide), + superSugar(super_sugar), + methodSugar(method_sugar), + expr1(expr1), + id(id), + params(params), + trailingComma(trailing_comma), + opFodder(op_fodder), + expr2(expr2), + expr3(expr3), + commaFodder(comma_fodder) { // Enforce what is written in comments above. assert(kind != ASSERT || (hide == VISIBLE && !superSugar && !methodSugar)); @@ -599,38 +672,90 @@ struct ObjectField { assert(kind == ASSERT || expr3 == nullptr); } // For when we don't know if it's a function or not. - static ObjectField Local( - const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, - const Fodder &fodder_r, bool method_sugar, const Identifier *id, const ArgParams ¶ms, - bool trailing_comma, const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) + static ObjectField Local(const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, + const Fodder &fodder_r, bool method_sugar, const Identifier *id, + const ArgParams ¶ms, bool trailing_comma, const Fodder &op_fodder, + AST *body, const Fodder &comma_fodder) { - return ObjectField( - LOCAL, fodder1, fodder2, fodder_l, fodder_r, VISIBLE, false, method_sugar, nullptr, id, - params, trailing_comma, op_fodder, body, nullptr, comma_fodder); + return ObjectField(LOCAL, + fodder1, + fodder2, + fodder_l, + fodder_r, + VISIBLE, + false, + method_sugar, + nullptr, + id, + params, + trailing_comma, + op_fodder, + body, + nullptr, + comma_fodder); } - static ObjectField Local( - const Fodder &fodder1, const Fodder &fodder2, const Identifier *id, - const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) + static ObjectField Local(const Fodder &fodder1, const Fodder &fodder2, const Identifier *id, + const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) { - return ObjectField( - LOCAL, fodder1, fodder2, Fodder{}, Fodder{}, VISIBLE, false, false, nullptr, id, - ArgParams{}, false, op_fodder, body, nullptr, comma_fodder); + return ObjectField(LOCAL, + fodder1, + fodder2, + Fodder{}, + Fodder{}, + VISIBLE, + false, + false, + nullptr, + id, + ArgParams{}, + false, + op_fodder, + body, + nullptr, + comma_fodder); } - static ObjectField LocalMethod( - const Fodder &fodder1, const Fodder &fodder2, const Fodder &fodder_l, - const Fodder &fodder_r, const Identifier *id, const ArgParams ¶ms, bool trailing_comma, - const Fodder &op_fodder, AST *body, const Fodder &comma_fodder) + static ObjectField LocalMethod(const Fodder &fodder1, const Fodder &fodder2, + const Fodder &fodder_l, const Fodder &fodder_r, + const Identifier *id, const ArgParams ¶ms, + bool trailing_comma, const Fodder &op_fodder, AST *body, + const Fodder &comma_fodder) { - return ObjectField( - LOCAL, fodder1, fodder2, fodder_l, fodder_r, VISIBLE, false, true, nullptr, id, params, - trailing_comma, op_fodder, body, nullptr, comma_fodder); + return ObjectField(LOCAL, + fodder1, + fodder2, + fodder_l, + fodder_r, + VISIBLE, + false, + true, + nullptr, + id, + params, + trailing_comma, + op_fodder, + body, + nullptr, + comma_fodder); } static ObjectField Assert(const Fodder &fodder1, AST *body, const Fodder &op_fodder, AST *msg, const Fodder &comma_fodder) { - return ObjectField( - ASSERT, fodder1, Fodder{}, Fodder{}, Fodder{}, VISIBLE, false, false, nullptr, nullptr, - ArgParams{}, false, op_fodder, body, msg, comma_fodder); + return ObjectField(ASSERT, + fodder1, + Fodder{}, + Fodder{}, + Fodder{}, + VISIBLE, + false, + false, + nullptr, + nullptr, + ArgParams{}, + false, + op_fodder, + body, + msg, + comma_fodder); } }; typedef std::vector ObjectFields; @@ -646,8 +771,10 @@ struct Object : public AST { Fodder closeFodder; Object(const LocationRange &lr, const Fodder &open_fodder, const ObjectFields &fields, bool trailing_comma, const Fodder &close_fodder) - : AST(lr, AST_OBJECT, open_fodder), fields(fields), trailingComma(trailing_comma), - closeFodder(close_fodder) + : AST(lr, AST_OBJECT, open_fodder), + fields(fields), + trailingComma(trailing_comma), + closeFodder(close_fodder) { assert(fields.size() > 0 || !trailing_comma); if (fields.size() > 0) @@ -665,18 +792,19 @@ struct DesugaredObject : public AST { AST *name; AST *body; Field(enum ObjectField::Hide hide, AST *name, AST *body) - : hide(hide), name(name), body(body) - { } + : hide(hide), name(name), body(body) + { + } }; typedef std::vector Fields; ASTs asserts; Fields fields; DesugaredObject(const LocationRange &lr, const ASTs &asserts, const Fields &fields) - : AST(lr, AST_DESUGARED_OBJECT, Fodder{}), asserts(asserts), fields(fields) - { } + : AST(lr, AST_DESUGARED_OBJECT, Fodder{}), asserts(asserts), fields(fields) + { + } }; - /** Represents object comprehension { [e]: e for x in e for.. if... }. */ struct ObjectComprehension : public AST { ObjectFields fields; @@ -687,9 +815,13 @@ struct ObjectComprehension : public AST { const ObjectFields &fields, bool trailing_comma, const std::vector &specs, const Fodder &close_fodder) - : AST(lr, AST_OBJECT_COMPREHENSION, open_fodder), fields(fields), - trailingComma(trailing_comma), specs(specs), closeFodder(close_fodder) - { } + : AST(lr, AST_OBJECT_COMPREHENSION, open_fodder), + fields(fields), + trailingComma(trailing_comma), + specs(specs), + closeFodder(close_fodder) + { + } }; /** Represents post-desugaring object comprehension { [e]: e for x in e }. */ @@ -698,11 +830,15 @@ struct ObjectComprehensionSimple : public AST { AST *value; const Identifier *id; AST *array; - ObjectComprehensionSimple(const LocationRange &lr, AST *field, AST *value, - const Identifier *id, AST *array) - : AST(lr, AST_OBJECT_COMPREHENSION_SIMPLE, Fodder{}), field(field), value(value), id(id), - array(array) - { } + ObjectComprehensionSimple(const LocationRange &lr, AST *field, AST *value, const Identifier *id, + AST *array) + : AST(lr, AST_OBJECT_COMPREHENSION_SIMPLE, Fodder{}), + field(field), + value(value), + id(id), + array(array) + { + } }; /** Represents (e), which is desugared. */ @@ -711,15 +847,14 @@ struct Parens : public AST { Fodder closeFodder; Parens(const LocationRange &lr, const Fodder &open_fodder, AST *expr, const Fodder &close_fodder) - : AST(lr, AST_PARENS, open_fodder), expr(expr), closeFodder(close_fodder) - { } + : AST(lr, AST_PARENS, open_fodder), expr(expr), closeFodder(close_fodder) + { + } }; /** Represents the self keyword. */ struct Self : public AST { - Self(const LocationRange &lr, const Fodder &open_fodder) - : AST(lr, AST_SELF, open_fodder) - { } + Self(const LocationRange &lr, const Fodder &open_fodder) : AST(lr, AST_SELF, open_fodder) {} }; /** Represents the super[e] and super.f constructs. @@ -734,9 +869,13 @@ struct SuperIndex : public AST { const Identifier *id; SuperIndex(const LocationRange &lr, const Fodder &open_fodder, const Fodder &dot_fodder, AST *index, const Fodder &id_fodder, const Identifier *id) - : AST(lr, AST_SUPER_INDEX, open_fodder), dotFodder(dot_fodder), index(index), - idFodder(id_fodder), id(id) - { } + : AST(lr, AST_SUPER_INDEX, open_fodder), + dotFodder(dot_fodder), + index(index), + idFodder(id_fodder), + id(id) + { + } }; /** Represents the e in super construct. @@ -745,21 +884,19 @@ struct InSuper : public AST { AST *element; Fodder inFodder; Fodder superFodder; - InSuper(const LocationRange &lr, const Fodder &open_fodder, - AST *element, const Fodder &in_fodder, const Fodder &super_fodder) - : AST(lr, AST_IN_SUPER, open_fodder), element(element), - inFodder(in_fodder), superFodder(super_fodder) - { } + InSuper(const LocationRange &lr, const Fodder &open_fodder, AST *element, + const Fodder &in_fodder, const Fodder &super_fodder) + : AST(lr, AST_IN_SUPER, open_fodder), + element(element), + inFodder(in_fodder), + superFodder(super_fodder) + { + } }; -enum UnaryOp { - UOP_NOT, - UOP_BITWISE_NOT, - UOP_PLUS, - UOP_MINUS -}; +enum UnaryOp { UOP_NOT, UOP_BITWISE_NOT, UOP_PLUS, UOP_MINUS }; -static inline std::string uop_string (UnaryOp uop) +static inline std::string uop_string(UnaryOp uop) { switch (uop) { case UOP_PLUS: return "+"; @@ -768,43 +905,48 @@ static inline std::string uop_string (UnaryOp uop) case UOP_NOT: return "!"; default: - std::cerr << "INTERNAL ERROR: Unrecognised unary operator: " << uop << std::endl; - std::abort(); + std::cerr << "INTERNAL ERROR: Unrecognised unary operator: " << uop << std::endl; + std::abort(); } } /** Represents unary operators. */ struct Unary : public AST { - UnaryOp op; + UnaryOp op; AST *expr; Unary(const LocationRange &lr, const Fodder &open_fodder, UnaryOp op, AST *expr) - : AST(lr, AST_UNARY, open_fodder), op(op), expr(expr) - { } + : AST(lr, AST_UNARY, open_fodder), op(op), expr(expr) + { + } }; /** Represents variables. */ struct Var : public AST { const Identifier *id; Var(const LocationRange &lr, const Fodder &open_fodder, const Identifier *id) - : AST(lr, AST_VAR, open_fodder), id(id) - { } + : AST(lr, AST_VAR, open_fodder), id(id) + { + } }; - /** Allocates ASTs on demand, frees them in its destructor. */ class Allocator { - std::map internedIdentifiers; + std::map internedIdentifiers; ASTs allocated; - public: - template T* make(Args&&... args) + + public: + template + T *make(Args &&... args) { auto r = new T(std::forward(args)...); allocated.push_back(r); return r; } - template T *clone(T * ast) { + template + T *clone(T *ast) + { auto r = new T(*ast); allocated.push_back(r); return r; @@ -839,10 +981,10 @@ class Allocator { namespace { // Precedences used by various compilation units are defined here. -const int APPLY_PRECEDENCE = 2; // Function calls and indexing. -const int UNARY_PRECEDENCE = 4; // Logical and bitwise negation, unary + - -const int BEFORE_ELSE_PRECEDENCE = 15; // True branch of an if. -const int MAX_PRECEDENCE = 16; // Local, If, Import, Function, Error +const int APPLY_PRECEDENCE = 2; // Function calls and indexing. +const int UNARY_PRECEDENCE = 4; // Logical and bitwise negation, unary + - +const int BEFORE_ELSE_PRECEDENCE = 15; // True branch of an if. +const int MAX_PRECEDENCE = 16; // Local, If, Import, Function, Error /** These are the binary operator precedences, unary precedence is given by * UNARY_PRECEDENCE. diff --git a/core/desugarer.cpp b/core/desugarer.cpp index 26b766c08..771d108a6 100644 --- a/core/desugarer.cpp +++ b/core/desugarer.cpp @@ -64,15 +64,15 @@ BuiltinDecl jsonnet_builtin_decl(unsigned long builtin) case 25: return {U"native", {U"name"}}; case 26: return {U"md5", {U"str"}}; default: - std::cerr << "INTERNAL ERROR: Unrecognized builtin function: " << builtin << std::endl; - std::abort(); + std::cerr << "INTERNAL ERROR: Unrecognized builtin function: " << builtin << std::endl; + std::abort(); } // Quiet, compiler. return BuiltinDecl(); } static constexpr char STD_CODE[] = { - #include "std.jsonnet.h" +#include "std.jsonnet.h" }; /** Desugar Jsonnet expressions to reduce the number of constructs the rest of the implementation @@ -83,35 +83,48 @@ static constexpr char STD_CODE[] = { * variables used in user code. */ class Desugarer { - Allocator *alloc; - template T* make(Args&&... args) + template + T *make(Args &&... args) { return alloc->make(std::forward(args)...); } AST *clone(AST *ast) - { return clone_ast(*alloc, ast); } + { + return clone_ast(*alloc, ast); + } const Identifier *id(const UString &s) - { return alloc->makeIdentifier(s); } + { + return alloc->makeIdentifier(s); + } LiteralString *str(const UString &s) - { return make(E, EF, s, LiteralString::DOUBLE, "", ""); } + { + return make(E, EF, s, LiteralString::DOUBLE, "", ""); + } LiteralString *str(const LocationRange &loc, const UString &s) - { return make(loc, EF, s, LiteralString::DOUBLE, "", ""); } + { + return make(loc, EF, s, LiteralString::DOUBLE, "", ""); + } LiteralNull *null(void) - { return make(E, EF); } + { + return make(E, EF); + } Var *var(const Identifier *ident) - { return make(E, EF, ident); } + { + return make(E, EF, ident); + } Var *std(void) - { return var(id(U"std")); } - + { + return var(id(U"std")); + } Local::Bind bind(const Identifier *id, AST *body) { @@ -125,8 +138,8 @@ class Desugarer { Array *singleton(AST *body) { - return make(body->location, EF, Array::Elements{Array::Element(body, EF)}, - false, EF); + return make( + body->location, EF, Array::Elements{Array::Element(body, EF)}, false, EF); } Apply *stdFunc(const UString &name, AST *v) @@ -189,10 +202,8 @@ class Desugarer { return error(str(loc, msg)); } - public: - Desugarer(Allocator *alloc) - : alloc(alloc) - { } + public: + Desugarer(Allocator *alloc) : alloc(alloc) {} void desugarParams(ArgParams ¶ms, unsigned obj_level) { @@ -212,15 +223,18 @@ class Desugarer { { // Desugar children for (auto &field : fields) { - if (field.expr1 != nullptr) desugar(field.expr1, obj_level); + if (field.expr1 != nullptr) + desugar(field.expr1, obj_level); desugar(field.expr2, obj_level + 1); - if (field.expr3 != nullptr) desugar(field.expr3, obj_level + 1); + if (field.expr3 != nullptr) + desugar(field.expr3, obj_level + 1); desugarParams(field.params, obj_level + 1); } // Simplify asserts for (auto &field : fields) { - if (field.kind != ObjectField::ASSERT) continue; + if (field.kind != ObjectField::ASSERT) + continue; AST *msg = field.expr3; field.expr3 = nullptr; if (msg == nullptr) { @@ -229,37 +243,42 @@ class Desugarer { } // if expr2 then true else error msg - field.expr2 = make( - field.expr2->location, - EF, - field.expr2, - EF, - make(E, EF, true), - EF, - error(msg)); + field.expr2 = make(field.expr2->location, + EF, + field.expr2, + EF, + make(E, EF, true), + EF, + error(msg)); } // Remove methods for (auto &field : fields) { - if (!field.methodSugar) continue; - field.expr2 = make( - field.expr2->location, EF, field.fodderL, field.params, field.trailingComma, - field.fodderR, field.expr2); + if (!field.methodSugar) + continue; + field.expr2 = make(field.expr2->location, + EF, + field.fodderL, + field.params, + field.trailingComma, + field.fodderR, + field.expr2); field.methodSugar = false; field.params.clear(); } - // Remove object-level locals auto copy = fields; fields.clear(); Local::Binds binds; for (auto &local : copy) { - if (local.kind != ObjectField::LOCAL) continue; + if (local.kind != ObjectField::LOCAL) + continue; binds.push_back(bind(local.id, local.expr2)); } for (auto &field : copy) { - if (field.kind == ObjectField::LOCAL) continue; + if (field.kind == ObjectField::LOCAL) + continue; if (!binds.empty()) field.expr2 = make(field.expr2->location, EF, binds, field.expr2); fields.push_back(field); @@ -269,26 +288,26 @@ class Desugarer { for (auto &field : fields) { switch (field.kind) { case ObjectField::ASSERT: - // Nothing to do. - break; + // Nothing to do. + break; case ObjectField::FIELD_ID: - field.expr1 = str(field.id->name); - field.kind = ObjectField::FIELD_EXPR; - break; + field.expr1 = str(field.id->name); + field.kind = ObjectField::FIELD_EXPR; + break; case ObjectField::FIELD_EXPR: - // Nothing to do. - break; + // Nothing to do. + break; case ObjectField::FIELD_STR: - // Just set the flag. - field.kind = ObjectField::FIELD_EXPR; - break; + // Just set the flag. + field.kind = ObjectField::FIELD_EXPR; + break; case ObjectField::LOCAL: - std::cerr << "Locals should be removed by now." << std::endl; - abort(); + std::cerr << "Locals should be removed by now." << std::endl; + abort(); } } @@ -301,21 +320,25 @@ class Desugarer { SuperVars &superVars; unsigned &counter; const Identifier *newSelf; - public: + + public: SubstituteSelfSuper(Desugarer *desugarer, SuperVars &super_vars, unsigned &counter) - : CompilerPass(*desugarer->alloc), desugarer(desugarer), superVars(super_vars), - counter(counter), newSelf(nullptr) + : CompilerPass(*desugarer->alloc), + desugarer(desugarer), + superVars(super_vars), + counter(counter), + newSelf(nullptr) { } void visitExpr(AST *&expr) { - if (dynamic_cast(expr)) { + if (dynamic_cast(expr)) { if (newSelf == nullptr) { newSelf = desugarer->id(U"$outer_self"); superVars.emplace_back(newSelf, nullptr); } expr = alloc.make(expr->location, expr->openFodder, newSelf); - } else if (auto *super_index = dynamic_cast(expr)) { + } else if (auto *super_index = dynamic_cast(expr)) { UStringStream ss; ss << U"$outer_super_index" << (counter++); const Identifier *super_var = desugarer->id(ss.str()); @@ -325,7 +348,7 @@ class Desugarer { // Re-use super_index since we're replacing it here. superVars.emplace_back(super_var, super_index); expr = alloc.make(expr->location, expr->openFodder, super_var); - } else if (auto *in_super = dynamic_cast(expr)) { + } else if (auto *in_super = dynamic_cast(expr)) { UStringStream ss; ss << U"$outer_in_super" << (counter++); const Identifier *in_super_var = desugarer->id(ss.str()); @@ -342,7 +365,8 @@ class Desugarer { // Remove +: for (auto &field : fields) { - if (!field.superSugar) continue; + if (!field.superSugar) + continue; // We have to bind self/super from expr1 outside the class, as we copy the expression // into the field body. // Clone it so that we maintain the AST as a tree. @@ -354,13 +378,12 @@ class Desugarer { EF, make(ast->location, EF, index, EF, EF), EF, - make( - ast->location, - EF, - make(ast->location, EF, EF, clone(index), EF, nullptr), - EF, - BOP_PLUS, - field.expr2), + make(ast->location, + EF, + make(ast->location, EF, EF, clone(index), EF, nullptr), + EF, + BOP_PLUS, + field.expr2), EF, clone(field.expr2)); field.superSugar = false; @@ -371,22 +394,22 @@ class Desugarer { void desugar(AST *&ast_, unsigned obj_level) { - if (auto *ast = dynamic_cast(ast_)) { + if (auto *ast = dynamic_cast(ast_)) { desugar(ast->target, obj_level); for (ArgParam &arg : ast->args) desugar(arg.expr, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->left, obj_level); desugar(ast->right, obj_level); - ast_ = make(ast->location, ast->openFodder, - ast->left, EF, BOP_PLUS, ast->right); + ast_ = + make(ast->location, ast->openFodder, ast->left, EF, BOP_PLUS, ast->right); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { for (auto &el : ast->elements) desugar(el.expr, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { for (ComprehensionSpec &spec : ast->specs) desugar(spec.expr, obj_level); desugar(ast->body, obj_level + 1); @@ -396,14 +419,14 @@ class Desugarer { AST *one = make(E, EF, "1.0"); auto *_r = id(U"$r"); auto *_l = id(U"$l"); - std::vector _i(n); - for (int i = 0; i < n ; ++i) { + std::vector _i(n); + for (int i = 0; i < n; ++i) { UStringStream ss; ss << U"$i_" << i; _i[i] = id(ss.str()); } - std::vector _aux(n); - for (int i = 0; i < n ; ++i) { + std::vector _aux(n); + for (int i = 0; i < n; ++i) { UStringStream ss; ss << U"$aux_" << i; _aux[i] = id(ss.str()); @@ -421,16 +444,14 @@ class Desugarer { EF, var(_aux[last_for]), EF, - ArgParams { - { make(E, EF, var(_i[last_for]), EF, BOP_PLUS, one), EF}, - { make(E, EF, var(_r), EF, BOP_PLUS, singleton(ast->body)), EF} - }, + ArgParams{{make(E, EF, var(_i[last_for]), EF, BOP_PLUS, one), EF}, + {make(E, EF, var(_r), EF, BOP_PLUS, singleton(ast->body)), EF}}, false, // trailingComma EF, EF, true // tailstrict ); - for (int i = n - 1; i >= 0 ; --i) { + for (int i = n - 1; i >= 0; --i) { const ComprehensionSpec &spec = ast->specs[i]; AST *out; if (i > 0) { @@ -444,11 +465,15 @@ class Desugarer { EF, var(_aux[prev_for]), EF, - ArgParams { - { make(E, EF, var(_i[prev_for]), EF, BOP_PLUS, one), EF, }, - { var(_r), EF, } - }, - false, // trailingComma + ArgParams{{ + make(E, EF, var(_i[prev_for]), EF, BOP_PLUS, one), + EF, + }, + { + var(_r), + EF, + }}, + false, // trailingComma EF, EF, true // tailstrict @@ -464,14 +489,13 @@ class Desugarer { else [[[...out...]]] */ - in = make( - ast->location, - EF, - spec.expr, - EF, - in, // True branch. - EF, - out); // False branch. + in = make(ast->location, + EF, + spec.expr, + EF, + in, // True branch. + EF, + out); // False branch. } break; case ComprehensionSpec::FOR: { /* @@ -490,34 +514,43 @@ class Desugarer { in = make( ast->location, EF, - Local::Binds { + Local::Binds{ bind(_l, spec.expr), // Need to check expr is an array - bind(_aux[i], make( - ast->location, - EF, - EF, - ArgParams{{EF, _i[i], EF}, {EF, _r, EF}}, - false, // trailingComma - EF, - make( - ast->location, - EF, - make( - E, EF, var(_i[i]), EF, BOP_GREATER_EQ, length(var(_l))), - EF, - out, - EF, - make( - ast->location, - EF, - singleBind( - spec.var, - make(E, EF, var(_l), EF, false, var(_i[i]), - EF, nullptr, EF, nullptr, EF) - ), - in) - ) - ))}, + bind(_aux[i], + make( + ast->location, + EF, + EF, + ArgParams{{EF, _i[i], EF}, {EF, _r, EF}}, + false, // trailingComma + EF, + make(ast->location, + EF, + make(E, + EF, + var(_i[i]), + EF, + BOP_GREATER_EQ, + length(var(_l))), + EF, + out, + EF, + make( + ast->location, + EF, + singleBind(spec.var, + make(E, + EF, + var(_l), + EF, + false, + var(_i[i]), + EF, + nullptr, + EF, + nullptr, + EF)), + in))))}, make( ast->location, EF, @@ -528,15 +561,13 @@ class Desugarer { EF, var(_aux[i]), EF, - ArgParams { - {zero, EF}, - { - i == 0 - ? make(E, EF, Array::Elements{}, false, EF) - : static_cast(var(_r)), - EF, - } - }, + ArgParams{{zero, EF}, + { + i == 0 ? make( + E, EF, Array::Elements{}, false, EF) + : static_cast(var(_r)), + EF, + }}, false, // trailingComma EF, EF, @@ -550,7 +581,7 @@ class Desugarer { ast_ = in; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->cond, obj_level); if (ast->message == nullptr) { ast->message = str(U"Assertion failed."); @@ -560,10 +591,10 @@ class Desugarer { // if cond then rest else error msg AST *branch_false = make(ast->location, EF, ast->message); - ast_ = make(ast->location, ast->openFodder, - ast->cond, EF, ast->rest, EF, branch_false); + ast_ = make( + ast->location, ast->openFodder, ast->cond, EF, ast->rest, EF, branch_false); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->left, obj_level); desugar(ast->right, obj_level); @@ -571,59 +602,57 @@ class Desugarer { switch (ast->op) { case BOP_PERCENT: { - AST *f_mod = make(E, EF, std(), EF, false, str(U"mod"), EF, - nullptr, EF, nullptr, EF); + AST *f_mod = make( + E, EF, std(), EF, false, str(U"mod"), EF, nullptr, EF, nullptr, EF); ArgParams args = {{ast->left, EF}, {ast->right, EF}}; - ast_ = make(ast->location, ast->openFodder, f_mod, EF, args, - false, EF, EF, false); + ast_ = make( + ast->location, ast->openFodder, f_mod, EF, args, false, EF, EF, false); } break; - case BOP_MANIFEST_UNEQUAL: - invert = true; + case BOP_MANIFEST_UNEQUAL: invert = true; case BOP_MANIFEST_EQUAL: { ast_ = equals(ast->location, ast->left, ast->right); if (invert) ast_ = make(ast->location, ast->openFodder, UOP_NOT, ast_); - } - break; + } break; default:; - // Otherwise don't change it. + // Otherwise don't change it. } - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->cond, obj_level); desugar(ast->branchTrue, obj_level); if (ast->branchFalse == nullptr) ast->branchFalse = null(); desugar(ast->branchFalse, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (obj_level == 0) { throw StaticError(ast->location, "No top-level object found."); } ast_ = var(id(U"$")); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->expr, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->body, obj_level); desugarParams(ast->params, obj_level); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->element, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->target, obj_level); if (ast->isSlice) { if (ast->index == nullptr) @@ -664,29 +693,33 @@ class Desugarer { desugar(ast->index, obj_level); } - } else if (auto *ast = dynamic_cast(ast_)) { - for (auto &bind: ast->binds) + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto &bind : ast->binds) desugar(bind.body, obj_level); desugar(ast->body, obj_level); - for (auto &bind: ast->binds) { + for (auto &bind : ast->binds) { if (bind.functionSugar) { desugarParams(bind.params, obj_level); - bind.body = make( - ast->location, ast->openFodder, bind.parenLeftFodder, bind.params, false, - bind.parenRightFodder, bind.body); + bind.body = make(ast->location, + ast->openFodder, + bind.parenLeftFodder, + bind.params, + false, + bind.parenRightFodder, + bind.body); bind.functionSugar = false; bind.params.clear(); } } - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if ((ast->tokenKind != LiteralString::BLOCK) && (ast->tokenKind != LiteralString::VERBATIM_DOUBLE) && (ast->tokenKind != LiteralString::VERBATIM_SINGLE)) { @@ -695,10 +728,10 @@ class Desugarer { ast->tokenKind = LiteralString::DOUBLE; ast->blockIndent.clear(); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { for (auto &field : ast->fields) { desugar(field.name, obj_level); desugar(field.body, obj_level + 1); @@ -707,7 +740,7 @@ class Desugarer { desugar(assert, obj_level + 1); } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { // Hidden variable to allow outer/top binding. if (obj_level == 0) { const Identifier *hidden_var = id(U"$"); @@ -725,8 +758,8 @@ class Desugarer { } else if (field.kind == ObjectField::FIELD_EXPR) { new_fields.emplace_back(field.hide, field.expr1, field.expr2); } else { - std::cerr << "INTERNAL ERROR: field should have been desugared: " - << field.kind << std::endl; + std::cerr << "INTERNAL ERROR: field should have been desugared: " << field.kind + << std::endl; } } ast_ = make(ast->location, new_asserts, new_fields); @@ -744,7 +777,7 @@ class Desugarer { ast_ = make(ast->location, EF, binds, ast_); } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { // Hidden variable to allow outer/top binding. if (obj_level == 0) { const Identifier *hidden_var = id(U"$"); @@ -769,53 +802,55 @@ class Desugarer { AST *zero = make(E, EF, "0.0"); int counter = 1; Local::Binds binds; - Array::Elements arr_e {Array::Element(field, EF)}; + Array::Elements arr_e{Array::Element(field, EF)}; for (ComprehensionSpec &spec : ast->specs) { if (spec.kind == ComprehensionSpec::FOR) { std::stringstream num; num << counter++; - binds.push_back(bind( - spec.var, - make(E, EF, var(_arr), EF, false, - make(E, EF, num.str()), EF, nullptr, EF, nullptr, - EF))); + binds.push_back(bind(spec.var, + make(E, + EF, + var(_arr), + EF, + false, + make(E, EF, num.str()), + EF, + nullptr, + EF, + nullptr, + EF))); arr_e.emplace_back(var(spec.var), EF); } } - AST *arr = make( - ast->location, - EF, - make(ast->location, EF, arr_e, false, EF), - EF, - false, - ast->specs, - EF); + AST *arr = make(ast->location, + EF, + make(ast->location, EF, arr_e, false, EF), + EF, + false, + ast->specs, + EF); desugar(arr, obj_level); ast_ = make( ast->location, make(E, EF, var(_arr), EF, false, zero, EF, nullptr, EF, nullptr, EF), - make( - ast->location, - EF, - binds, - value), + make(ast->location, EF, binds, value), _arr, arr); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->field, obj_level); desugar(ast->value, obj_level + 1); desugar(ast->array, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { // Strip parens. desugar(ast->expr, obj_level); ast_ = ast->expr; - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto * ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (ast->id != nullptr) { assert(ast->index == nullptr); ast->index = str(ast->id->name); @@ -823,16 +858,15 @@ class Desugarer { } desugar(ast->index, obj_level); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { desugar(ast->expr, obj_level); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); - } } @@ -844,7 +878,7 @@ class Desugarer { Tokens tokens = jsonnet_lex("std.jsonnet", STD_CODE); AST *std_ast = jsonnet_parse(alloc, tokens); desugar(std_ast, 0); - auto *std_obj = dynamic_cast(std_ast); + auto *std_obj = dynamic_cast(std_ast); if (std_obj == nullptr) { std::cerr << "INTERNAL ERROR: std.jsonnet not an object." << std::endl; std::abort(); @@ -852,20 +886,17 @@ class Desugarer { // Bind 'std' builtins that are implemented natively. DesugaredObject::Fields &fields = std_obj->fields; - for (unsigned long c=0 ; c <= max_builtin ; ++c) { + for (unsigned long c = 0; c <= max_builtin; ++c) { const auto &decl = jsonnet_builtin_decl(c); Identifiers params; for (const auto &p : decl.params) params.push_back(id(p)); - fields.emplace_back( - ObjectField::HIDDEN, - str(decl.name), - make(E, encode_utf8(decl.name), params)); + fields.emplace_back(ObjectField::HIDDEN, + str(decl.name), + make(E, encode_utf8(decl.name), params)); } fields.emplace_back( - ObjectField::HIDDEN, - str(U"thisFile"), - str(decode_utf8(ast->location.file))); + ObjectField::HIDDEN, str(U"thisFile"), str(decode_utf8(ast->location.file))); std::vector empty; auto line_end_blank = Fodder{{FodderElement::LINE_END, 1, 0, empty}}; @@ -879,8 +910,7 @@ class Desugarer { if (tlas != nullptr) { LocationRange tla_loc("Top-level function"); ArgParams args; - for (const auto &pair : *tlas) - { + for (const auto &pair : *tlas) { AST *expr; if (pair.second.isCode) { // Now, implement the std library by wrapping in a local construct. @@ -894,36 +924,30 @@ class Desugarer { args.emplace_back(EF, id(decode_utf8(pair.first)), EF, expr, EF); } const Identifier *body = id(U"top_level"); - ast = make( - ast->location, - line_end_blank, - singleBind(body, ast), - make( - E, - line_end, - primitiveEquals(E, type(var(body)), str(U"function")), - EF, - make( - tla_loc, - EF, - make(E, line_end, body), - EF, - args, - false, // trailing comma - EF, - EF, - false // tailstrict - ), - line_end, - make(E, line_end, body))); + ast = + make(ast->location, + line_end_blank, + singleBind(body, ast), + make(E, + line_end, + primitiveEquals(E, type(var(body)), str(U"function")), + EF, + make(tla_loc, + EF, + make(E, line_end, body), + EF, + args, + false, // trailing comma + EF, + EF, + false // tailstrict + ), + line_end, + make(E, line_end, body))); } // local std = (std.jsonnet stuff); ast - ast = make( - ast->location, - EF, - singleBind(id(U"std"), std_obj), - ast); + ast = make(ast->location, EF, singleBind(id(U"std"), std_obj), ast); } }; diff --git a/core/formatter.cpp b/core/formatter.cpp index ab760cb8a..9f6fa1f2d 100644 --- a/core/formatter.cpp +++ b/core/formatter.cpp @@ -32,21 +32,21 @@ static std::string unparse_id(const Identifier *id) /** If left recursive, return the left hand side, else return nullptr. */ static AST *left_recursive(AST *ast_) { - if (auto *ast = dynamic_cast(ast_)) + if (auto *ast = dynamic_cast(ast_)) return ast->target; - if (auto *ast = dynamic_cast(ast_)) + if (auto *ast = dynamic_cast(ast_)) return ast->left; - if (auto *ast = dynamic_cast(ast_)) + if (auto *ast = dynamic_cast(ast_)) return ast->left; - if (auto *ast = dynamic_cast(ast_)) + if (auto *ast = dynamic_cast(ast_)) return ast->target; - if (auto *ast = dynamic_cast(ast_)) + if (auto *ast = dynamic_cast(ast_)) return ast->element; return nullptr; } static const AST *left_recursive(const AST *ast_) { - return left_recursive(const_cast(ast_)); + return left_recursive(const_cast(ast_)); } /** Pretty-print fodder. @@ -61,21 +61,21 @@ void fodder_fill(std::ostream &o, const Fodder &fodder, bool space_before, bool for (const auto &fod : fodder) { switch (fod.kind) { case FodderElement::LINE_END: - if (fod.comment.size() > 0) - o << " " << fod.comment[0]; - o << '\n'; - o << std::string(fod.blanks, '\n'); - o << std::string(fod.indent, ' '); - last_indent = fod.indent; - space_before = false; - break; + if (fod.comment.size() > 0) + o << " " << fod.comment[0]; + o << '\n'; + o << std::string(fod.blanks, '\n'); + o << std::string(fod.indent, ' '); + last_indent = fod.indent; + space_before = false; + break; case FodderElement::INTERSTITIAL: - if (space_before) - o << ' '; - o << fod.comment[0]; - space_before = true; - break; + if (space_before) + o << ' '; + o << fod.comment[0]; + space_before = true; + break; case FodderElement::PARAGRAPH: { bool first = true; @@ -109,16 +109,16 @@ static void fodder_count(unsigned &column, const Fodder &fodder, bool space_befo switch (fod.kind) { case FodderElement::PARAGRAPH: case FodderElement::LINE_END: - column = fod.indent; - space_before = false; - break; + column = fod.indent; + space_before = false; + break; case FodderElement::INTERSTITIAL: - if (space_before) - column++; - column += fod.comment[0].length(); - space_before = true; - break; + if (space_before) + column++; + column += fod.comment[0].length(); + space_before = true; + break; } } if (separate_token && space_before) @@ -126,16 +126,13 @@ static void fodder_count(unsigned &column, const Fodder &fodder, bool space_befo } class Unparser { - public: - - private: + public: + private: std::ostream &o; FmtOpts opts; - public: - Unparser(std::ostream &o, const FmtOpts &opts) - : o(o), opts(opts) - { } + public: + Unparser(std::ostream &o, const FmtOpts &opts) : o(o), opts(opts) {} void unparseSpecs(const std::vector &specs) { @@ -143,17 +140,17 @@ class Unparser { fill(spec.openFodder, true, true); switch (spec.kind) { case ComprehensionSpec::FOR: - o << "for"; - fill(spec.varFodder, true, true); - o << unparse_id(spec.var); - fill(spec.inFodder, true, true); - o << "in"; - unparse(spec.expr, true); - break; + o << "for"; + fill(spec.varFodder, true, true); + o << unparse_id(spec.var); + fill(spec.inFodder, true, true); + o << "in"; + unparse(spec.expr, true); + break; case ComprehensionSpec::IF: - o << "if"; - unparse(spec.expr, true); - break; + o << "if"; + unparse(spec.expr, true); + break; } } } @@ -170,7 +167,8 @@ class Unparser { o << "("; bool first = true; for (const auto ¶m : params) { - if (!first) o << ","; + if (!first) + o << ","; fill(param.idFodder, !first, true); o << unparse_id(param.id); if (param.expr != nullptr) { @@ -199,8 +197,8 @@ class Unparser { { bool first = true; for (const auto &field : fields) { - - if (!first) o << ','; + if (!first) + o << ','; switch (field.kind) { case ObjectField::LOCAL: { @@ -217,8 +215,6 @@ class Unparser { case ObjectField::FIELD_ID: case ObjectField::FIELD_STR: case ObjectField::FIELD_EXPR: { - - if (field.kind == ObjectField::FIELD_ID) { fill(field.fodder1, !first || space_before, true); o << unparse_id(field.id); @@ -237,7 +233,8 @@ class Unparser { fill(field.opFodder, false, false); - if (field.superSugar) o << "+"; + if (field.superSugar) + o << "+"; switch (field.hide) { case ObjectField::INHERIT: o << ":"; break; case ObjectField::HIDDEN: o << "::"; break; @@ -277,13 +274,14 @@ class Unparser { fill(ast_->openFodder, space_before, separate_token); - if (auto *ast = dynamic_cast(ast_)) { + if (auto *ast = dynamic_cast(ast_)) { unparse(ast->target, space_before); fill(ast->fodderL, false, false); o << "("; bool first = true; for (const auto &arg : ast->args) { - if (!first) o << ','; + if (!first) + o << ','; bool space = !first; if (arg.id != nullptr) { fill(arg.idFodder, space, true); @@ -295,7 +293,8 @@ class Unparser { fill(arg.commaFodder, false, false); first = false; } - if (ast->trailingComma) o << ","; + if (ast->trailingComma) + o << ","; fill(ast->fodderR, false, false); o << ")"; if (ast->tailstrict) { @@ -303,33 +302,36 @@ class Unparser { o << "tailstrict"; } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { unparse(ast->left, space_before); unparse(ast->right, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "["; bool first = true; for (const auto &element : ast->elements) { - if (!first) o << ','; + if (!first) + o << ','; unparse(element.expr, !first || opts.padArrays); fill(element.commaFodder, false, false); first = false; } - if (ast->trailingComma) o << ","; + if (ast->trailingComma) + o << ","; fill(ast->closeFodder, ast->elements.size() > 0, opts.padArrays); o << "]"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "["; unparse(ast->body, opts.padArrays); fill(ast->commaFodder, false, false); - if (ast->trailingComma) o << ","; + if (ast->trailingComma) + o << ","; unparseSpecs(ast->specs); fill(ast->closeFodder, true, opts.padArrays); o << "]"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "assert"; unparse(ast->cond, true); if (ast->message != nullptr) { @@ -341,17 +343,17 @@ class Unparser { o << ";"; unparse(ast->rest, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { unparse(ast->left, space_before); fill(ast->opFodder, true, true); o << bop_string(ast->op); // The - 1 is for left associativity. unparse(ast->right, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "/* builtin " << ast->name << " */ null"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "if"; unparse(ast->cond, true); fill(ast->thenFodder, true, true); @@ -365,35 +367,35 @@ class Unparser { unparse(ast->branchTrue, true); } - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { o << "$"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "error"; unparse(ast->expr, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "function"; - unparseParams(ast->parenLeftFodder, ast->params, ast->trailingComma, - ast->parenRightFodder); + unparseParams( + ast->parenLeftFodder, ast->params, ast->trailingComma, ast->parenRightFodder); unparse(ast->body, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "import"; unparse(ast->file, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "importstr"; unparse(ast->file, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { unparse(ast->element, true); fill(ast->inFodder, true, true); o << "in"; fill(ast->superFodder, true, true); o << "super"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { unparse(ast->target, space_before); fill(ast->dotFodder, false, false); if (ast->id != nullptr) { @@ -425,7 +427,7 @@ class Unparser { o << "]"; } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "local"; assert(ast->binds.size() > 0); bool first = true; @@ -436,7 +438,9 @@ class Unparser { fill(bind.varFodder, true, true); o << unparse_id(bind.var); if (bind.functionSugar) { - unparseParams(bind.parenLeftFodder, bind.params, bind.trailingComma, + unparseParams(bind.parenLeftFodder, + bind.params, + bind.trailingComma, bind.parenRightFodder); } fill(bind.opFodder, true, true); @@ -447,13 +451,13 @@ class Unparser { o << ";"; unparse(ast->body, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << (ast->value ? "true" : "false"); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << ast->originalString; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (ast->tokenKind == LiteralString::DOUBLE) { o << "\""; o << encode_utf8(ast->value); @@ -466,7 +470,7 @@ class Unparser { o << "|||\n"; if (ast->value.c_str()[0] != U'\n') o << ast->blockIndent; - for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + for (const char32_t *cp = ast->value.c_str(); *cp != U'\0'; ++cp) { std::string utf8; encode_utf8(*cp, utf8); o << utf8; @@ -477,7 +481,7 @@ class Unparser { o << ast->blockTermIndent << "|||"; } else if (ast->tokenKind == LiteralString::VERBATIM_DOUBLE) { o << "@\""; - for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + for (const char32_t *cp = ast->value.c_str(); *cp != U'\0'; ++cp) { if (*cp == U'"') { o << "\"\""; } else { @@ -489,7 +493,7 @@ class Unparser { o << "\""; } else if (ast->tokenKind == LiteralString::VERBATIM_SINGLE) { o << "@'"; - for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + for (const char32_t *cp = ast->value.c_str(); *cp != U'\0'; ++cp) { if (*cp == U'\'') { o << "''"; } else { @@ -501,17 +505,18 @@ class Unparser { o << "'"; } - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { o << "null"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "{"; unparseFields(ast->fields, opts.padObjects); - if (ast->trailingComma) o << ","; + if (ast->trailingComma) + o << ","; fill(ast->closeFodder, ast->fields.size() > 0, opts.padObjects); o << "}"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "{"; for (AST *assert : ast->asserts) { o << "assert"; @@ -532,15 +537,16 @@ class Unparser { } o << "}"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "{"; unparseFields(ast->fields, opts.padObjects); - if (ast->trailingComma) o << ","; + if (ast->trailingComma) + o << ","; unparseSpecs(ast->specs); fill(ast->closeFodder, true, opts.padObjects); o << "}"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "{["; unparse(ast->field, false); o << "]:"; @@ -549,16 +555,16 @@ class Unparser { unparse(ast->array, true); o << "}"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "("; unparse(ast->expr, false); fill(ast->closeFodder, false, false); o << ")"; - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { o << "self"; - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << "super"; fill(ast->dotFodder, false, false); if (ast->id != nullptr) { @@ -572,26 +578,24 @@ class Unparser { o << "]"; } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << uop_string(ast->op); - if (dynamic_cast(left_recursive(ast->expr))) { + if (dynamic_cast(left_recursive(ast->expr))) { unparse(ast->expr, true); } else { unparse(ast->expr, false); } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { o << encode_utf8(ast->id->name); } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); - } } }; - /******************************************************************************** * The rest of this file contains transformations on the ASTs before unparsing. * ********************************************************************************/ @@ -599,31 +603,36 @@ class Unparser { /** A generic Pass that does nothing but can be extended to easily define real passes. */ class FmtPass : public CompilerPass { - protected: + protected: FmtOpts opts; - public: - FmtPass(Allocator &alloc, const FmtOpts &opts) - : CompilerPass(alloc), opts(opts) { } + public: + FmtPass(Allocator &alloc, const FmtOpts &opts) : CompilerPass(alloc), opts(opts) {} }; - class EnforceStringStyle : public FmtPass { using FmtPass::visit; - public: - EnforceStringStyle(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + public: + EnforceStringStyle(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} void visit(LiteralString *lit) { - if (lit->tokenKind == LiteralString::BLOCK) return; - if (lit->tokenKind == LiteralString::VERBATIM_DOUBLE) return; - if (lit->tokenKind == LiteralString::VERBATIM_SINGLE) return; + if (lit->tokenKind == LiteralString::BLOCK) + return; + if (lit->tokenKind == LiteralString::VERBATIM_DOUBLE) + return; + if (lit->tokenKind == LiteralString::VERBATIM_SINGLE) + return; UString canonical = jsonnet_string_unescape(lit->location, lit->value); unsigned num_single = 0, num_double = 0; for (char32_t c : canonical) { - if (c == '\'') num_single++; - if (c == '"') num_double++; + if (c == '\'') + num_single++; + if (c == '"') + num_double++; } - if (num_single > 0 && num_double > 0) return; // Don't change it. + if (num_single > 0 && num_double > 0) + return; // Don't change it. bool use_single = opts.stringStyle == 's'; if (num_single > 0) use_single = false; @@ -637,11 +646,12 @@ class EnforceStringStyle : public FmtPass { }; class EnforceCommentStyle : public FmtPass { - public: + public: bool firstFodder; EnforceCommentStyle(Allocator &alloc, const FmtOpts &opts) - : FmtPass(alloc, opts), firstFodder(true) - { } + : FmtPass(alloc, opts), firstFodder(true) + { + } /** Change the comment to match the given style, but don't break she-bang. * * If preserve_hash is true, do not touch a comment that starts with #!. @@ -652,7 +662,8 @@ class EnforceCommentStyle : public FmtPass { s = "#" + s.substr(2); } if (opts.commentStyle == 's' && s[0] == '#') { - if (preserve_hash && s[1] == '!') return; + if (preserve_hash && s[1] == '!') + return; s = "//" + s.substr(1); } } @@ -662,13 +673,12 @@ class EnforceCommentStyle : public FmtPass { switch (f.kind) { case FodderElement::LINE_END: case FodderElement::PARAGRAPH: - if (f.comment.size() == 1) { - fixComment(f.comment[0], firstFodder); - } - break; + if (f.comment.size() == 1) { + fixComment(f.comment[0], firstFodder); + } + break; - case FodderElement::INTERSTITIAL: - break; + case FodderElement::INTERSTITIAL: break; } firstFodder = false; } @@ -676,18 +686,19 @@ class EnforceCommentStyle : public FmtPass { }; class EnforceMaximumBlankLines : public FmtPass { - public: - EnforceMaximumBlankLines(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + public: + EnforceMaximumBlankLines(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} void fodderElement(FodderElement &f) { if (f.kind != FodderElement::INTERSTITIAL) - if (f.blanks > 2) f.blanks = 2; + if (f.blanks > 2) + f.blanks = 2; } }; class StripComments : public FmtPass { - public: - StripComments(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + public: + StripComments(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} void fodder(Fodder &fodder) { Fodder copy = fodder; @@ -700,14 +711,17 @@ class StripComments : public FmtPass { }; class StripEverything : public FmtPass { - public: - StripEverything(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } - void fodder(Fodder &fodder) { fodder.clear(); } + public: + StripEverything(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} + void fodder(Fodder &fodder) + { + fodder.clear(); + } }; class StripAllButComments : public FmtPass { - public: - StripAllButComments(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + public: + StripAllButComments(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} Fodder comments; void fodder(Fodder &fodder) { @@ -757,8 +771,9 @@ bool contains_newline(const Fodder &fodder) /* Commas should appear at the end of an object/array only if the closing token is on a new line. */ class FixTrailingCommas : public FmtPass { using FmtPass::visit; - public: - FixTrailingCommas(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + public: + FixTrailingCommas(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} Fodder comments; // Generalized fix that works across a range of ASTs. @@ -825,18 +840,17 @@ class FixTrailingCommas : public FmtPass { remove_comma(expr->fields.back().commaFodder, expr->trailingComma, expr->closeFodder); FmtPass::visit(expr); } - }; - /* Remove nested parens. */ class FixParens : public FmtPass { using FmtPass::visit; - public: - FixParens(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + public: + FixParens(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} void visit(Parens *expr) { - if (auto *body = dynamic_cast(expr->expr)) { + if (auto *body = dynamic_cast(expr->expr)) { // Deal with fodder. expr->expr = body->expr; fodder_move_front(open_fodder(body->expr), body->openFodder); @@ -846,24 +860,22 @@ class FixParens : public FmtPass { } }; - - /* Ensure ApplyBrace syntax sugar is used in the case of A + { }. */ class FixPlusObject : public FmtPass { using FmtPass::visit; - public: - FixPlusObject(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + public: + FixPlusObject(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} void visitExpr(AST *&expr) { - if (auto *bin_op = dynamic_cast(expr)) { + if (auto *bin_op = dynamic_cast(expr)) { // Could relax this to allow more ASTs on the LHS but this seems OK for now. - if (dynamic_cast(bin_op->left) - || dynamic_cast(bin_op->left)) { - if (AST *rhs = dynamic_cast(bin_op->right)) { + if (dynamic_cast(bin_op->left) || dynamic_cast(bin_op->left)) { + if (AST *rhs = dynamic_cast(bin_op->right)) { if (bin_op->op == BOP_PLUS) { fodder_move_front(rhs->openFodder, bin_op->opFodder); - expr = alloc.make(bin_op->location, bin_op->openFodder, - bin_op->left, rhs); + expr = alloc.make( + bin_op->location, bin_op->openFodder, bin_op->left, rhs); } } } @@ -872,13 +884,12 @@ class FixPlusObject : public FmtPass { } }; - - /* Remove final colon in slices. */ class NoRedundantSliceColon : public FmtPass { using FmtPass::visit; - public: - NoRedundantSliceColon(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + + public: + NoRedundantSliceColon(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} void visit(Index *expr) { @@ -896,18 +907,18 @@ class NoRedundantSliceColon : public FmtPass { /* Ensure syntax sugar is used where possible. */ class PrettyFieldNames : public FmtPass { using FmtPass::visit; - public: - PrettyFieldNames(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } - bool isIdentifier(const UString &str) { + public: + PrettyFieldNames(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} + + bool isIdentifier(const UString &str) + { bool first = true; for (char32_t c : str) { if (!first && c >= '0' && c <= '9') continue; first = false; - if ((c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z') - || (c == '_')) + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')) continue; return false; } @@ -921,7 +932,7 @@ class PrettyFieldNames : public FmtPass { { if (!expr->isSlice && expr->index != nullptr) { // Maybe we can use an id instead. - if (auto *lit = dynamic_cast(expr->index)) { + if (auto *lit = dynamic_cast(expr->index)) { if (isIdentifier(lit->value)) { expr->id = alloc.makeIdentifier(lit->value); expr->idFodder = lit->openFodder; @@ -937,7 +948,7 @@ class PrettyFieldNames : public FmtPass { for (auto &field : expr->fields) { // First try ["foo"] -> "foo". if (field.kind == ObjectField::FIELD_EXPR) { - if (auto *field_expr = dynamic_cast(field.expr1)) { + if (auto *field_expr = dynamic_cast(field.expr1)) { field.kind = ObjectField::FIELD_STR; fodder_move_front(field_expr->openFodder, field.fodder1); if (field.methodSugar) { @@ -949,7 +960,7 @@ class PrettyFieldNames : public FmtPass { } // Then try "foo" -> foo. if (field.kind == ObjectField::FIELD_STR) { - if (auto *lit = dynamic_cast(field.expr1)) { + if (auto *lit = dynamic_cast(field.expr1)) { if (isIdentifier(lit->value)) { field.kind = ObjectField::FIELD_ID; field.id = alloc.makeIdentifier(lit->value); @@ -977,12 +988,12 @@ class PrettyFieldNames : public FmtPass { /// }] /// The outer array can stay unexpanded, because there are no newlines between /// the square brackets and the braces. -class FixNewlines: public FmtPass { +class FixNewlines : public FmtPass { using FmtPass::visit; bool shouldExpand(const Array *array) { - for (const auto &elem: array->elements) { + for (const auto &elem : array->elements) { if (countNewlines(open_fodder(elem.expr)) > 0) { return true; } @@ -995,7 +1006,7 @@ class FixNewlines: public FmtPass { void expand(Array *array) { - for (auto &elem: array->elements) { + for (auto &elem : array->elements) { ensureCleanNewline(open_fodder(elem.expr)); } ensureCleanNewline(array->closeFodder); @@ -1011,7 +1022,7 @@ class FixNewlines: public FmtPass { bool shouldExpand(Object *object) { - for (auto &field: object->fields) { + for (auto &field : object->fields) { if (countNewlines(objectFieldOpenFodder(field)) > 0) { return true; } @@ -1024,7 +1035,7 @@ class FixNewlines: public FmtPass { void expand(Object *object) { - for (auto &field: object->fields) { + for (auto &field : object->fields) { ensureCleanNewline(objectFieldOpenFodder(field)); } ensureCleanNewline(object->closeFodder); @@ -1032,7 +1043,7 @@ class FixNewlines: public FmtPass { bool shouldExpand(Local *local) { - for (auto &bind: local->binds) { + for (auto &bind : local->binds) { if (countNewlines(bind.varFodder) > 0) { return true; } @@ -1043,7 +1054,7 @@ class FixNewlines: public FmtPass { void expand(Local *local) { bool first = true; - for (auto &bind: local->binds) { + for (auto &bind : local->binds) { if (!first) { ensureCleanNewline(bind.varFodder); } @@ -1056,7 +1067,7 @@ class FixNewlines: public FmtPass { if (countNewlines(open_fodder(comp->body)) > 0) { return true; } - for (auto &spec: comp->specs) { + for (auto &spec : comp->specs) { if (countNewlines(spec.openFodder) > 0) { return true; } @@ -1070,7 +1081,7 @@ class FixNewlines: public FmtPass { void expand(ArrayComprehension *comp) { ensureCleanNewline(open_fodder(comp->body)); - for (auto &spec: comp->specs) { + for (auto &spec : comp->specs) { ensureCleanNewline(spec.openFodder); } ensureCleanNewline(comp->closeFodder); @@ -1078,12 +1089,12 @@ class FixNewlines: public FmtPass { bool shouldExpand(ObjectComprehension *comp) { - for (auto &field: comp->fields) { + for (auto &field : comp->fields) { if (countNewlines(objectFieldOpenFodder(field)) > 0) { return true; } } - for (auto &spec: comp->specs) { + for (auto &spec : comp->specs) { if (countNewlines(spec.openFodder) > 0) { return true; } @@ -1096,10 +1107,10 @@ class FixNewlines: public FmtPass { void expand(ObjectComprehension *comp) { - for (auto &field: comp->fields) { + for (auto &field : comp->fields) { ensureCleanNewline(objectFieldOpenFodder(field)); } - for (auto &spec: comp->specs) { + for (auto &spec : comp->specs) { ensureCleanNewline(spec.openFodder); } ensureCleanNewline(comp->closeFodder); @@ -1107,8 +1118,8 @@ class FixNewlines: public FmtPass { bool shouldExpand(Parens *parens) { - return countNewlines(open_fodder(parens->expr)) > 0 - || countNewlines(parens->closeFodder) > 0; + return countNewlines(open_fodder(parens->expr)) > 0 || + countNewlines(parens->closeFodder) > 0; } void expand(Parens *parens) @@ -1139,7 +1150,7 @@ class FixNewlines: public FmtPass { bool shouldExpandBetween(ArgParams ¶ms) { bool first = true; - for (auto ¶m: params) { + for (auto ¶m : params) { if (!first && countNewlines(argParamOpenFodder(param)) > 0) { return true; } @@ -1151,7 +1162,7 @@ class FixNewlines: public FmtPass { void expandBetween(ArgParams ¶ms) { bool first = true; - for (auto ¶m: params) { + for (auto ¶m : params) { if (!first) { ensureCleanNewline(argParamOpenFodder(param)); } @@ -1178,16 +1189,17 @@ class FixNewlines: public FmtPass { void expandNearParens(ArgParams ¶ms, Fodder &fodder_r) { if (!params.empty()) { - ensureCleanNewline(argParamOpenFodder(params.front())); + ensureCleanNewline(argParamOpenFodder(params.front())); } ensureCleanNewline(fodder_r); } - public: - FixNewlines(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) { } + public: + FixNewlines(Allocator &alloc, const FmtOpts &opts) : FmtPass(alloc, opts) {} - template - void simpleExpandingVisit(T *expr) { + template + void simpleExpandingVisit(T *expr) + { if (shouldExpand(expr)) { expand(expr); } @@ -1239,12 +1251,11 @@ class FixNewlines: public FmtPass { }; class FixIndentation { - FmtOpts opts; unsigned column; - public: - FixIndentation(const FmtOpts &opts) : opts(opts), column(0) { } + public: + FixIndentation(const FmtOpts &opts) : opts(opts), column(0) {} /* Set the indentation on the fodder elements, adjust column counter as if it was printed. * \param fodder The fodder to pretend to print. @@ -1254,8 +1265,8 @@ class FixIndentation { * \param all_but_last_indent New indentation value for all but final fodder element. * \param last_indent New indentation value for the final fodder element. */ - void fill(Fodder &fodder, bool space_before, bool separate_token, - unsigned all_but_last_indent, unsigned last_indent) + void fill(Fodder &fodder, bool space_before, bool separate_token, unsigned all_but_last_indent, + unsigned last_indent) { setIndents(fodder, all_but_last_indent, last_indent); fodder_count(column, fodder, space_before, separate_token); @@ -1279,7 +1290,7 @@ class FixIndentation { struct Indent { unsigned base; unsigned lineUp; - Indent(unsigned base, unsigned line_up) : base(base), lineUp(line_up) { } + Indent(unsigned base, unsigned line_up) : base(base), lineUp(line_up) {} }; /** Calculate the indentation of sub-expressions. @@ -1390,15 +1401,13 @@ class FixIndentation { column += 2; // in Indent new_indent = newIndent(open_fodder(spec.expr), indent, column); expr(spec.expr, new_indent, true); - } - break; + } break; case ComprehensionSpec::IF: { column += 2; // if Indent new_indent = newIndent(open_fodder(spec.expr), indent, column); expr(spec.expr, new_indent, true); - } - break; + } break; } } } @@ -1413,7 +1422,8 @@ class FixIndentation { Indent new_indent = newIndent(first_inside, indent, column); bool first = true; for (auto ¶m : params) { - if (!first) column++; // ',' + if (!first) + column++; // ',' fill(param.idFodder, !first, true, new_indent.lineUp); column += param.id->name.length(); if (param.expr != nullptr) { @@ -1449,11 +1459,11 @@ class FixIndentation { unsigned new_indent = indent.lineUp; bool first = true; for (auto &field : fields) { - if (!first) column++; // ',' + if (!first) + column++; // ',' switch (field.kind) { case ObjectField::LOCAL: { - fill(field.fodder1, !first || space_before, true, indent.lineUp); column += 5; // local fill(field.fodder2, true, true, indent.lineUp); @@ -1468,7 +1478,6 @@ class FixIndentation { case ObjectField::FIELD_ID: case ObjectField::FIELD_STR: case ObjectField::FIELD_EXPR: { - if (field.kind == ObjectField::FIELD_ID) { fill(field.fodder1, !first || space_before, true, new_indent); column += field.id->name.length(); @@ -1488,11 +1497,12 @@ class FixIndentation { fill(field.opFodder, false, false, new_indent); - if (field.superSugar) column++; + if (field.superSugar) + column++; switch (field.hide) { - case ObjectField::INHERIT: column+=1; break; - case ObjectField::HIDDEN: column+=2; break; - case ObjectField::VISIBLE: column+=3; break; + case ObjectField::INHERIT: column += 1; break; + case ObjectField::HIDDEN: column += 2; break; + case ObjectField::VISIBLE: column += 3; break; } Indent new_indent2 = newIndent(open_fodder(field.expr2), indent, column); expr(field.expr2, new_indent2, true); @@ -1500,7 +1510,6 @@ class FixIndentation { } break; case ObjectField::ASSERT: { - fill(field.fodder1, !first || space_before, true, new_indent); column += 6; // assert // + 1 for the space after the assert @@ -1532,7 +1541,8 @@ class FixIndentation { /** Get the first fodder from an ArgParam. */ const Fodder &argParamFirstFodder(const ArgParam &ap) { - if (ap.id != nullptr) return ap.idFodder; + if (ap.id != nullptr) + return ap.idFodder; return open_fodder(ap.expr); } @@ -1546,15 +1556,14 @@ class FixIndentation { { fill(ast_->openFodder, space_before, !left_recursive(ast_), indent.lineUp); - if (auto *ast = dynamic_cast(ast_)) { + if (auto *ast = dynamic_cast(ast_)) { const Fodder &init_fodder = open_fodder(ast->target); - Indent new_indent = align(init_fodder, indent, - column + (space_before ? 1 : 0)); + Indent new_indent = align(init_fodder, indent, column + (space_before ? 1 : 0)); expr(ast->target, new_indent, space_before); fill(ast->fodderL, false, false, new_indent.lineUp); column++; // ( - const Fodder &first_fodder = ast->args.size() == 0 - ? ast->fodderR : argParamFirstFodder(ast->args[0]); + const Fodder &first_fodder = + ast->args.size() == 0 ? ast->fodderR : argParamFirstFodder(ast->args[0]); bool strong_indent = false; // Need to use strong indent if any of the // arguments (except the first) are preceded by newlines. @@ -1569,12 +1578,12 @@ class FixIndentation { strong_indent = true; } - Indent arg_indent = strong_indent - ? newIndentStrong(first_fodder, indent, column) - : newIndent(first_fodder, indent, column); + Indent arg_indent = strong_indent ? newIndentStrong(first_fodder, indent, column) + : newIndent(first_fodder, indent, column); first = true; for (auto &arg : ast->args) { - if (!first) column++; // "," + if (!first) + column++; // "," bool space = !first; if (arg.id != nullptr) { @@ -1587,7 +1596,8 @@ class FixIndentation { fill(arg.commaFodder, false, false, arg_indent.lineUp); first = false; } - if (ast->trailingComma) column++; // "," + if (ast->trailingComma) + column++; // "," fill(ast->fodderR, false, false, arg_indent.lineUp, indent.base); column++; // ) if (ast->tailstrict) { @@ -1595,19 +1605,17 @@ class FixIndentation { column += 10; // tailstrict } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { const Fodder &init_fodder = open_fodder(ast->left); - Indent new_indent = align(init_fodder, indent, - column + (space_before ? 1 : 0)); + Indent new_indent = align(init_fodder, indent, column + (space_before ? 1 : 0)); expr(ast->left, new_indent, space_before); expr(ast->right, new_indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column++; // '[' // First fodder element exists and is a newline - const Fodder &first_fodder = ast->elements.size() > 0 - ? open_fodder(ast->elements[0].expr) - : ast->closeFodder; + const Fodder &first_fodder = + ast->elements.size() > 0 ? open_fodder(ast->elements[0].expr) : ast->closeFodder; unsigned new_column = column + (opts.padArrays ? 1 : 0); bool strong_indent = false; // Need to use strong indent if there are not newlines before any of the sub-expressions @@ -1621,36 +1629,41 @@ class FixIndentation { strong_indent = true; } - Indent new_indent = strong_indent - ? newIndentStrong(first_fodder, indent, new_column) - : newIndent(first_fodder, indent, new_column); + Indent new_indent = strong_indent ? newIndentStrong(first_fodder, indent, new_column) + : newIndent(first_fodder, indent, new_column); first = true; for (auto &element : ast->elements) { - if (!first) column++; + if (!first) + column++; expr(element.expr, new_indent, !first || opts.padArrays); fill(element.commaFodder, false, false, new_indent.lineUp, new_indent.lineUp); first = false; } - if (ast->trailingComma) column++; + if (ast->trailingComma) + column++; // Handle penultimate newlines from expr.close_fodder if there are any. - fill(ast->closeFodder, ast->elements.size() > 0, opts.padArrays, new_indent.lineUp, + fill(ast->closeFodder, + ast->elements.size() > 0, + opts.padArrays, + new_indent.lineUp, indent.base); column++; // ']' - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column++; // [ - Indent new_indent = newIndent(open_fodder(ast->body), indent, - column + (opts.padArrays ? 1 : 0)); + Indent new_indent = + newIndent(open_fodder(ast->body), indent, column + (opts.padArrays ? 1 : 0)); expr(ast->body, new_indent, opts.padArrays); fill(ast->commaFodder, false, false, new_indent.lineUp); - if (ast->trailingComma) column++; // ',' + if (ast->trailingComma) + column++; // ',' specs(ast->specs, new_indent); fill(ast->closeFodder, true, opts.padArrays, new_indent.lineUp, indent.base); column++; // ] - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 6; // assert // + 1 for the space after the assert Indent new_indent = newIndent(open_fodder(ast->cond), indent, column + 1); @@ -1664,7 +1677,7 @@ class FixIndentation { column++; // ";" expr(ast->rest, indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { const Fodder &first_fodder = open_fodder(ast->left); // Need to use strong indent in the case of @@ -1678,9 +1691,8 @@ class FixIndentation { bool strong_indent = hasNewLines(ast->opFodder) || hasNewLines(open_fodder(ast->right)); unsigned inner_column = column + (space_before ? 1 : 0); - Indent new_indent = strong_indent - ? alignStrong(first_fodder, indent, inner_column) - : align(first_fodder, indent, inner_column); + Indent new_indent = strong_indent ? alignStrong(first_fodder, indent, inner_column) + : align(first_fodder, indent, inner_column); expr(ast->left, new_indent, space_before); fill(ast->opFodder, true, true, new_indent.lineUp); column += bop_string(ast->op).length(); @@ -1690,12 +1702,12 @@ class FixIndentation { // true expr(ast->right, new_indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 11; // "/* builtin " column += ast->name.length(); column += 8; // " */ null" - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 2; // if Indent cond_indent = newIndent(open_fodder(ast->cond), indent, column + 1); expr(ast->cond, cond_indent, true); @@ -1710,39 +1722,42 @@ class FixIndentation { expr(ast->branchFalse, false_indent, true); } - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { column++; // $ - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 5; // error Indent new_indent = newIndent(open_fodder(ast->expr), indent, column + 1); expr(ast->expr, new_indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 8; // function - params(ast->parenLeftFodder, ast->params, ast->trailingComma, - ast->parenRightFodder, indent); + params(ast->parenLeftFodder, + ast->params, + ast->trailingComma, + ast->parenRightFodder, + indent); Indent new_indent = newIndent(open_fodder(ast->body), indent, column + 1); expr(ast->body, new_indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 6; // import Indent new_indent = newIndent(open_fodder(ast->file), indent, column + 1); expr(ast->file, new_indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 9; // importstr Indent new_indent = newIndent(open_fodder(ast->file), indent, column + 1); expr(ast->file, new_indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { expr(ast->element, indent, space_before); fill(ast->inFodder, true, true, indent.lineUp); column += 2; // in fill(ast->superFodder, true, true, indent.lineUp); column += 5; // super - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { expr(ast->target, indent, space_before); fill(ast->dotFodder, false, false, indent.lineUp); if (ast->id != nullptr) { @@ -1787,7 +1802,7 @@ class FixIndentation { column++; // "]" } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 5; // local assert(ast->binds.size() > 0); bool first = true; @@ -1799,8 +1814,11 @@ class FixIndentation { fill(bind.varFodder, true, true, new_indent.lineUp); column += bind.var->name.length(); if (bind.functionSugar) { - params(bind.parenLeftFodder, bind.params, bind.trailingComma, - bind.parenRightFodder, new_indent); + params(bind.parenLeftFodder, + bind.params, + bind.trailingComma, + bind.parenRightFodder, + new_indent); } fill(bind.opFodder, true, true, new_indent.lineUp); column++; // '=' @@ -1811,13 +1829,13 @@ class FixIndentation { column++; // ';' expr(ast->body, indent, true); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += (ast->value ? 4 : 5); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += ast->originalString.length(); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (ast->tokenKind == LiteralString::DOUBLE) { column += 2 + ast->value.length(); // Include quotes } else if (ast->tokenKind == LiteralString::SINGLE) { @@ -1826,10 +1844,10 @@ class FixIndentation { ast->blockIndent = std::string(indent.base + opts.indent, ' '); ast->blockTermIndent = std::string(indent.base, ' '); column = indent.base; // blockTermIndent - column += 3; // "|||" + column += 3; // "|||" } else if (ast->tokenKind == LiteralString::VERBATIM_SINGLE) { column += 3; // Include @, start and end quotes - for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + for (const char32_t *cp = ast->value.c_str(); *cp != U'\0'; ++cp) { if (*cp == U'\'') { column += 2; } else { @@ -1838,7 +1856,7 @@ class FixIndentation { } } else if (ast->tokenKind == LiteralString::VERBATIM_DOUBLE) { column += 3; // Include @, start and end quotes - for (const char32_t *cp = ast->value.c_str() ; *cp != U'\0' ; ++cp) { + for (const char32_t *cp = ast->value.c_str(); *cp != U'\0'; ++cp) { if (*cp == U'"') { column += 2; } else { @@ -1847,26 +1865,29 @@ class FixIndentation { } } - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { column += 4; // null - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column++; // '{' const Fodder &first_fodder = ast->fields.size() == 0 - ? ast->closeFodder - : ast->fields[0].kind == ObjectField::FIELD_STR - ? open_fodder(ast->fields[0].expr1) - : ast->fields[0].fodder1; - Indent new_indent = newIndent(first_fodder, indent, - column + (opts.padObjects ? 1 : 0)); + ? ast->closeFodder + : ast->fields[0].kind == ObjectField::FIELD_STR + ? open_fodder(ast->fields[0].expr1) + : ast->fields[0].fodder1; + Indent new_indent = newIndent(first_fodder, indent, column + (opts.padObjects ? 1 : 0)); fields(ast->fields, new_indent, opts.padObjects); - if (ast->trailingComma) column++; - fill(ast->closeFodder, ast->fields.size() > 0, opts.padObjects, - new_indent.lineUp, indent.base); + if (ast->trailingComma) + column++; + fill(ast->closeFodder, + ast->fields.size() > 0, + opts.padObjects, + new_indent.lineUp, + indent.base); column++; // '}' - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { // No fodder but need to recurse and maintain column counter. column++; // '{' for (AST *assert : ast->asserts) { @@ -1887,24 +1908,25 @@ class FixIndentation { } column++; // '}' - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column++; // '{' unsigned start_column = column; const Fodder &first_fodder = ast->fields.size() == 0 - ? ast->closeFodder - : ast->fields[0].kind == ObjectField::FIELD_STR - ? open_fodder(ast->fields[0].expr1) - : ast->fields[0].fodder1; - Indent new_indent = newIndent(first_fodder, indent, - start_column + (opts.padObjects ? 1 : 0)); + ? ast->closeFodder + : ast->fields[0].kind == ObjectField::FIELD_STR + ? open_fodder(ast->fields[0].expr1) + : ast->fields[0].fodder1; + Indent new_indent = + newIndent(first_fodder, indent, start_column + (opts.padObjects ? 1 : 0)); fields(ast->fields, new_indent, opts.padObjects); - if (ast->trailingComma) column++; // ',' + if (ast->trailingComma) + column++; // ',' specs(ast->specs, new_indent); fill(ast->closeFodder, true, opts.padObjects, new_indent.lineUp, indent.base); column++; // '}' - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column++; // '{' column++; // '[' expr(ast->field, indent, false); @@ -1917,17 +1939,17 @@ class FixIndentation { expr(ast->array, indent, true); column++; // '}' - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column++; // ( Indent new_indent = newIndentStrong(open_fodder(ast->expr), indent, column); expr(ast->expr, new_indent, false); fill(ast->closeFodder, false, false, new_indent.lineUp, indent.base); column++; // ) - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { column += 4; // self - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += 5; // super fill(ast->dotFodder, false, false, indent.lineUp); if (ast->id != nullptr) { @@ -1943,18 +1965,17 @@ class FixIndentation { column++; // "]"; } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += uop_string(ast->op).length(); Indent new_indent = newIndent(open_fodder(ast->expr), indent, column); expr(ast->expr, new_indent, false); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { column += ast->id->name.length(); } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); - } } virtual void file(AST *body, Fodder &final_fodder) @@ -1978,7 +1999,9 @@ class SortImports { /// Internal representation of an import struct ImportElem { ImportElem(UString key, Fodder adjacentFodder, Local::Bind bind) - : key(key), adjacentFodder(adjacentFodder), bind(bind) { } + : key(key), adjacentFodder(adjacentFodder), bind(bind) + { + } // A key by which the imports should be sorted. // It's a file path that is imported, represented as UTF-32 codepoints without case folding. @@ -1992,7 +2015,8 @@ class SortImports { // The bind that contains the import // Satisfies: bind.functionSugar == false && bind.body->type == AST_IMPORT Local::Bind bind; - bool operator<(const ImportElem &elem) const { + bool operator<(const ImportElem &elem) const + { return key < elem.key; } }; @@ -2001,8 +2025,8 @@ class SortImports { Allocator &alloc; - public: - SortImports(Allocator &alloc) : alloc(alloc) { } + public: + SortImports(Allocator &alloc) : alloc(alloc) {} /// Get the value by which the imports should be sorted. UString sortingKey(Import *import) @@ -2013,7 +2037,7 @@ class SortImports { /// Check if `local` expression is used for importing, bool isGoodLocal(Local *local) { - for (const auto &bind: local->binds) { + for (const auto &bind : local->binds) { if (bind.body->type != AST_IMPORT || bind.functionSugar) { return false; } @@ -2023,7 +2047,7 @@ class SortImports { Local *goodLocalOrNull(AST *expr) { - if (auto *local = dynamic_cast(expr)) { + if (auto *local = dynamic_cast(expr)) { return isGoodLocal(local) ? local : nullptr; } else { return nullptr; @@ -2052,7 +2076,7 @@ class SortImports { { Fodder afterPrev, beforeNext; bool inSecondPart = false; - for (const auto &fodderElem: fodder) { + for (const auto &fodderElem : fodder) { if (inSecondPart) { fodder_push_back(beforeNext, fodderElem); } else { @@ -2065,12 +2089,10 @@ class SortImports { // to beforeNext. afterPrev.back().blanks = 0; assert(beforeNext.empty()); - beforeNext.emplace_back( - FodderElement::Kind::LINE_END, - fodderElem.blanks, - fodderElem.indent, - std::vector() - ); + beforeNext.emplace_back(FodderElement::Kind::LINE_END, + fodderElem.blanks, + fodderElem.indent, + std::vector()); } } } @@ -2105,7 +2127,7 @@ class SortImports { ensureCleanNewline(adjacent); Local::Bind newBind = bind; newBind.varFodder = before; - Import *import = dynamic_cast(bind.body); + Import *import = dynamic_cast(bind.body); assert(import != nullptr); result.emplace_back(sortingKey(import), adjacent, newBind); before = beforeNext; @@ -2123,12 +2145,8 @@ class SortImports { } else { fodder = imports[i - 1].adjacentFodder; } - auto *local = alloc.make( - LocationRange(), - fodder, - Local::Binds({import.bind}), - body - ); + auto *local = + alloc.make(LocationRange(), fodder, Local::Binds({import.bind}), body); body = local; } @@ -2138,7 +2156,7 @@ class SortImports { bool duplicatedVariables(const ImportElems &elems) { std::set idents; - for (const auto &elem: elems) { + for (const auto &elem : elems) { idents.insert(elem.bind.var->name); } return idents.size() < elems.size(); @@ -2153,7 +2171,7 @@ class SortImports { } bool newlineReached = false; - for (const auto &fodderElem: open_fodder(next)) { + for (const auto &fodderElem : open_fodder(next)) { if (newlineReached || fodderElem.blanks > 0) { return true; } @@ -2181,10 +2199,7 @@ class SortImports { Fodder afterGroup = imports.back().adjacentFodder; ensureCleanNewline(beforeNextFodder); - auto nextOpenFodder = concat_fodder( - afterGroup, - beforeNextFodder - ); + auto nextOpenFodder = concat_fodder(afterGroup, beforeNextFodder); // Process the code after the current group: AST *bodyAfterGroup; @@ -2202,7 +2217,7 @@ class SortImports { return buildGroupAST(imports, bodyAfterGroup, groupOpenFodder); } else { assert(beforeNextFodder.empty()); - return toplevelImport(dynamic_cast(local->body), imports, groupOpenFodder); + return toplevelImport(dynamic_cast(local->body), imports, groupOpenFodder); } } diff --git a/core/formatter.h b/core/formatter.h index 7db974c2a..3fa4aff61 100644 --- a/core/formatter.h +++ b/core/formatter.h @@ -32,18 +32,19 @@ struct FmtOpts { bool prettyFieldNames; bool sortImports; FmtOpts(void) - : stringStyle('l'), - commentStyle('l'), - indent(0), - maxBlankLines(2), - padArrays(false), - padObjects(true), - stripComments(false), - stripAllButComments(false), - stripEverything(false), - prettyFieldNames(true), - sortImports(false) - { } + : stringStyle('l'), + commentStyle('l'), + indent(0), + maxBlankLines(2), + padArrays(false), + padObjects(true), + stripComments(false), + stripAllButComments(false), + stripEverything(false), + prettyFieldNames(true), + sortImports(false) + { + } }; /** The inverse of jsonnet_parse. diff --git a/core/json.h b/core/json.h index d1c546308..bf880080b 100644 --- a/core/json.h +++ b/core/json.h @@ -17,9 +17,9 @@ limitations under the License. #ifndef JSONNET_JSON_H #define JSONNET_JSON_H -#include #include #include +#include #include diff --git a/core/lexer.cpp b/core/lexer.cpp index b477bf058..feec27d6e 100644 --- a/core/lexer.cpp +++ b/core/lexer.cpp @@ -17,8 +17,8 @@ limitations under the License. #include #include -#include #include +#include #include "lexer.h" #include "static_error.h" @@ -29,7 +29,8 @@ static const std::vector EMPTY; /** Strip whitespace from both ends of a string, but only up to margin on the left hand side. */ static std::string strip_ws(const std::string &s, unsigned margin) { - if (s.size() == 0) return s; // Avoid underflow below. + if (s.size() == 0) + return s; // Avoid underflow below. size_t i = 0; while (i < s.length() && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r') && i < margin) i++; @@ -45,7 +46,7 @@ static std::vector line_split(const std::string &s, unsigned margin { std::vector ret; std::stringstream ss; - for (size_t i=0 ; i line_split(const std::string &s, unsigned margin return ret; } - - /** Consume whitespace. * * Return number of \n and number of spaces after last \n. Convert \t to spaces. @@ -71,32 +70,29 @@ static void lex_ws(const char *&c, unsigned &new_lines, unsigned &indent, const for (; *c != '\0' && (*c == ' ' || *c == '\n' || *c == '\t' || *c == '\r'); c++) { switch (*c) { case '\r': - // Ignore. - break; + // Ignore. + break; case '\n': - indent = 0; - new_lines++; - line_number++; - line_start = c + 1; - break; + indent = 0; + new_lines++; + line_number++; + line_start = c + 1; + break; case ' ': - indent += 1; - break; + indent += 1; + break; // This only works for \t at the beginning of lines, but we strip it everywhere else // anyway. The only case where this will cause a problem is spaces followed by \t // at the beginning of a line. However that is rare, ill-advised, and if re-indentation // is enabled it will be fixed later. - case '\t': - indent += 8; - break; + case '\t': indent += 8; break; } } } - /** # Consume all text until the end of the line, return number of newlines after that and indent */ @@ -144,12 +140,21 @@ static bool is_identifier(char c) static bool is_symbol(char c) { switch (c) { - case '!': case '$': case ':': - case '~': case '+': case '-': - case '&': case '|': case '^': - case '=': case '<': case '>': - case '*': case '/': case '%': - return true; + case '!': + case '$': + case ':': + case '~': + case '+': + case '-': + case '&': + case '|': + case '^': + case '=': + case '<': + case '>': + case '*': + case '/': + case '%': return true; } return false; } @@ -177,7 +182,8 @@ static const std::map keywords = { Token::Kind lex_get_keyword_kind(const std::string &identifier) { auto it = keywords.find(identifier); - if (it == keywords.end()) return Token::IDENTIFIER; + if (it == keywords.end()) + return Token::IDENTIFIER; return it->second; } @@ -208,137 +214,163 @@ std::string lex_number(const char *&c, const std::string &filename, const Locati while (true) { switch (state) { case BEGIN: - switch (*c) { - case '0': - state = AFTER_ZERO; - break; - - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_ONE_TO_NINE; + switch (*c) { + case '0': state = AFTER_ZERO; break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_ONE_TO_NINE; break; + + default: throw StaticError(filename, begin, "Couldn't lex number"); + } break; - default: - throw StaticError(filename, begin, "Couldn't lex number"); - } - break; - case AFTER_ZERO: - switch (*c) { - case '.': - state = AFTER_DOT; - break; - - case 'e': case 'E': - state = AFTER_E; - break; + switch (*c) { + case '.': state = AFTER_DOT; break; - default: - goto end; - } - break; - - case AFTER_ONE_TO_NINE: - switch (*c) { - case '.': - state = AFTER_DOT; - break; + case 'e': + case 'E': state = AFTER_E; break; - case 'e': case 'E': - state = AFTER_E; + default: goto end; + } break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_ONE_TO_NINE; + case AFTER_ONE_TO_NINE: + switch (*c) { + case '.': state = AFTER_DOT; break; + + case 'e': + case 'E': state = AFTER_E; break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_ONE_TO_NINE; break; + + default: goto end; + } break; - default: - goto end; - } - break; - case AFTER_DOT: - switch (*c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_DIGIT; - break; - - default: { - std::stringstream ss; - ss << "Couldn't lex number, junk after decimal point: " << *c; - throw StaticError(filename, begin, ss.str()); + switch (*c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_DIGIT; break; + + default: { + std::stringstream ss; + ss << "Couldn't lex number, junk after decimal point: " << *c; + throw StaticError(filename, begin, ss.str()); + } } - } - break; - - case AFTER_DIGIT: - switch (*c) { - case 'e': case 'E': - state = AFTER_E; break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_DIGIT; + case AFTER_DIGIT: + switch (*c) { + case 'e': + case 'E': state = AFTER_E; break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_DIGIT; break; + + default: goto end; + } break; - default: - goto end; - } - break; - case AFTER_E: - switch (*c) { - case '+': case '-': - state = AFTER_EXP_SIGN; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_EXP_DIGIT; - break; - - default: { - std::stringstream ss; - ss << "Couldn't lex number, junk after 'E': " << *c; - throw StaticError(filename, begin, ss.str()); + switch (*c) { + case '+': + case '-': state = AFTER_EXP_SIGN; break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_EXP_DIGIT; break; + + default: { + std::stringstream ss; + ss << "Couldn't lex number, junk after 'E': " << *c; + throw StaticError(filename, begin, ss.str()); + } } - } - break; - - case AFTER_EXP_SIGN: - switch (*c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_EXP_DIGIT; break; - default: { - std::stringstream ss; - ss << "Couldn't lex number, junk after exponent sign: " << *c; - throw StaticError(filename, begin, ss.str()); + case AFTER_EXP_SIGN: + switch (*c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_EXP_DIGIT; break; + + default: { + std::stringstream ss; + ss << "Couldn't lex number, junk after exponent sign: " << *c; + throw StaticError(filename, begin, ss.str()); + } } - } - break; + break; case AFTER_EXP_DIGIT: - switch (*c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - state = AFTER_EXP_DIGIT; + switch (*c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = AFTER_EXP_DIGIT; break; + + default: goto end; + } break; - - default: - goto end; - } - break; } r += *c; c++; } - end: +end: return r; } @@ -348,7 +380,8 @@ static int whitespace_check(const char *a, const char *b) { int i = 0; while (a[i] == ' ' || a[i] == '\t') { - if (b[i] != a[i]) return 0; + if (b[i] != a[i]) + return 0; i++; } return i; @@ -378,8 +411,7 @@ Tokens jsonnet_lex(const std::string &filename, const char *input) Fodder fodder; bool fresh_line = true; // Are we tokenizing from the beginning of a new line? - while (*c!='\0') { - + while (*c != '\0') { // Used to ensure we have actually advanced the pointer by the end of the iteration. const char *original_c = c; @@ -405,111 +437,116 @@ Tokens jsonnet_lex(const std::string &filename, const char *input) Location begin(line_number, c - line_start + 1); switch (*c) { - // The following operators should never be combined with subsequent symbols. case '{': - kind = Token::BRACE_L; - c++; - break; + kind = Token::BRACE_L; + c++; + break; case '}': - kind = Token::BRACE_R; - c++; - break; + kind = Token::BRACE_R; + c++; + break; case '[': - kind = Token::BRACKET_L; - c++; - break; + kind = Token::BRACKET_L; + c++; + break; case ']': - kind = Token::BRACKET_R; - c++; - break; + kind = Token::BRACKET_R; + c++; + break; case ',': - kind = Token::COMMA; - c++; - break; + kind = Token::COMMA; + c++; + break; case '.': - kind = Token::DOT; - c++; - break; + kind = Token::DOT; + c++; + break; case '(': - kind = Token::PAREN_L; - c++; - break; + kind = Token::PAREN_L; + c++; + break; case ')': - kind = Token::PAREN_R; - c++; - break; + kind = Token::PAREN_R; + c++; + break; case ';': - kind = Token::SEMICOLON; - c++; - break; + kind = Token::SEMICOLON; + c++; + break; // Numeric literals. - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - kind = Token::NUMBER; - data = lex_number(c, filename, begin); - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + kind = Token::NUMBER; + data = lex_number(c, filename, begin); + break; // UString literals. case '"': { c++; - for (; ; ++c) { + for (;; ++c) { if (*c == '\0') { throw StaticError(filename, begin, "Unterminated string"); } if (*c == '"') { break; } - if (*c == '\\' && *(c+1) != '\0') { + if (*c == '\\' && *(c + 1) != '\0') { data += *c; ++c; } if (*c == '\n') { // Maintain line/column counters. line_number++; - line_start = c+1; + line_start = c + 1; } data += *c; } c++; // Advance beyond the ". kind = Token::STRING_DOUBLE; - } - break; + } break; // UString literals. case '\'': { c++; - for (; ; ++c) { + for (;; ++c) { if (*c == '\0') { throw StaticError(filename, begin, "Unterminated string"); } if (*c == '\'') { break; } - if (*c == '\\' && *(c+1) != '\0') { + if (*c == '\\' && *(c + 1) != '\0') { data += *c; ++c; } if (*c == '\n') { // Maintain line/column counters. line_number++; - line_start = c+1; + line_start = c + 1; } data += *c; } c++; // Advance beyond the '. kind = Token::STRING_SINGLE; - } - break; + } break; // Verbatim string literals. // ' and " quoting is interpreted here, unlike non-verbatim strings @@ -526,16 +563,16 @@ Tokens jsonnet_lex(const std::string &filename, const char *input) } const char quot = *c; c++; // Advance beyond the opening quote. - for (; ; ++c) { - if (*c == '\0') { + for (;; ++c) { + if (*c == '\0') { throw StaticError(filename, begin, "Unterminated verbatim string"); } if (*c == quot) { - if (*(c+1) == quot) { - c++; - } else { - break; - } + if (*(c + 1) == quot) { + c++; + } else { + break; + } } data += *c; } @@ -545,197 +582,202 @@ Tokens jsonnet_lex(const std::string &filename, const char *input) } else { kind = Token::VERBATIM_STRING_SINGLE; } - } - break; + } break; // Keywords default: - if (is_identifier_first(*c)) { - std::string id; - for (; is_identifier(*c); ++c) - id += *c; - kind = lex_get_keyword_kind(id); - data = id; - - } else if (is_symbol(*c) || *c == '#') { - - // Single line C++ and Python style comments. - if (*c == '#' || (*c == '/' && *(c+1) == '/')) { - std::vector comment(1); - unsigned blanks; - unsigned indent; - lex_until_newline(c, comment[0], blanks, indent, line_start, line_number); - auto kind = fresh_line ? FodderElement::PARAGRAPH : FodderElement::LINE_END; - fodder.emplace_back(kind, blanks, indent, comment); - fresh_line = true; - continue; // We've not got a token, just fodder, so keep scanning. - } - - // Multi-line C style comment. - if (*c == '/' && *(c+1) == '*') { + if (is_identifier_first(*c)) { + std::string id; + for (; is_identifier(*c); ++c) + id += *c; + kind = lex_get_keyword_kind(id); + data = id; + + } else if (is_symbol(*c) || *c == '#') { + // Single line C++ and Python style comments. + if (*c == '#' || (*c == '/' && *(c + 1) == '/')) { + std::vector comment(1); + unsigned blanks; + unsigned indent; + lex_until_newline(c, comment[0], blanks, indent, line_start, line_number); + auto kind = fresh_line ? FodderElement::PARAGRAPH : FodderElement::LINE_END; + fodder.emplace_back(kind, blanks, indent, comment); + fresh_line = true; + continue; // We've not got a token, just fodder, so keep scanning. + } - unsigned margin = c - line_start; + // Multi-line C style comment. + if (*c == '/' && *(c + 1) == '*') { + unsigned margin = c - line_start; - const char *initial_c = c; - c += 2; // Avoid matching /*/: skip the /* before starting the search for */. + const char *initial_c = c; + c += 2; // Avoid matching /*/: skip the /* before starting the search for + // */. - while (!(*c == '*' && *(c+1) == '/')) { - if (*c == '\0') { - auto msg = "Multi-line comment has no terminating */."; - throw StaticError(filename, begin, msg); - } - if (*c == '\n') { - // Just keep track of the line / column counters. - line_number++; - line_start = c+1; - } - ++c; - } - c += 2; // Move the pointer to the char after the closing '/'. - - std::string comment(initial_c, c - initial_c); // Includes the "/*" and "*/". - - // Lex whitespace after comment - unsigned new_lines_after, indent_after; - lex_ws(c, new_lines_after, indent_after, line_start, line_number); - std::vector lines; - if (comment.find('\n') >= comment.length()) { - // Comment looks like /* foo */ - lines.push_back(comment); - fodder.emplace_back(FodderElement::INTERSTITIAL, 0, 0, lines); - if (new_lines_after > 0) { - fodder.emplace_back(FodderElement::LINE_END, new_lines_after - 1, - indent_after, EMPTY); - fresh_line = true; - } - } else { - lines = line_split(comment, margin); - assert(lines[0][0] == '/'); - // Little hack to support PARAGRAPHs with * down the LHS: - // Add a space to lines that start with a '*' - bool all_star = true; - for (auto &l : lines) { - if (l[0] != '*') - all_star = false; + while (!(*c == '*' && *(c + 1) == '/')) { + if (*c == '\0') { + auto msg = "Multi-line comment has no terminating */."; + throw StaticError(filename, begin, msg); + } + if (*c == '\n') { + // Just keep track of the line / column counters. + line_number++; + line_start = c + 1; + } + ++c; } - if (all_star) { + c += 2; // Move the pointer to the char after the closing '/'. + + std::string comment(initial_c, + c - initial_c); // Includes the "/*" and "*/". + + // Lex whitespace after comment + unsigned new_lines_after, indent_after; + lex_ws(c, new_lines_after, indent_after, line_start, line_number); + std::vector lines; + if (comment.find('\n') >= comment.length()) { + // Comment looks like /* foo */ + lines.push_back(comment); + fodder.emplace_back(FodderElement::INTERSTITIAL, 0, 0, lines); + if (new_lines_after > 0) { + fodder.emplace_back(FodderElement::LINE_END, + new_lines_after - 1, + indent_after, + EMPTY); + fresh_line = true; + } + } else { + lines = line_split(comment, margin); + assert(lines[0][0] == '/'); + // Little hack to support PARAGRAPHs with * down the LHS: + // Add a space to lines that start with a '*' + bool all_star = true; for (auto &l : lines) { - if (l[0] == '*') l = " " + l; + if (l[0] != '*') + all_star = false; } + if (all_star) { + for (auto &l : lines) { + if (l[0] == '*') + l = " " + l; + } + } + if (new_lines_after == 0) { + // Ensure a line end after the paragraph. + new_lines_after = 1; + indent_after = 0; + } + fodder_push_back(fodder, + FodderElement(FodderElement::PARAGRAPH, + new_lines_after - 1, + indent_after, + lines)); + fresh_line = true; } - if (new_lines_after == 0) { - // Ensure a line end after the paragraph. - new_lines_after = 1; - indent_after = 0; - } - fodder_push_back(fodder, - FodderElement(FodderElement::PARAGRAPH, - new_lines_after - 1, - indent_after, - lines)); - fresh_line = true; + continue; // We've not got a token, just fodder, so keep scanning. } - continue; // We've not got a token, just fodder, so keep scanning. - } - // Text block - if (*c == '|' && *(c+1) == '|' && *(c+2) == '|') { - if (*(c+3) != '\n') { - auto msg = "Text block syntax requires new line after |||."; - throw StaticError(filename, begin, msg); - } - std::stringstream block; - c += 4; // Skip the "|||\n" - line_number++; - // Skip any blank lines at the beginning of the block. - while (*c == '\n') { - line_number++; - ++c; - block << '\n'; - } - line_start = c; - const char *first_line = c; - int ws_chars = whitespace_check(first_line, c); - string_block_indent = std::string(first_line, ws_chars); - if (ws_chars == 0) { - auto msg = "Text block's first line must start with whitespace."; - throw StaticError(filename, begin, msg); - } - while (true) { - assert(ws_chars > 0); - // Read up to the \n - for (c = &c[ws_chars]; *c != '\n' ; ++c) { - if (*c == '\0') - throw StaticError(filename, begin, "Unexpected EOF"); - block << *c; + // Text block + if (*c == '|' && *(c + 1) == '|' && *(c + 2) == '|') { + if (*(c + 3) != '\n') { + auto msg = "Text block syntax requires new line after |||."; + throw StaticError(filename, begin, msg); } - // Add the \n - block << '\n'; - ++c; + std::stringstream block; + c += 4; // Skip the "|||\n" line_number++; - line_start = c; - // Skip any blank lines + // Skip any blank lines at the beginning of the block. while (*c == '\n') { line_number++; ++c; block << '\n'; } - // Examine next line - ws_chars = whitespace_check(first_line, c); + line_start = c; + const char *first_line = c; + int ws_chars = whitespace_check(first_line, c); + string_block_indent = std::string(first_line, ws_chars); if (ws_chars == 0) { - // End of text block - // Skip over any whitespace - while (*c == ' ' || *c == '\t') { - string_block_term_indent += *c; + auto msg = "Text block's first line must start with whitespace."; + throw StaticError(filename, begin, msg); + } + while (true) { + assert(ws_chars > 0); + // Read up to the \n + for (c = &c[ws_chars]; *c != '\n'; ++c) { + if (*c == '\0') + throw StaticError(filename, begin, "Unexpected EOF"); + block << *c; + } + // Add the \n + block << '\n'; + ++c; + line_number++; + line_start = c; + // Skip any blank lines + while (*c == '\n') { + line_number++; ++c; + block << '\n'; } - // Expect ||| - if (!(*c == '|' && *(c+1) == '|' && *(c+2) == '|')) { - auto msg = "Text block not terminated with |||"; - throw StaticError(filename, begin, msg); + // Examine next line + ws_chars = whitespace_check(first_line, c); + if (ws_chars == 0) { + // End of text block + // Skip over any whitespace + while (*c == ' ' || *c == '\t') { + string_block_term_indent += *c; + ++c; + } + // Expect ||| + if (!(*c == '|' && *(c + 1) == '|' && *(c + 2) == '|')) { + auto msg = "Text block not terminated with |||"; + throw StaticError(filename, begin, msg); + } + c += 3; // Leave after the last | + data = block.str(); + kind = Token::STRING_BLOCK; + break; // Out of the while loop. } - c += 3; // Leave after the last | - data = block.str(); - kind = Token::STRING_BLOCK; - break; // Out of the while loop. } - } - break; // Out of the switch. - } + break; // Out of the switch. + } - const char *operator_begin = c; - for (; is_symbol(*c) ; ++c) { - // Not allowed // in operators - if (*c == '/' && *(c+1) == '/') break; - // Not allowed /* in operators - if (*c == '/' && *(c+1) == '*') break; - // Not allowed ||| in operators - if (*c == '|' && *(c+1) == '|' && *(c+2) == '|') break; - } - // Not allowed to end with a + - ~ ! unless a single char. - // So, wind it back if we need to (but not too far). - while (c > operator_begin + 1 - && (*(c-1) == '+' || *(c-1) == '-' || *(c-1) == '~' || *(c-1) == '!')) { - c--; - } - data += std::string(operator_begin, c); - if (data == "$") { - kind = Token::DOLLAR; - data = ""; + const char *operator_begin = c; + for (; is_symbol(*c); ++c) { + // Not allowed // in operators + if (*c == '/' && *(c + 1) == '/') + break; + // Not allowed /* in operators + if (*c == '/' && *(c + 1) == '*') + break; + // Not allowed ||| in operators + if (*c == '|' && *(c + 1) == '|' && *(c + 2) == '|') + break; + } + // Not allowed to end with a + - ~ ! unless a single char. + // So, wind it back if we need to (but not too far). + while (c > operator_begin + 1 && (*(c - 1) == '+' || *(c - 1) == '-' || + *(c - 1) == '~' || *(c - 1) == '!')) { + c--; + } + data += std::string(operator_begin, c); + if (data == "$") { + kind = Token::DOLLAR; + data = ""; + } else { + kind = Token::OPERATOR; + } } else { - kind = Token::OPERATOR; + std::stringstream ss; + ss << "Could not lex the character "; + auto uc = (unsigned char)(*c); + if (*c < 32) + ss << "code " << unsigned(uc); + else + ss << "'" << *c << "'"; + throw StaticError(filename, begin, ss.str()); } - } else { - std::stringstream ss; - ss << "Could not lex the character "; - auto uc = (unsigned char)(*c); - if (*c < 32) - ss << "code " << unsigned(uc); - else - ss << "'" << *c << "'"; - throw StaticError(filename, begin, ss.str()); - } } // Ensure that a bug in the above code does not cause an infinite memory consuming loop due @@ -745,7 +787,11 @@ Tokens jsonnet_lex(const std::string &filename, const char *input) } Location end(line_number, c - line_start); - r.emplace_back(kind, fodder, data, string_block_indent, string_block_term_indent, + r.emplace_back(kind, + fodder, + data, + string_block_indent, + string_block_term_indent, LocationRange(filename, begin, end)); fodder.clear(); fresh_line = false; @@ -764,8 +810,8 @@ std::string jsonnet_unlex(const Tokens &tokens) switch (f.kind) { case FodderElement::LINE_END: { if (f.comment.size() > 0) { - ss << "LineEnd(" << f.blanks << ", " << f.indent << ", " - << f.comment[0] << ")\n"; + ss << "LineEnd(" << f.blanks << ", " << f.indent << ", " << f.comment[0] + << ")\n"; } else { ss << "LineEnd(" << f.blanks << ", " << f.indent << ")\n"; } @@ -795,7 +841,7 @@ std::string jsonnet_unlex(const Tokens &tokens) } else if (t.kind == Token::STRING_BLOCK) { ss << "|||\n"; ss << t.stringBlockIndent; - for (const char *cp = t.data.c_str() ; *cp != '\0' ; ++cp) { + for (const char *cp = t.data.c_str(); *cp != '\0'; ++cp) { ss << *cp; if (*cp == '\n' && *(cp + 1) != '\n' && *(cp + 1) != '\0') { ss << t.stringBlockIndent; diff --git a/core/lexer.h b/core/lexer.h index aa61ee3cd..839199ea7 100644 --- a/core/lexer.h +++ b/core/lexer.h @@ -17,17 +17,17 @@ limitations under the License. #ifndef JSONNET_LEXER_H #define JSONNET_LEXER_H -#include #include +#include #include -#include #include #include +#include #include -#include "unicode.h" #include "static_error.h" +#include "unicode.h" /** Whitespace and comments. * @@ -60,8 +60,8 @@ struct FodderElement { * // and # style commes have exactly one line. C-style comments can have more than one * line. * - * All lines of the comment are indented according to the indentation level of the previous new line - * / paragraph fodder. + * All lines of the comment are indented according to the indentation level of the previous + * new line / paragraph fodder. * * The PARAGRAPH fodder specifies the indentation level and vertical spacing before whatever * comes next. @@ -87,7 +87,7 @@ struct FodderElement { FodderElement(Kind kind, unsigned blanks, unsigned indent, const std::vector &comment) - : kind(kind), blanks(blanks), indent(indent), comment(comment) + : kind(kind), blanks(blanks), indent(indent), comment(comment) { assert(kind != LINE_END || comment.size() <= 1); assert(kind != INTERSTITIAL || (blanks == 0 && indent == 0 && comment.size() == 1)); @@ -99,18 +99,18 @@ static inline std::ostream &operator<<(std::ostream &o, const FodderElement &f) { switch (f.kind) { case FodderElement::LINE_END: - o << "END(" << f.blanks << ", " << f.indent; - if (!f.comment.empty()) { - o << ", " << f.comment[0]; - } - o << ")"; - break; + o << "END(" << f.blanks << ", " << f.indent; + if (!f.comment.empty()) { + o << ", " << f.comment[0]; + } + o << ")"; + break; case FodderElement::INTERSTITIAL: - o << "INT(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << ")"; - break; + o << "INT(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << ")"; + break; case FodderElement::PARAGRAPH: - o << "PAR(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << "...)"; - break; + o << "PAR(" << f.blanks << ", " << f.indent << ", " << f.comment[0] << "...)"; + break; } return o; } @@ -128,7 +128,8 @@ static inline std::ostream &operator<<(std::ostream &o, const FodderElement &f) */ typedef std::vector Fodder; -static inline bool fodder_has_clean_endline(const Fodder &fodder) { +static inline bool fodder_has_clean_endline(const Fodder &fodder) +{ return !fodder.empty() && fodder.back().kind != FodderElement::INTERSTITIAL; } @@ -161,13 +162,15 @@ static inline void fodder_push_back(Fodder &a, const FodderElement &elem) */ static inline Fodder concat_fodder(const Fodder &a, const Fodder &b) { - if (a.size() == 0) return b; - if (b.size() == 0) return a; + if (a.size() == 0) + return b; + if (b.size() == 0) + return a; Fodder r = a; // Carefully add the first element of b. fodder_push_back(r, b[0]); // Add the rest of b. - for (unsigned i = 1; i < b.size() ; ++i) { + for (unsigned i = 1; i < b.size(); ++i) { r.push_back(b[i]); } return r; @@ -197,12 +200,9 @@ static inline void ensureCleanNewline(Fodder &fodder) static inline int countNewlines(const FodderElement &elem) { switch (elem.kind) { - case FodderElement::INTERSTITIAL: - return 0; - case FodderElement::LINE_END: - return 1; - case FodderElement::PARAGRAPH: - return elem.comment.size() + elem.blanks; + case FodderElement::INTERSTITIAL: return 0; + case FodderElement::LINE_END: return 1; + case FodderElement::PARAGRAPH: return elem.comment.size() + elem.blanks; } std::cerr << "Unknown FodderElement kind" << std::endl; abort(); @@ -211,7 +211,7 @@ static inline int countNewlines(const FodderElement &elem) static inline int countNewlines(const Fodder &fodder) { int sum = 0; - for (const auto &elem: fodder) { + for (const auto &elem : fodder) { sum += countNewlines(elem); } return sum; @@ -292,19 +292,26 @@ struct Token { */ std::string stringBlockTermIndent; - UString data32(void) { return decode_utf8(data); } + UString data32(void) + { + return decode_utf8(data); + } LocationRange location; Token(Kind kind, const Fodder &fodder, const std::string &data, const std::string &string_block_indent, const std::string &string_block_term_indent, const LocationRange &location) - : kind(kind), fodder(fodder), data(data), stringBlockIndent(string_block_indent), - stringBlockTermIndent(string_block_term_indent), location(location) - { } + : kind(kind), + fodder(fodder), + data(data), + stringBlockIndent(string_block_indent), + stringBlockTermIndent(string_block_term_indent), + location(location) + { + } - Token(Kind kind, const std::string &data="") - : kind(kind), data(data) { } + Token(Kind kind, const std::string &data = "") : kind(kind), data(data) {} static const char *toString(Kind v) { @@ -350,8 +357,8 @@ struct Token { case END_OF_FILE: return "end of file"; default: - std::cerr << "INTERNAL ERROR: Unknown token kind: " << v << std::endl; - std::abort(); + std::cerr << "INTERNAL ERROR: Unknown token kind: " << v << std::endl; + std::abort(); } } }; @@ -365,8 +372,10 @@ typedef std::list Tokens; static inline bool operator==(const Token &a, const Token &b) { - if (a.kind != b.kind) return false; - if (a.data != b.data) return false; + if (a.kind != b.kind) + return false; + if (a.data != b.data) + return false; return true; } @@ -381,7 +390,7 @@ static inline std::ostream &operator<<(std::ostream &o, const Token &v) if (v.data == "") { o << Token::toString(v.kind); } else if (v.kind == Token::OPERATOR) { - o << "\"" << v.data << "\""; + o << "\"" << v.data << "\""; } else { o << "(" << Token::toString(v.kind) << ", \"" << v.data << "\")"; } diff --git a/core/lexer_test.cpp b/core/lexer_test.cpp index 92c11005f..2d454ced2 100644 --- a/core/lexer_test.cpp +++ b/core/lexer_test.cpp @@ -21,9 +21,7 @@ limitations under the License. namespace { -void testLex(const char* name, - const char* input, - const std::list& tokens, +void testLex(const char* name, const char* input, const std::list& tokens, const std::string& error) { std::list test_tokens(tokens); @@ -31,8 +29,7 @@ void testLex(const char* name, try { std::list lexed_tokens = jsonnet_lex(name, input); - ASSERT_EQ(test_tokens, lexed_tokens) - << "Test failed: " << name << std::endl; + ASSERT_EQ(test_tokens, lexed_tokens) << "Test failed: " << name << std::endl; } catch (StaticError& e) { ASSERT_EQ(error, e.toString()); } @@ -54,9 +51,10 @@ TEST(Lexer, TestOperators) testLex("colon 2", "::", {Token(Token::Kind::OPERATOR, "::")}, ""); testLex("colon 2", ":::", {Token(Token::Kind::OPERATOR, ":::")}, ""); testLex("arrow right", "->", {Token(Token::Kind::OPERATOR, "->")}, ""); - testLex("less than minus", "<-", - {Token(Token::Kind::OPERATOR, "<"), - Token(Token::Kind::OPERATOR, "-")}, ""); + testLex("less than minus", + "<-", + {Token(Token::Kind::OPERATOR, "<"), Token(Token::Kind::OPERATOR, "-")}, + ""); testLex("comma", ",", {Token(Token::Kind::COMMA, "")}, ""); testLex("dollar", "$", {Token(Token::Kind::DOLLAR, "")}, ""); testLex("dot", ".", {Token(Token::Kind::DOT, "")}, ""); @@ -97,79 +95,106 @@ TEST(Lexer, TestNumbers) testLex("number 1.1e100", "1.1e100", {Token(Token::Kind::NUMBER, "1.1e100")}, ""); testLex("number 1.1e-100", "1.1e-100", {Token(Token::Kind::NUMBER, "1.1e-100")}, ""); testLex("number 1.1e+100", "1.1e+100", {Token(Token::Kind::NUMBER, "1.1e+100")}, ""); - testLex("number 0100", "0100", + testLex("number 0100", + "0100", {Token(Token::Kind::NUMBER, "0"), Token(Token::Kind::NUMBER, "100")}, ""); - testLex("number 10+10", "10+10", + testLex("number 10+10", + "10+10", {Token(Token::Kind::NUMBER, "10"), Token(Token::Kind::OPERATOR, "+"), - Token(Token::Kind::NUMBER, "10")}, ""); - testLex("number 1.+3", "1.+3", {}, + Token(Token::Kind::NUMBER, "10")}, + ""); + testLex("number 1.+3", + "1.+3", + {}, "number 1.+3:1:1: Couldn't lex number, junk after decimal point: +"); - testLex("number 1e!", "1e!", {}, - "number 1e!:1:1: Couldn't lex number, junk after 'E': !"); - testLex("number 1e+!", "1e+!", {}, + testLex("number 1e!", "1e!", {}, "number 1e!:1:1: Couldn't lex number, junk after 'E': !"); + testLex("number 1e+!", + "1e+!", + {}, "number 1e+!:1:1: Couldn't lex number, junk after exponent sign: !"); } TEST(Lexer, TestDoubleStrings) { - testLex("double string \"hi\"", - "\"hi\"", {Token(Token::Kind::STRING_DOUBLE, "hi")}, ""); - testLex("double string \"hi nl\"", - "\"hi\n\"", {Token(Token::Kind::STRING_DOUBLE, "hi\n")}, ""); + testLex("double string \"hi\"", "\"hi\"", {Token(Token::Kind::STRING_DOUBLE, "hi")}, ""); + testLex("double string \"hi nl\"", "\"hi\n\"", {Token(Token::Kind::STRING_DOUBLE, "hi\n")}, ""); testLex("double string \"hi\\\"\"", - "\"hi\\\"\"", {Token(Token::Kind::STRING_DOUBLE, "hi\\\"")}, ""); + "\"hi\\\"\"", + {Token(Token::Kind::STRING_DOUBLE, "hi\\\"")}, + ""); testLex("double string \"hi\\nl\"", - "\"hi\\\n\"", {Token(Token::Kind::STRING_DOUBLE, "hi\\\n")}, ""); - testLex("double string \"hi", - "\"hi", {}, "double string \"hi:1:1: Unterminated string"); + "\"hi\\\n\"", + {Token(Token::Kind::STRING_DOUBLE, "hi\\\n")}, + ""); + testLex("double string \"hi", "\"hi", {}, "double string \"hi:1:1: Unterminated string"); } TEST(Lexer, TestSingleStrings) { - testLex("single string 'hi'", - "'hi'", {Token(Token::Kind::STRING_SINGLE, "hi")}, ""); - testLex("single string 'hi nl'", - "'hi\n'", {Token(Token::Kind::STRING_SINGLE, "hi\n")}, ""); - testLex("single string 'hi\\''", - "'hi\\''", {Token(Token::Kind::STRING_SINGLE, "hi\\'")}, ""); - testLex("single string 'hi\\nl'", - "'hi\\\n'", {Token(Token::Kind::STRING_SINGLE, "hi\\\n")}, ""); - testLex("single string 'hi", - "'hi", {}, "single string 'hi:1:1: Unterminated string"); + testLex("single string 'hi'", "'hi'", {Token(Token::Kind::STRING_SINGLE, "hi")}, ""); + testLex("single string 'hi nl'", "'hi\n'", {Token(Token::Kind::STRING_SINGLE, "hi\n")}, ""); + testLex("single string 'hi\\''", "'hi\\''", {Token(Token::Kind::STRING_SINGLE, "hi\\'")}, ""); + testLex( + "single string 'hi\\nl'", "'hi\\\n'", {Token(Token::Kind::STRING_SINGLE, "hi\\\n")}, ""); + testLex("single string 'hi", "'hi", {}, "single string 'hi:1:1: Unterminated string"); } TEST(Lexer, TestVerbatimDoubleStrings) { testLex("verbatim double string @\"hi\"", - "@\"hi\"", {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi")}, ""); + "@\"hi\"", + {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi")}, + ""); testLex("verbatim double string @\"hi nl\"", - "@\"hi\n\"", {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\n")}, ""); + "@\"hi\n\"", + {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\n")}, + ""); testLex("verbatim double string @\"hi\\\"", - "@\"hi\\\"", {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\\")}, ""); + "@\"hi\\\"", + {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\\")}, + ""); testLex("verbatim double string @\"hi\\\\\"", - "@\"hi\\\\\"", {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\\\\")}, ""); + "@\"hi\\\\\"", + {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\\\\")}, + ""); testLex("verbatim double string @\"hi\"\"\"", - "@\"hi\"\"\"", {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\"")}, ""); + "@\"hi\"\"\"", + {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "hi\"")}, + ""); testLex("verbatim double string @\"\"\"hi\"", - "@\"\"\"hi\"", {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "\"hi")}, ""); + "@\"\"\"hi\"", + {Token(Token::Kind::VERBATIM_STRING_DOUBLE, "\"hi")}, + ""); } TEST(Lexer, TestVerbatimSingleStrings) { testLex("verbatim single string @'hi'", - "@'hi'", {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi")}, ""); + "@'hi'", + {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi")}, + ""); testLex("verbatim single string @'hi nl'", - "@'hi\n'", {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi\n")}, ""); + "@'hi\n'", + {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi\n")}, + ""); testLex("verbatim single string @'hi\\'", - "@'hi\\'", {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi\\")}, ""); + "@'hi\\'", + {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi\\")}, + ""); testLex("verbatim single string @'hi\\\\'", - "@'hi\\\\'", {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi\\\\")}, ""); + "@'hi\\\\'", + {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi\\\\")}, + ""); testLex("verbatim single string @'hi'''", - "@'hi'''", {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi'")}, ""); + "@'hi'''", + {Token(Token::Kind::VERBATIM_STRING_SINGLE, "hi'")}, + ""); testLex("verbatim single string @'''hi'", - "@'''hi'", {Token(Token::Kind::VERBATIM_STRING_SINGLE, "'hi")}, ""); + "@'''hi'", + {Token(Token::Kind::VERBATIM_STRING_SINGLE, "'hi")}, + ""); } TEST(Lexer, TestBlockStringSpaces) @@ -181,13 +206,8 @@ TEST(Lexer, TestBlockStringSpaces) " |||\n" " foo\n" "|||"; - const Token token = Token( - Token::Kind::STRING_BLOCK, - {}, - "test\n more\n|||\n foo\n", - " ", - "", - {}); + const Token token = + Token(Token::Kind::STRING_BLOCK, {}, "test\n more\n|||\n foo\n", " ", "", {}); testLex("block string spaces", str, {token}, ""); } @@ -200,13 +220,8 @@ TEST(Lexer, TestBlockStringTabs) "\t|||\n" "\t foo\n" "|||"; - const Token token = Token( - Token::Kind::STRING_BLOCK, - {}, - "test\n more\n|||\n foo\n", - "\t", - "", - {}); + const Token token = + Token(Token::Kind::STRING_BLOCK, {}, "test\n more\n|||\n foo\n", "\t", "", {}); testLex("block string tabs", str, {token}, ""); } @@ -219,13 +234,8 @@ TEST(Lexer, TestBlockStringsMixed) "\t \t|||\n" "\t \t foo\n" "|||"; - const Token token = Token( - Token::Kind::STRING_BLOCK, - {}, - "test\n more\n|||\n foo\n", - "\t \t", - "", - {}); + const Token token = + Token(Token::Kind::STRING_BLOCK, {}, "test\n more\n|||\n foo\n", "\t \t", "", {}); testLex("block string mixed", str, {token}, ""); } @@ -238,13 +248,8 @@ TEST(Lexer, TestBlockStringBlanks) " |||\n" " foo\n" "|||"; - const Token token = Token( - Token::Kind::STRING_BLOCK, - {}, - "\ntest\n\n\n more\n|||\n foo\n", - " ", - "", - {}); + const Token token = + Token(Token::Kind::STRING_BLOCK, {}, "\ntest\n\n\n more\n|||\n foo\n", " ", "", {}); testLex("block string blanks", str, {token}, ""); } @@ -255,7 +260,9 @@ TEST(Lexer, TestBlockStringBadIndent) " test\n" " foo\n" "|||"; - testLex("block string bad indent", str, {}, + testLex("block string bad indent", + str, + {}, "block string bad indent:1:1: Text block not terminated with |||"); } @@ -272,7 +279,9 @@ TEST(Lexer, TestBlockStringNotTerm) const char str[] = "|||\n" " test\n"; - testLex("block string not term", str, {}, + testLex("block string not term", + str, + {}, "block string not term:1:1: Text block not terminated with |||"); } @@ -282,7 +291,9 @@ TEST(Lexer, TestBlockStringNoWs) "|||\n" "test\n" "|||"; - testLex("block string no ws", str, {}, + testLex("block string no ws", + str, + {}, "block string no ws:1:1: Text block's first line must start with" " whitespace."); } @@ -311,9 +322,10 @@ TEST(Lexer, TestKeywords) TEST(Lexer, TestIdentifier) { testLex("identifier", "foobar123", {Token(Token::Kind::IDENTIFIER, "foobar123")}, ""); - testLex("identifier", "foo bar123", - {Token(Token::Kind::IDENTIFIER, "foo"), - Token(Token::Kind::IDENTIFIER, "bar123")}, ""); + testLex("identifier", + "foo bar123", + {Token(Token::Kind::IDENTIFIER, "foo"), Token(Token::Kind::IDENTIFIER, "bar123")}, + ""); } TEST(Lexer, TestComments) @@ -322,7 +334,9 @@ TEST(Lexer, TestComments) testLex("c++ comment", "// hi", {}, ""); testLex("hash comment", "# hi", {}, ""); testLex("c comment", "/* hi */", {}, ""); - testLex("c comment no term", "/* hi", {}, + testLex("c comment no term", + "/* hi", + {}, "c comment no term:1:1: Multi-line comment has no terminating */."); } diff --git a/core/libjsonnet.cpp b/core/libjsonnet.cpp index a29582b84..d614c5ab8 100644 --- a/core/libjsonnet.cpp +++ b/core/libjsonnet.cpp @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include #include #include -#include #include #include @@ -41,7 +41,7 @@ static void memory_panic(void) abort(); } -static char *from_string(JsonnetVm* vm, const std::string &v) +static char *from_string(JsonnetVm *vm, const std::string &v) { char *r = jsonnet_realloc(vm, nullptr, v.length() + 1); std::strcpy(r, v.c_str()); @@ -53,7 +53,7 @@ static char *default_import_callback(void *ctx, const char *dir, const char *fil const char *jsonnet_json_extract_string(JsonnetVm *vm, const struct JsonnetJsonValue *v) { - (void) vm; + (void)vm; if (v->kind != JsonnetJsonValue::STRING) return nullptr; return v->string.c_str(); @@ -61,7 +61,7 @@ const char *jsonnet_json_extract_string(JsonnetVm *vm, const struct JsonnetJsonV int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonValue *v, double *out) { - (void) vm; + (void)vm; if (v->kind != JsonnetJsonValue::NUMBER) return 0; *out = v->number; @@ -70,20 +70,21 @@ int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonVa int jsonnet_json_extract_bool(struct JsonnetVm *vm, const struct JsonnetJsonValue *v) { - (void) vm; - if (v->kind != JsonnetJsonValue::BOOL) return 2; + (void)vm; + if (v->kind != JsonnetJsonValue::BOOL) + return 2; return v->number != 0; } int jsonnet_json_extract_null(struct JsonnetVm *vm, const struct JsonnetJsonValue *v) { - (void) vm; + (void)vm; return v->kind == JsonnetJsonValue::NULL_KIND; } JsonnetJsonValue *jsonnet_json_make_string(JsonnetVm *vm, const char *v) { - (void) vm; + (void)vm; JsonnetJsonValue *r = new JsonnetJsonValue(); r->kind = JsonnetJsonValue::STRING; r->string = v; @@ -92,7 +93,7 @@ JsonnetJsonValue *jsonnet_json_make_string(JsonnetVm *vm, const char *v) JsonnetJsonValue *jsonnet_json_make_number(struct JsonnetVm *vm, double v) { - (void) vm; + (void)vm; JsonnetJsonValue *r = new JsonnetJsonValue(); r->kind = JsonnetJsonValue::NUMBER; r->number = v; @@ -101,7 +102,7 @@ JsonnetJsonValue *jsonnet_json_make_number(struct JsonnetVm *vm, double v) JsonnetJsonValue *jsonnet_json_make_bool(struct JsonnetVm *vm, int v) { - (void) vm; + (void)vm; JsonnetJsonValue *r = new JsonnetJsonValue(); r->kind = JsonnetJsonValue::BOOL; r->number = v != 0; @@ -110,7 +111,7 @@ JsonnetJsonValue *jsonnet_json_make_bool(struct JsonnetVm *vm, int v) JsonnetJsonValue *jsonnet_json_make_null(struct JsonnetVm *vm) { - (void) vm; + (void)vm; JsonnetJsonValue *r = new JsonnetJsonValue(); r->kind = JsonnetJsonValue::NULL_KIND; return r; @@ -118,7 +119,7 @@ JsonnetJsonValue *jsonnet_json_make_null(struct JsonnetVm *vm) JsonnetJsonValue *jsonnet_json_make_array(JsonnetVm *vm) { - (void) vm; + (void)vm; JsonnetJsonValue *r = new JsonnetJsonValue(); r->kind = JsonnetJsonValue::ARRAY; return r; @@ -126,30 +127,30 @@ JsonnetJsonValue *jsonnet_json_make_array(JsonnetVm *vm) void jsonnet_json_array_append(JsonnetVm *vm, JsonnetJsonValue *arr, JsonnetJsonValue *v) { - (void) vm; + (void)vm; assert(arr->kind == JsonnetJsonValue::ARRAY); arr->elements.emplace_back(v); } JsonnetJsonValue *jsonnet_json_make_object(JsonnetVm *vm) { - (void) vm; + (void)vm; JsonnetJsonValue *r = new JsonnetJsonValue(); r->kind = JsonnetJsonValue::OBJECT; return r; } -void jsonnet_json_object_append(JsonnetVm *vm, JsonnetJsonValue *obj, - const char *f, JsonnetJsonValue *v) +void jsonnet_json_object_append(JsonnetVm *vm, JsonnetJsonValue *obj, const char *f, + JsonnetJsonValue *v) { - (void) vm; + (void)vm; assert(obj->kind == JsonnetJsonValue::OBJECT); obj->fields[std::string(f)] = std::unique_ptr(v); } void jsonnet_json_destroy(JsonnetVm *vm, JsonnetJsonValue *v) { - (void) vm; + (void)vm; delete v; } @@ -170,20 +171,21 @@ struct JsonnetVm { bool fmtDebugDesugaring; JsonnetVm(void) - : gcGrowthTrigger(2.0), maxStack(500), gcMinObjects(1000), maxTrace(20), - importCallback(default_import_callback), importCallbackContext(this), stringOutput(false), - fmtDebugDesugaring(false) + : gcGrowthTrigger(2.0), + maxStack(500), + gcMinObjects(1000), + maxTrace(20), + importCallback(default_import_callback), + importCallbackContext(this), + stringOutput(false), + fmtDebugDesugaring(false) { jpaths.emplace_back("/usr/share/" + std::string(jsonnet_version()) + "/"); jpaths.emplace_back("/usr/local/share/" + std::string(jsonnet_version()) + "/"); } }; -enum ImportStatus { - IMPORT_STATUS_OK, - IMPORT_STATUS_FILE_NOT_FOUND, - IMPORT_STATUS_IO_ERROR -}; +enum ImportStatus { IMPORT_STATUS_OK, IMPORT_STATUS_FILE_NOT_FOUND, IMPORT_STATUS_IO_ERROR }; static enum ImportStatus try_path(const std::string &dir, const std::string &rel, std::string &content, std::string &found_here, @@ -208,7 +210,8 @@ static enum ImportStatus try_path(const std::string &dir, const std::string &rel std::ifstream f; f.open(abs_path.c_str()); - if (!f.good()) return IMPORT_STATUS_FILE_NOT_FOUND; + if (!f.good()) + return IMPORT_STATUS_FILE_NOT_FOUND; try { content.assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); } catch (const std::ios_base::failure &io_err) { @@ -228,7 +231,7 @@ static enum ImportStatus try_path(const std::string &dir, const std::string &rel static char *default_import_callback(void *ctx, const char *dir, const char *file, char **found_here_cptr, int *success) { - auto *vm = static_cast(ctx); + auto *vm = static_cast(ctx); std::string input, found_here, err_msg; @@ -261,13 +264,17 @@ static char *default_import_callback(void *ctx, const char *dir, const char *fil } #define TRY try { -#define CATCH(func) \ - } catch (const std::bad_alloc &) {\ - memory_panic(); \ - } catch (const std::exception &e) {\ - std::cerr << "Something went wrong during " func ", please report this: " \ - << e.what() << std::endl; \ - abort(); \ +#define CATCH(func) \ + } \ + catch (const std::bad_alloc &) \ + { \ + memory_panic(); \ + } \ + catch (const std::exception &e) \ + { \ + std::cerr << "Something went wrong during " func ", please report this: " << e.what() \ + << std::endl; \ + abort(); \ } const char *jsonnet_version(void) @@ -278,7 +285,7 @@ const char *jsonnet_version(void) JsonnetVm *jsonnet_make(void) { TRY - return new JsonnetVm(); + return new JsonnetVm(); CATCH("jsonnet_make") return nullptr; } @@ -286,7 +293,7 @@ JsonnetVm *jsonnet_make(void) void jsonnet_destroy(JsonnetVm *vm) { TRY - delete vm; + delete vm; CATCH("jsonnet_destroy") } @@ -317,15 +324,14 @@ void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, vo } void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNativeCallback *cb, - void *ctx, const char * const *params) + void *ctx, const char *const *params) { std::vector params2; for (; *params != nullptr; params++) params2.push_back(*params); - vm->nativeCallbacks[name] = VmNativeCallback {cb, ctx, params2}; + vm->nativeCallbacks[name] = VmNativeCallback{cb, ctx, params2}; } - void jsonnet_ext_var(JsonnetVm *vm, const char *key, const char *val) { vm->ext[key] = VmExt(val, false); @@ -402,9 +408,11 @@ void jsonnet_max_trace(JsonnetVm *vm, unsigned v) void jsonnet_jpath_add(JsonnetVm *vm, const char *path_) { - if (std::strlen(path_) == 0) return; + if (std::strlen(path_) == 0) + return; std::string path = path_; - if (path[path.length() - 1] != '/') path += '/'; + if (path[path.length() - 1] != '/') + path += '/'; vm->jpaths.emplace_back(path); } @@ -439,7 +447,6 @@ static char *jsonnet_fmt_snippet_aux(JsonnetVm *vm, const char *filename, const *error = true; return from_string(vm, ss.str()); } - } char *jsonnet_fmt_file(JsonnetVm *vm, const char *filename, int *error) @@ -454,8 +461,7 @@ char *jsonnet_fmt_file(JsonnetVm *vm, const char *filename, int *error) return from_string(vm, ss.str()); } std::string input; - input.assign(std::istreambuf_iterator(f), - std::istreambuf_iterator()); + input.assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); return jsonnet_fmt_snippet_aux(vm, filename, input.c_str(), error); CATCH("jsonnet_fmt_file") @@ -470,13 +476,12 @@ char *jsonnet_fmt_snippet(JsonnetVm *vm, const char *filename, const char *snipp return nullptr; // Never happens. } - namespace { enum EvalKind { REGULAR, MULTI, STREAM }; } // namespace -static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, - const char *snippet, int *error, EvalKind kind) +static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, const char *snippet, + int *error, EvalKind kind) { try { Allocator alloc; @@ -490,28 +495,41 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, jsonnet_static_analysis(expr); switch (kind) { case REGULAR: { - std::string json_str = jsonnet_vm_execute( - &alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects, - vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback, - vm->importCallbackContext, vm->stringOutput); + std::string json_str = jsonnet_vm_execute(&alloc, + expr, + vm->ext, + vm->maxStack, + vm->gcMinObjects, + vm->gcGrowthTrigger, + vm->nativeCallbacks, + vm->importCallback, + vm->importCallbackContext, + vm->stringOutput); json_str += "\n"; *error = false; return from_string(vm, json_str); - } - break; + } break; case MULTI: { - std::map files = jsonnet_vm_execute_multi( - &alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects, - vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback, - vm->importCallbackContext, vm->stringOutput); - size_t sz = 1; // final sentinel + std::map files = + jsonnet_vm_execute_multi(&alloc, + expr, + vm->ext, + vm->maxStack, + vm->gcMinObjects, + vm->gcGrowthTrigger, + vm->nativeCallbacks, + vm->importCallback, + vm->importCallbackContext, + vm->stringOutput); + size_t sz = 1; // final sentinel for (const auto &pair : files) { - sz += pair.first.length() + 1; // include sentinel - sz += pair.second.length() + 2; // Add a '\n' as well as sentinel + sz += pair.first.length() + 1; // include sentinel + sz += pair.second.length() + 2; // Add a '\n' as well as sentinel } - char *buf = (char*)::malloc(sz); - if (buf == nullptr) memory_panic(); + char *buf = (char *)::malloc(sz); + if (buf == nullptr) + memory_panic(); std::ptrdiff_t i = 0; for (const auto &pair : files) { memcpy(&buf[i], pair.first.c_str(), pair.first.length() + 1); @@ -523,23 +541,29 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, buf[i] = '\0'; i++; } - buf[i] = '\0'; // final sentinel + buf[i] = '\0'; // final sentinel *error = false; return buf; - } - break; + } break; case STREAM: { - std::vector documents = jsonnet_vm_execute_stream( - &alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects, - vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback, - vm->importCallbackContext); - size_t sz = 1; // final sentinel + std::vector documents = + jsonnet_vm_execute_stream(&alloc, + expr, + vm->ext, + vm->maxStack, + vm->gcMinObjects, + vm->gcGrowthTrigger, + vm->nativeCallbacks, + vm->importCallback, + vm->importCallbackContext); + size_t sz = 1; // final sentinel for (const auto &doc : documents) { - sz += doc.length() + 2; // Add a '\n' as well as sentinel + sz += doc.length() + 2; // Add a '\n' as well as sentinel } - char *buf = (char*)::malloc(sz); - if (buf == nullptr) memory_panic(); + char *buf = (char *)::malloc(sz); + if (buf == nullptr) + memory_panic(); std::ptrdiff_t i = 0; for (const auto &doc : documents) { memcpy(&buf[i], doc.c_str(), doc.length()); @@ -549,15 +573,14 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, buf[i] = '\0'; i++; } - buf[i] = '\0'; // final sentinel + buf[i] = '\0'; // final sentinel *error = false; return buf; - } - break; + } break; default: - fputs("INTERNAL ERROR: bad value of 'kind', probably memory corruption.\n", stderr); - abort(); + fputs("INTERNAL ERROR: bad value of 'kind', probably memory corruption.\n", stderr); + abort(); } } catch (StaticError &e) { @@ -572,7 +595,7 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename, const long max_above = vm->maxTrace / 2; const long max_below = vm->maxTrace - max_above; const long sz = e.stackTrace.size(); - for (long i = 0 ; i < sz ; ++i) { + for (long i = 0; i < sz; ++i) { const auto &f = e.stackTrace[i]; if (vm->maxTrace > 0 && i >= max_above && i < sz - max_below) { if (i == max_above) @@ -600,8 +623,7 @@ static char *jsonnet_evaluate_file_aux(JsonnetVm *vm, const char *filename, int return from_string(vm, ss.str()); } std::string input; - input.assign(std::istreambuf_iterator(f), - std::istreambuf_iterator()); + input.assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); return jsonnet_evaluate_snippet_aux(vm, filename, input.c_str(), error, kind); } @@ -609,7 +631,7 @@ static char *jsonnet_evaluate_file_aux(JsonnetVm *vm, const char *filename, int char *jsonnet_evaluate_file(JsonnetVm *vm, const char *filename, int *error) { TRY - return jsonnet_evaluate_file_aux(vm, filename, error, REGULAR); + return jsonnet_evaluate_file_aux(vm, filename, error, REGULAR); CATCH("jsonnet_evaluate_file") return nullptr; // Never happens. } @@ -617,7 +639,7 @@ char *jsonnet_evaluate_file(JsonnetVm *vm, const char *filename, int *error) char *jsonnet_evaluate_file_multi(JsonnetVm *vm, const char *filename, int *error) { TRY - return jsonnet_evaluate_file_aux(vm, filename, error, MULTI); + return jsonnet_evaluate_file_aux(vm, filename, error, MULTI); CATCH("jsonnet_evaluate_file_multi") return nullptr; // Never happens. } @@ -625,7 +647,7 @@ char *jsonnet_evaluate_file_multi(JsonnetVm *vm, const char *filename, int *erro char *jsonnet_evaluate_file_stream(JsonnetVm *vm, const char *filename, int *error) { TRY - return jsonnet_evaluate_file_aux(vm, filename, error, STREAM); + return jsonnet_evaluate_file_aux(vm, filename, error, STREAM); CATCH("jsonnet_evaluate_file_stream") return nullptr; // Never happens. } @@ -633,46 +655,48 @@ char *jsonnet_evaluate_file_stream(JsonnetVm *vm, const char *filename, int *err char *jsonnet_evaluate_snippet(JsonnetVm *vm, const char *filename, const char *snippet, int *error) { TRY - return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, REGULAR); + return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, REGULAR); CATCH("jsonnet_evaluate_snippet") return nullptr; // Never happens. } -char *jsonnet_evaluate_snippet_multi(JsonnetVm *vm, const char *filename, - const char *snippet, int *error) +char *jsonnet_evaluate_snippet_multi(JsonnetVm *vm, const char *filename, const char *snippet, + int *error) { TRY - return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, MULTI); + return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, MULTI); CATCH("jsonnet_evaluate_snippet_multi") return nullptr; // Never happens. } -char *jsonnet_evaluate_snippet_stream(JsonnetVm *vm, const char *filename, - const char *snippet, int *error) +char *jsonnet_evaluate_snippet_stream(JsonnetVm *vm, const char *filename, const char *snippet, + int *error) { TRY - return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, STREAM); + return jsonnet_evaluate_snippet_aux(vm, filename, snippet, error, STREAM); CATCH("jsonnet_evaluate_snippet_stream") return nullptr; // Never happens. } char *jsonnet_realloc(JsonnetVm *vm, char *str, size_t sz) { - (void) vm; + (void)vm; if (str == nullptr) { - if (sz == 0) return nullptr; - auto *r = static_cast(::malloc(sz)); - if (r == nullptr) memory_panic(); + if (sz == 0) + return nullptr; + auto *r = static_cast(::malloc(sz)); + if (r == nullptr) + memory_panic(); return r; } else { if (sz == 0) { ::free(str); return nullptr; } else { - auto *r = static_cast(::realloc(str, sz)); - if (r == nullptr) memory_panic(); + auto *r = static_cast(::realloc(str, sz)); + if (r == nullptr) + memory_panic(); return r; } } } - diff --git a/core/libjsonnet_test.cpp b/core/libjsonnet_test.cpp index 051ffd8f1..1ad9146ed 100644 --- a/core/libjsonnet_test.cpp +++ b/core/libjsonnet_test.cpp @@ -15,7 +15,7 @@ limitations under the License. */ extern "C" { - #include "libjsonnet.h" +#include "libjsonnet.h" } #include "gtest/gtest.h" diff --git a/core/parser.cpp b/core/parser.cpp index b0d1ac9a8..48c3699a6 100644 --- a/core/parser.cpp +++ b/core/parser.cpp @@ -14,16 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include #include #include +#include +#include #include #include #include #include -#include - #include "ast.h" #include "desugarer.h" @@ -31,7 +30,6 @@ limitations under the License. #include "parser.h" #include "static_error.h" - std::string jsonnet_unparse_number(double v) { std::stringstream ss; @@ -47,13 +45,13 @@ std::string jsonnet_unparse_number(double v) return ss.str(); } - namespace { static bool op_is_unary(const std::string &op, UnaryOp &uop) { auto it = unary_map.find(op); - if (it == unary_map.end()) return false; + if (it == unary_map.end()) + return false; uop = it->second; return true; } @@ -61,7 +59,8 @@ static bool op_is_unary(const std::string &op, UnaryOp &uop) static bool op_is_binary(const std::string &op, BinaryOp &bop) { auto it = binary_map.find(op); - if (it == binary_map.end()) return false; + if (it == binary_map.end()) + return false; bop = it->second; return true; } @@ -84,7 +83,6 @@ LocationRange span(const Token &begin, AST *end) /** Holds state while parsing a given token list. */ class Parser { - // The private member functions are utilities for dealing with the token stream. StaticError unexpected(const Token &tok, const std::string &while_) @@ -101,7 +99,8 @@ class Parser { return tok; } - void push(Token tok) { + void push(Token tok) + { tokens.push_front(tok); } @@ -115,11 +114,11 @@ class Parser { Token doublePeek(void) { Tokens::iterator it = tokens.begin(); // First one. - it++; // Now pointing at the second one. + it++; // Now pointing at the second one. return *(it); } - Token popExpect(Token::Kind k, const char *data=nullptr) + Token popExpect(Token::Kind k, const char *data = nullptr) { Token tok = pop(); if (tok.kind != k) { @@ -138,11 +137,8 @@ class Parser { std::list &tokens; Allocator *alloc; - public: - - Parser(Tokens &tokens, Allocator *alloc) - : tokens(tokens), alloc(alloc) - { } + public: + Parser(Tokens &tokens, Allocator *alloc) : tokens(tokens), alloc(alloc) {} /** Parse a comma-separated list of expressions. * @@ -152,8 +148,8 @@ class Parser { * \param element_kind Used in error messages when a comma was not found. * \returns The last token (the one that matched parameter end). */ - Token parseArgs(ArgParams &args, Token::Kind end, - const std::string &element_kind, bool &got_comma) + Token parseArgs(ArgParams &args, Token::Kind end, const std::string &element_kind, + bool &got_comma) { got_comma = false; bool first = true; @@ -165,7 +161,7 @@ class Parser { } if (!first && !got_comma) { std::stringstream ss; - ss << "Expected a comma before next " << element_kind << "."; + ss << "Expected a comma before next " << element_kind << "."; throw StaticError(next.location, ss.str()); } // Either id=expr or id or expr, but note that expr could be id==1 so this needs @@ -205,11 +201,9 @@ class Parser { // parseArgs returns f(x) with x as an expression. Convert it here. for (auto &p : params) { if (p.id == nullptr) { - auto *pv = dynamic_cast(p.expr); + auto *pv = dynamic_cast(p.expr); if (pv == nullptr) { - throw StaticError(p.expr->location, - "Could not parse parameter here."); - + throw StaticError(p.expr->location, "Could not parse parameter here."); } p.id = pv->id; p.idFodder = pv->openFodder; @@ -243,24 +237,30 @@ class Parser { Token eq = popExpect(Token::OPERATOR, "="); AST *body = parse(MAX_PRECEDENCE); Token delim = pop(); - binds.emplace_back(var_id.fodder, id, eq.fodder, body, is_function, fodder_l, params, - trailing_comma, fodder_r, delim.fodder); + binds.emplace_back(var_id.fodder, + id, + eq.fodder, + body, + is_function, + fodder_l, + params, + trailing_comma, + fodder_r, + delim.fodder); return delim; } - Token parseObjectRemainder(AST *&obj, const Token &tok) { ObjectFields fields; std::set literal_fields; // For duplicate fields detection. - std::set binds; // For duplicate locals detection. + std::set binds; // For duplicate locals detection. bool got_comma = false; bool first = true; Token next = pop(); do { - if (next.kind == Token::BRACE_R) { obj = alloc->make( span(tok, next), tok.fodder, fields, got_comma, next.fodder); @@ -272,7 +272,8 @@ class Parser { unsigned num_asserts = 0; const ObjectField *field_ptr = nullptr; for (const auto &field : fields) { - if (field.kind == ObjectField::LOCAL) continue; + if (field.kind == ObjectField::LOCAL) + continue; if (field.kind == ObjectField::ASSERT) { num_asserts++; continue; @@ -315,8 +316,11 @@ class Parser { got_comma = false; switch (next.kind) { - case Token::BRACKET_L: case Token::IDENTIFIER: case Token::STRING_DOUBLE: - case Token::STRING_SINGLE: case Token::STRING_BLOCK: { + case Token::BRACKET_L: + case Token::IDENTIFIER: + case Token::STRING_DOUBLE: + case Token::STRING_SINGLE: + case Token::STRING_BLOCK: { ObjectField::Kind kind; AST *expr1 = nullptr; const Identifier *id = nullptr; @@ -327,19 +331,28 @@ class Parser { id = alloc->makeIdentifier(next.data32()); } else if (next.kind == Token::STRING_DOUBLE) { kind = ObjectField::FIELD_STR; - expr1 = alloc->make( - next.location, next.fodder, next.data32(), LiteralString::DOUBLE, - "", ""); + expr1 = alloc->make(next.location, + next.fodder, + next.data32(), + LiteralString::DOUBLE, + "", + ""); } else if (next.kind == Token::STRING_SINGLE) { kind = ObjectField::FIELD_STR; - expr1 = alloc->make( - next.location, next.fodder, next.data32(), LiteralString::SINGLE, - "", ""); + expr1 = alloc->make(next.location, + next.fodder, + next.data32(), + LiteralString::SINGLE, + "", + ""); } else if (next.kind == Token::STRING_BLOCK) { kind = ObjectField::FIELD_STR; - expr1 = alloc->make( - next.location, next.fodder, next.data32(), LiteralString::BLOCK, - next.stringBlockIndent, next.stringBlockTermIndent); + expr1 = alloc->make(next.location, + next.fodder, + next.data32(), + LiteralString::BLOCK, + next.stringBlockIndent, + next.stringBlockTermIndent); } else { kind = ObjectField::FIELD_EXPR; fodder1 = next.fodder; @@ -369,7 +382,7 @@ class Parser { od++; } unsigned colons = 0; - for (; *od != '\0' ; ++od) { + for (; *od != '\0'; ++od) { if (*od != ':') { throw StaticError( next.location, @@ -379,17 +392,11 @@ class Parser { } ObjectField::Hide field_hide; switch (colons) { - case 1: - field_hide = ObjectField::INHERIT; - break; + case 1: field_hide = ObjectField::INHERIT; break; - case 2: - field_hide = ObjectField::HIDDEN; - break; + case 2: field_hide = ObjectField::HIDDEN; break; - case 3: - field_hide = ObjectField::VISIBLE; - break; + case 3: field_hide = ObjectField::VISIBLE; break; default: throw StaticError( @@ -399,12 +406,12 @@ class Parser { // Basic checks for invalid Jsonnet code. if (is_method && plus_sugar) { - throw StaticError( - next.location, "Cannot use +: syntax sugar in a method: " + next.data); + throw StaticError(next.location, + "Cannot use +: syntax sugar in a method: " + next.data); } if (kind != ObjectField::FIELD_EXPR) { if (!literal_fields.insert(next.data).second) { - throw StaticError(next.location, "Duplicate field: "+next.data); + throw StaticError(next.location, "Duplicate field: " + next.data); } } @@ -417,12 +424,23 @@ class Parser { next = pop(); got_comma = true; } - fields.emplace_back( - kind, fodder1, fodder2, fodder_l, fodder_r, field_hide, plus_sugar, - is_method, expr1, id, params, meth_comma, op.fodder, body, nullptr, - comma_fodder); - } - break; + fields.emplace_back(kind, + fodder1, + fodder2, + fodder_l, + fodder_r, + field_hide, + plus_sugar, + is_method, + expr1, + id, + params, + meth_comma, + op.fodder, + body, + nullptr, + comma_fodder); + } break; case Token::LOCAL: { Fodder local_fodder = next.fodder; @@ -454,13 +472,19 @@ class Parser { next = pop(); got_comma = true; } - fields.push_back( - ObjectField::Local( - local_fodder, var_id.fodder, paren_l_fodder, paren_r_fodder, - is_method, id, params, func_comma, eq.fodder, body, comma_fodder)); - - } - break; + fields.push_back(ObjectField::Local(local_fodder, + var_id.fodder, + paren_l_fodder, + paren_r_fodder, + is_method, + id, + params, + func_comma, + eq.fodder, + body, + comma_fodder)); + + } break; case Token::ASSERT: { Fodder assert_fodder = next.fodder; @@ -480,16 +504,13 @@ class Parser { next = pop(); got_comma = true; } - fields.push_back(ObjectField::Assert(assert_fodder, cond, colon_fodder, msg, - comma_fodder)); - } - break; + fields.push_back( + ObjectField::Assert(assert_fodder, cond, colon_fodder, msg, comma_fodder)); + } break; - default: - throw unexpected(next, "parsing field definition"); + default: throw unexpected(next, "parsing field definition"); } - } while (true); } @@ -503,14 +524,14 @@ class Parser { const Identifier *id = alloc->makeIdentifier(id_token.data32()); Token in_token = popExpect(Token::IN); AST *arr = parse(MAX_PRECEDENCE); - specs.emplace_back(ComprehensionSpec::FOR, for_fodder, id_token.fodder, id, - in_token.fodder, arr); + specs.emplace_back( + ComprehensionSpec::FOR, for_fodder, id_token.fodder, id, in_token.fodder, arr); Token maybe_if = pop(); for (; maybe_if.kind == Token::IF; maybe_if = pop()) { AST *cond = parse(MAX_PRECEDENCE); - specs.emplace_back(ComprehensionSpec::IF, maybe_if.fodder, Fodder{}, nullptr, - Fodder{}, cond); + specs.emplace_back( + ComprehensionSpec::IF, maybe_if.fodder, Fodder{}, nullptr, Fodder{}, cond); } if (maybe_if.kind == end) { return maybe_if; @@ -546,11 +567,9 @@ class Parser { case Token::PAREN_R: case Token::SEMICOLON: case Token::TAILSTRICT: - case Token::THEN: - throw unexpected(tok, "parsing terminal"); + case Token::THEN: throw unexpected(tok, "parsing terminal"); - case Token::END_OF_FILE: - throw StaticError(tok.location, "Unexpected end of file."); + case Token::END_OF_FILE: throw StaticError(tok.location, "Unexpected end of file."); case Token::BRACE_L: { AST *obj; @@ -562,8 +581,8 @@ class Parser { Token next = peek(); if (next.kind == Token::BRACKET_R) { Token bracket_r = pop(); - return alloc->make(span(tok, next), tok.fodder, Array::Elements{}, - false, bracket_r.fodder); + return alloc->make( + span(tok, next), tok.fodder, Array::Elements{}, false, bracket_r.fodder); } AST *first = parse(MAX_PRECEDENCE); bool got_comma = false; @@ -581,9 +600,13 @@ class Parser { Token for_token = pop(); std::vector specs; Token last = parseComprehensionSpecs(Token::BRACKET_R, for_token.fodder, specs); - return alloc->make( - span(tok, last), tok.fodder, first, comma_fodder, got_comma, specs, - last.fodder); + return alloc->make(span(tok, last), + tok.fodder, + first, + comma_fodder, + got_comma, + specs, + last.fodder); } // Not a comprehension: It can have more elements. @@ -621,45 +644,42 @@ class Parser { } // Literals - case Token::NUMBER: - return alloc->make(span(tok), tok.fodder, tok.data); + case Token::NUMBER: return alloc->make(span(tok), tok.fodder, tok.data); case Token::STRING_SINGLE: - return alloc->make( - span(tok), tok.fodder, tok.data32(), LiteralString::SINGLE, "", ""); + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::SINGLE, "", ""); case Token::STRING_DOUBLE: - return alloc->make( - span(tok), tok.fodder, tok.data32(), LiteralString::DOUBLE, "", ""); + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::DOUBLE, "", ""); case Token::STRING_BLOCK: - return alloc->make( - span(tok), tok.fodder, tok.data32(), LiteralString::BLOCK, - tok.stringBlockIndent, tok.stringBlockTermIndent); + return alloc->make(span(tok), + tok.fodder, + tok.data32(), + LiteralString::BLOCK, + tok.stringBlockIndent, + tok.stringBlockTermIndent); case Token::VERBATIM_STRING_SINGLE: - return alloc->make( - span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_SINGLE, "", ""); + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_SINGLE, "", ""); case Token::VERBATIM_STRING_DOUBLE: - return alloc->make( - span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_DOUBLE, "", ""); - + return alloc->make( + span(tok), tok.fodder, tok.data32(), LiteralString::VERBATIM_DOUBLE, "", ""); - case Token::FALSE: - return alloc->make(span(tok), tok.fodder, false); + case Token::FALSE: return alloc->make(span(tok), tok.fodder, false); - case Token::TRUE: - return alloc->make(span(tok), tok.fodder, true); + case Token::TRUE: return alloc->make(span(tok), tok.fodder, true); case Token::NULL_LIT: - return alloc->make(span(tok), tok.fodder); + return alloc->make(span(tok), tok.fodder); // Variables - case Token::DOLLAR: - return alloc->make(span(tok), tok.fodder); + case Token::DOLLAR: return alloc->make(span(tok), tok.fodder); case Token::IDENTIFIER: - return alloc->make(span(tok), tok.fodder, alloc->makeIdentifier(tok.data32())); + return alloc->make(span(tok), tok.fodder, alloc->makeIdentifier(tok.data32())); - case Token::SELF: - return alloc->make(span(tok), tok.fodder); + case Token::SELF: return alloc->make(span(tok), tok.fodder); case Token::SUPER: { Token next = pop(); @@ -677,11 +697,10 @@ class Parser { Token bracket_r = popExpect(Token::BRACKET_R); id_fodder = bracket_r.fodder; // Not id_fodder, but use the same var. } break; - default: - throw StaticError(tok.location, "Expected . or [ after super."); + default: throw StaticError(tok.location, "Expected . or [ after super."); } - return alloc->make(span(tok), tok.fodder, next.fodder, index, - id_fodder, id); + return alloc->make( + span(tok), tok.fodder, next.fodder, index, id_fodder, id); } } @@ -695,7 +714,6 @@ class Parser { Token begin = peek(); switch (begin.kind) { - // These cases have effectively MAX_PRECEDENCE as the first // call to parse will parse them. case Token::ASSERT: { @@ -710,8 +728,13 @@ class Parser { } Token semicolon = popExpect(Token::SEMICOLON); AST *rest = parse(MAX_PRECEDENCE); - return alloc->make(span(begin, rest), begin.fodder, cond, colonFodder, - msg, semicolon.fodder, rest); + return alloc->make(span(begin, rest), + begin.fodder, + cond, + colonFodder, + msg, + semicolon.fodder, + rest); } case Token::ERROR: { @@ -728,27 +751,39 @@ class Parser { if (peek().kind == Token::ELSE) { Token else_ = pop(); AST *branch_false = parse(MAX_PRECEDENCE); - return alloc->make( - span(begin, branch_false), begin.fodder, cond, then.fodder, branch_true, - else_.fodder, branch_false); + return alloc->make(span(begin, branch_false), + begin.fodder, + cond, + then.fodder, + branch_true, + else_.fodder, + branch_false); } - return alloc->make(span(begin, branch_true), begin.fodder, cond, - then.fodder, branch_true, Fodder{}, nullptr); + return alloc->make(span(begin, branch_true), + begin.fodder, + cond, + then.fodder, + branch_true, + Fodder{}, + nullptr); } case Token::FUNCTION: { pop(); // Still available in 'begin'. Token paren_l = pop(); if (paren_l.kind == Token::PAREN_L) { - std::vector params_asts; + std::vector params_asts; bool got_comma; Fodder paren_r_fodder; - ArgParams params = parseParams( - "function parameter", got_comma, paren_r_fodder); + ArgParams params = parseParams("function parameter", got_comma, paren_r_fodder); AST *body = parse(MAX_PRECEDENCE); - return alloc->make( - span(begin, body), begin.fodder, paren_l.fodder, params, got_comma, - paren_r_fodder, body); + return alloc->make(span(begin, body), + begin.fodder, + paren_l.fodder, + params, + got_comma, + paren_r_fodder, + body); } else { std::stringstream ss; ss << "Expected ( but got " << paren_l; @@ -759,7 +794,7 @@ class Parser { case Token::IMPORT: { pop(); AST *body = parse(MAX_PRECEDENCE); - if (auto *lit = dynamic_cast(body)) { + if (auto *lit = dynamic_cast(body)) { if (lit->tokenKind == LiteralString::BLOCK) { throw StaticError(lit->location, "Cannot use text blocks in import statements."); @@ -775,7 +810,7 @@ class Parser { case Token::IMPORTSTR: { pop(); AST *body = parse(MAX_PRECEDENCE); - if (auto *lit = dynamic_cast(body)) { + if (auto *lit = dynamic_cast(body)) { if (lit->tokenKind == LiteralString::BLOCK) { throw StaticError(lit->location, "Cannot use text blocks in import statements."); @@ -798,7 +833,8 @@ class Parser { ss << "Expected , or ; but got " << delim; throw StaticError(delim.location, ss.str()); } - if (delim.kind == Token::SEMICOLON) break; + if (delim.kind == Token::SEMICOLON) + break; } while (true); AST *body = parse(MAX_PRECEDENCE); return alloc->make(span(begin, body), begin.fodder, binds, body); @@ -806,178 +842,198 @@ class Parser { default: - // Unary operator. - if (begin.kind == Token::OPERATOR) { - UnaryOp uop; - if (!op_is_unary(begin.data, uop)) { - std::stringstream ss; - ss << "Not a unary operator: " << begin.data; - throw StaticError(begin.location, ss.str()); - } - if (UNARY_PRECEDENCE == precedence) { - Token op = pop(); - AST *expr = parse(precedence); - return alloc->make(span(op, expr), op.fodder, uop, expr); - } - } - - // Base case - if (precedence == 0) return parseTerminal(); - - AST *lhs = parse(precedence - 1); - - Fodder begin_fodder; - - while (true) { - - // Then next token must be a binary operator. - - // The compiler can't figure out that this is never used uninitialized. - BinaryOp bop = BOP_PLUS; - - // Check precedence is correct for this level. If we're - // parsing operators with higher precedence, then return - // lhs and let lower levels deal with the operator. - switch (peek().kind) { - // Logical / arithmetic binary operator. - case Token::IN: - case Token::OPERATOR: - if (peek().data == ":") { - // Special case for the colons in assert. - // Since COLON is no-longer a special token, we have to make sure it - // does not trip the op_is_binary test below. It should - // terminate parsing of the expression here, returning control - // to the parsing of the actual assert AST. - return lhs; - } - if (peek().data == "::") { - // Special case for [e::] - // We need to stop parsing e when we see the :: and - // avoid tripping the op_is_binary test below. - return lhs; - } - if (!op_is_binary(peek().data, bop)) { + // Unary operator. + if (begin.kind == Token::OPERATOR) { + UnaryOp uop; + if (!op_is_unary(begin.data, uop)) { std::stringstream ss; - ss << "Not a binary operator: " << peek().data; - throw StaticError(peek().location, ss.str()); + ss << "Not a unary operator: " << begin.data; + throw StaticError(begin.location, ss.str()); + } + if (UNARY_PRECEDENCE == precedence) { + Token op = pop(); + AST *expr = parse(precedence); + return alloc->make(span(op, expr), op.fodder, uop, expr); } - if (precedence_map[bop] != precedence) return lhs; - break; - - // Index, Apply - case Token::DOT: case Token::BRACKET_L: - case Token::PAREN_L: case Token::BRACE_L: - if (APPLY_PRECEDENCE != precedence) return lhs; - break; - - default: - return lhs; } - Token op = pop(); - if (op.kind == Token::BRACKET_L) { - bool is_slice; - AST *first = nullptr; - Fodder second_fodder; - AST *second = nullptr; - Fodder third_fodder; - AST *third = nullptr; - - if (peek().kind == Token::BRACKET_R) - throw unexpected(pop(), "parsing index"); - - if (peek().data != ":" && peek().data != "::") { - first = parse(MAX_PRECEDENCE); + // Base case + if (precedence == 0) + return parseTerminal(); + + AST *lhs = parse(precedence - 1); + + Fodder begin_fodder; + + while (true) { + // Then next token must be a binary operator. + + // The compiler can't figure out that this is never used uninitialized. + BinaryOp bop = BOP_PLUS; + + // Check precedence is correct for this level. If we're + // parsing operators with higher precedence, then return + // lhs and let lower levels deal with the operator. + switch (peek().kind) { + // Logical / arithmetic binary operator. + case Token::IN: + case Token::OPERATOR: + if (peek().data == ":") { + // Special case for the colons in assert. + // Since COLON is no-longer a special token, we have to make sure it + // does not trip the op_is_binary test below. It should + // terminate parsing of the expression here, returning control + // to the parsing of the actual assert AST. + return lhs; + } + if (peek().data == "::") { + // Special case for [e::] + // We need to stop parsing e when we see the :: and + // avoid tripping the op_is_binary test below. + return lhs; + } + if (!op_is_binary(peek().data, bop)) { + std::stringstream ss; + ss << "Not a binary operator: " << peek().data; + throw StaticError(peek().location, ss.str()); + } + if (precedence_map[bop] != precedence) + return lhs; + break; + + // Index, Apply + case Token::DOT: + case Token::BRACKET_L: + case Token::PAREN_L: + case Token::BRACE_L: + if (APPLY_PRECEDENCE != precedence) + return lhs; + break; + + default: return lhs; } - if (peek().kind == Token::OPERATOR && peek().data == "::") { - // Handle :: - is_slice = true; - Token joined = pop(); - second_fodder = joined.fodder; - - if (peek().kind != Token::BRACKET_R) - third = parse(MAX_PRECEDENCE); - - } else if (peek().kind != Token::BRACKET_R) { - is_slice = true; - Token delim = pop(); - if (delim.data != ":") - throw unexpected(delim, "parsing slice"); + Token op = pop(); + if (op.kind == Token::BRACKET_L) { + bool is_slice; + AST *first = nullptr; + Fodder second_fodder; + AST *second = nullptr; + Fodder third_fodder; + AST *third = nullptr; + + if (peek().kind == Token::BRACKET_R) + throw unexpected(pop(), "parsing index"); + + if (peek().data != ":" && peek().data != "::") { + first = parse(MAX_PRECEDENCE); + } - second_fodder = delim.fodder; + if (peek().kind == Token::OPERATOR && peek().data == "::") { + // Handle :: + is_slice = true; + Token joined = pop(); + second_fodder = joined.fodder; - if (peek().data != ":" && peek().kind != Token::BRACKET_R) - second = parse(MAX_PRECEDENCE); + if (peek().kind != Token::BRACKET_R) + third = parse(MAX_PRECEDENCE); - if (peek().kind != Token::BRACKET_R) { + } else if (peek().kind != Token::BRACKET_R) { + is_slice = true; Token delim = pop(); if (delim.data != ":") throw unexpected(delim, "parsing slice"); - third_fodder = delim.fodder; + second_fodder = delim.fodder; - if (peek().kind != Token::BRACKET_R) - third = parse(MAX_PRECEDENCE); + if (peek().data != ":" && peek().kind != Token::BRACKET_R) + second = parse(MAX_PRECEDENCE); + + if (peek().kind != Token::BRACKET_R) { + Token delim = pop(); + if (delim.data != ":") + throw unexpected(delim, "parsing slice"); + + third_fodder = delim.fodder; + + if (peek().kind != Token::BRACKET_R) + third = parse(MAX_PRECEDENCE); + } + } else { + is_slice = false; } + Token end = popExpect(Token::BRACKET_R); + lhs = alloc->make(span(begin, end), + begin_fodder, + lhs, + op.fodder, + is_slice, + first, + second_fodder, + second, + third_fodder, + third, + end.fodder); + + } else if (op.kind == Token::DOT) { + Token field_id = popExpect(Token::IDENTIFIER); + const Identifier *id = alloc->makeIdentifier(field_id.data32()); + lhs = alloc->make(span(begin, field_id), + begin_fodder, + lhs, + op.fodder, + field_id.fodder, + id); + + } else if (op.kind == Token::PAREN_L) { + ArgParams args; + bool got_comma; + Token end = parseArgs(args, Token::PAREN_R, "function argument", got_comma); + bool tailstrict = false; + Fodder tailstrict_fodder; + if (peek().kind == Token::TAILSTRICT) { + Token tailstrict_token = pop(); + tailstrict_fodder = tailstrict_token.fodder; + tailstrict = true; + } + lhs = alloc->make(span(begin, end), + begin_fodder, + lhs, + op.fodder, + args, + got_comma, + end.fodder, + tailstrict_fodder, + tailstrict); + + } else if (op.kind == Token::BRACE_L) { + AST *obj; + Token end = parseObjectRemainder(obj, op); + lhs = alloc->make(span(begin, end), begin_fodder, lhs, obj); + + } else if (op.kind == Token::IN) { + if (peek().kind == Token::SUPER) { + Token super = pop(); + lhs = alloc->make( + span(begin, super), begin_fodder, lhs, op.fodder, super.fodder); + } else { + AST *rhs = parse(precedence - 1); + lhs = alloc->make( + span(begin, rhs), begin_fodder, lhs, op.fodder, bop, rhs); + } + } else { - is_slice = false; - } - Token end = popExpect(Token::BRACKET_R); - lhs = alloc->make(span(begin, end), begin_fodder, lhs, op.fodder, - is_slice, first, second_fodder, second, - third_fodder, third, end.fodder); - - } else if (op.kind == Token::DOT) { - Token field_id = popExpect(Token::IDENTIFIER); - const Identifier *id = alloc->makeIdentifier(field_id.data32()); - lhs = alloc->make(span(begin, field_id), begin_fodder, lhs, - op.fodder, field_id.fodder, id); - - } else if (op.kind == Token::PAREN_L) { - ArgParams args; - bool got_comma; - Token end = parseArgs(args, Token::PAREN_R, "function argument", got_comma); - bool tailstrict = false; - Fodder tailstrict_fodder; - if (peek().kind == Token::TAILSTRICT) { - Token tailstrict_token = pop(); - tailstrict_fodder = tailstrict_token.fodder; - tailstrict = true; - } - lhs = alloc->make(span(begin, end), begin_fodder, lhs, op.fodder, - args, got_comma, end.fodder, tailstrict_fodder, - tailstrict); - - } else if (op.kind == Token::BRACE_L) { - AST *obj; - Token end = parseObjectRemainder(obj, op); - lhs = alloc->make(span(begin, end), begin_fodder, lhs, obj); - - } else if (op.kind == Token::IN) { - if (peek().kind == Token::SUPER) { - Token super = pop(); - lhs = alloc->make( - span(begin, super), begin_fodder, lhs, op.fodder, super.fodder); - } else { + // Logical / arithmetic binary operator. + assert(op.kind == Token::OPERATOR); AST *rhs = parse(precedence - 1); lhs = alloc->make( span(begin, rhs), begin_fodder, lhs, op.fodder, bop, rhs); } - } else { - // Logical / arithmetic binary operator. - assert(op.kind == Token::OPERATOR); - AST *rhs = parse(precedence - 1); - lhs = alloc->make(span(begin, rhs), begin_fodder, lhs, op.fodder, - bop, rhs); + begin_fodder.clear(); } - - begin_fodder.clear(); - } } } - }; } // namespace diff --git a/core/parser_test.cpp b/core/parser_test.cpp index fc7bbe8b2..da5158519 100644 --- a/core/parser_test.cpp +++ b/core/parser_test.cpp @@ -18,8 +18,8 @@ limitations under the License. #include #include "ast.h" -#include "lexer.h" #include "gtest/gtest.h" +#include "lexer.h" namespace { @@ -33,10 +33,9 @@ void testParse(const char* snippet) AST* ast = jsonnet_parse(&allocator, tokens); (void)ast; } catch (StaticError& e) { - ASSERT_TRUE(false) - << "Static error: " << e.toString() << std::endl - << "Snippet:" << std::endl - << snippet << std::endl; + ASSERT_TRUE(false) << "Static error: " << e.toString() << std::endl + << "Snippet:" << std::endl + << snippet << std::endl; } } @@ -132,99 +131,67 @@ void testParseError(const char* snippet, const std::string& expectedError) AST* ast = jsonnet_parse(&allocator, tokens); (void)ast; } catch (StaticError& e) { - ASSERT_EQ(expectedError, e.toString()) - << "Snippet:" << std::endl - << snippet << std::endl; - } + ASSERT_EQ(expectedError, e.toString()) << "Snippet:" << std::endl << snippet << std::endl; + } } TEST(Parser, TestInvalidFunctionCall) { - testParseError( - "function(a, b c)", - "test:1:15: Expected a comma before next function parameter."); - testParseError( - "function(a, 1)", - "test:1:13: Could not parse parameter here."); + testParseError("function(a, b c)", + "test:1:15: Expected a comma before next function parameter."); + testParseError("function(a, 1)", "test:1:13: Could not parse parameter here."); testParseError("a b", R"(test:1:3: Did not expect: (IDENTIFIER, "b"))"); - testParseError( - "foo(a, bar(a b))", - "test:1:14: Expected a comma before next function argument."); + testParseError("foo(a, bar(a b))", + "test:1:14: Expected a comma before next function argument."); } TEST(Parser, TestInvalidLocal) { testParseError("local", "test:1:6: Expected token IDENTIFIER but got end of file"); - testParseError( - "local foo = 1, foo = 2; true", - "test:1:16-18: Duplicate local var: foo"); - testParseError( - "local foo(a b) = a; true", - "test:1:13: Expected a comma before next function parameter."); - testParseError( - "local foo(a): a; true", - "test:1:13: Expected operator = but got :"); - testParseError( - "local foo(a) = bar(a b); true", - "test:1:22: Expected a comma before next function argument."); - testParseError( - "local foo: 1; true", - "test:1:10: Expected operator = but got :"); - testParseError( - "local foo = bar(a b); true", - "test:1:19: Expected a comma before next function argument."); - - testParseError( - "local a = b ()", - "test:1:15: Expected , or ; but got end of file"); - testParseError( - "local a = b; (a b)", - R"_(test:1:17: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("local foo = 1, foo = 2; true", "test:1:16-18: Duplicate local var: foo"); + testParseError("local foo(a b) = a; true", + "test:1:13: Expected a comma before next function parameter."); + testParseError("local foo(a): a; true", "test:1:13: Expected operator = but got :"); + testParseError("local foo(a) = bar(a b); true", + "test:1:22: Expected a comma before next function argument."); + testParseError("local foo: 1; true", "test:1:10: Expected operator = but got :"); + testParseError("local foo = bar(a b); true", + "test:1:19: Expected a comma before next function argument."); + + testParseError("local a = b ()", "test:1:15: Expected , or ; but got end of file"); + testParseError("local a = b; (a b)", + R"_(test:1:17: Expected token ")" but got (IDENTIFIER, "b"))_"); } TEST(Parser, TestInvalidTuple) { - testParseError( - "{a b}", - R"(test:1:4: Expected token OPERATOR but got (IDENTIFIER, "b"))"); - testParseError( - "{a = b}", - "test:1:2: Expected one of :, ::, :::, +:, +::, +:::, got: ="); - testParseError( - "{a :::: b}", - "test:1:2: Expected one of :, ::, :::, +:, +::, +:::, got: ::::"); + testParseError("{a b}", + R"(test:1:4: Expected token OPERATOR but got (IDENTIFIER, "b"))"); + testParseError("{a = b}", "test:1:2: Expected one of :, ::, :::, +:, +::, +:::, got: ="); + testParseError("{a :::: b}", "test:1:2: Expected one of :, ::, :::, +:, +::, +:::, got: ::::"); } TEST(Parser, TestInvalidComprehension) { - testParseError( - "{assert x for x in [1, 2, 3]}", - "test:1:11-13: Object comprehension cannot have asserts."); - testParseError( - "{['foo' + x]: true, [x]: x for x in [1, 2, 3]}", - "test:1:28-30: Object comprehension can only have one field."); - testParseError( - "{foo: x for x in [1, 2, 3]}", - "test:1:9-11: Object comprehensions can only have [e] fields."); - testParseError( - "{[x]:: true for x in [1, 2, 3]}", - "test:1:13-15: Object comprehensions cannot have hidden fields."); - testParseError( - "{[x]: true for 1 in [1, 2, 3]}", - R"(test:1:16: Expected token IDENTIFIER but got (NUMBER, "1"))"); - testParseError( - "{[x]: true for x at [1, 2, 3]}", - R"(test:1:18-19: Expected token in but got (IDENTIFIER, "at"))"); - testParseError( - "{[x]: true for x in [1, 2 3]}", - "test:1:27: Expected a comma before next array element."); - testParseError( - "{[x]: true for x in [1, 2, 3] if (a b)}", - R"_(test:1:37: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "{[x]: true for x in [1, 2, 3] if a b}", - R"(test:1:36: Expected for, if or "}" after for clause,)" - R"( got: (IDENTIFIER, "b"))"); + testParseError("{assert x for x in [1, 2, 3]}", + "test:1:11-13: Object comprehension cannot have asserts."); + testParseError("{['foo' + x]: true, [x]: x for x in [1, 2, 3]}", + "test:1:28-30: Object comprehension can only have one field."); + testParseError("{foo: x for x in [1, 2, 3]}", + "test:1:9-11: Object comprehensions can only have [e] fields."); + testParseError("{[x]:: true for x in [1, 2, 3]}", + "test:1:13-15: Object comprehensions cannot have hidden fields."); + testParseError("{[x]: true for 1 in [1, 2, 3]}", + R"(test:1:16: Expected token IDENTIFIER but got (NUMBER, "1"))"); + testParseError("{[x]: true for x at [1, 2, 3]}", + R"(test:1:18-19: Expected token in but got (IDENTIFIER, "at"))"); + testParseError("{[x]: true for x in [1, 2 3]}", + "test:1:27: Expected a comma before next array element."); + testParseError("{[x]: true for x in [1, 2, 3] if (a b)}", + R"_(test:1:37: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("{[x]: true for x in [1, 2, 3] if a b}", + R"(test:1:36: Expected for, if or "}" after for clause,)" + R"( got: (IDENTIFIER, "b"))"); } TEST(Parser, TestInvalidNoComma) @@ -248,31 +215,23 @@ TEST(Parser, TestInvalidFields) TEST(Parser, TestInvalidLocalInTuple) { - testParseError( - "{local 1 = 3, true}", - R"(test:1:8: Expected token IDENTIFIER but got (NUMBER, "1"))"); - testParseError( - "{local foo = 1, local foo = 2, true}", - "test:1:23-25: Duplicate local var: foo"); - testParseError( - "{local foo(a b) = 1, a: true}", - "test:1:14: Expected a comma before next function parameter."); - testParseError( - "{local foo(a): 1, a: true}", - "test:1:14: Expected operator = but got :"); - testParseError( - "{local foo(a) = (a b), a: true}", - R"_(test:1:20: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("{local 1 = 3, true}", + R"(test:1:8: Expected token IDENTIFIER but got (NUMBER, "1"))"); + testParseError("{local foo = 1, local foo = 2, true}", + "test:1:23-25: Duplicate local var: foo"); + testParseError("{local foo(a b) = 1, a: true}", + "test:1:14: Expected a comma before next function parameter."); + testParseError("{local foo(a): 1, a: true}", "test:1:14: Expected operator = but got :"); + testParseError("{local foo(a) = (a b), a: true}", + R"_(test:1:20: Expected token ")" but got (IDENTIFIER, "b"))_"); } TEST(Parser, TestInvalidAssertInTuple) { - testParseError( - "{assert (a b), a: true}", - R"_(test:1:12: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "{assert a: (a b), a: true}", - R"_(test:1:15: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("{assert (a b), a: true}", + R"_(test:1:12: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("{assert a: (a b), a: true}", + R"_(test:1:15: Expected token ")" but got (IDENTIFIER, "b"))_"); } TEST(Parser, TestInvalidUnexpectedFunction) @@ -281,22 +240,18 @@ TEST(Parser, TestInvalidUnexpectedFunction) // implementation, which is: // test:1:2-10 Unexpected: (function, "function") while parsing field // definition. - testParseError( - "{function(a, b) a+b: true}", - "test:1:2-9: Unexpected: function while parsing field definition"); + testParseError("{function(a, b) a+b: true}", + "test:1:2-9: Unexpected: function while parsing field definition"); } TEST(Parser, TestInvalidArray) { - testParseError( - "[(a b), 2, 3]", - R"_(test:1:5: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "[1, (a b), 2, 3]", - R"_(test:1:8: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "[a for b in [1 2 3]]", - "test:1:16: Expected a comma before next array element."); + testParseError("[(a b), 2, 3]", + R"_(test:1:5: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("[1, (a b), 2, 3]", + R"_(test:1:8: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("[a for b in [1 2 3]]", + "test:1:16: Expected a comma before next array element."); } TEST(Parser, TestInvalidExpression) @@ -316,21 +271,17 @@ TEST(Parser, TestInvalidExpression) TEST(Parser, TestInvalidAssert) { - testParseError( - "assert (a b); true", - R"_(test:1:11: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "assert a: (a b); true", - R"_(test:1:14: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("assert (a b); true", + R"_(test:1:11: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("assert a: (a b); true", + R"_(test:1:14: Expected token ")" but got (IDENTIFIER, "b"))_"); // TODO(jsonnet-team): The error output of this differs from the Go // implementation, which is: // test:1:16: Expected token ";" but got (",", ",") - testParseError( - "assert a: 'foo', true", - R"(test:1:16: Expected token ";" but got ",")"); - testParseError( - "assert a: 'foo'; (a b)", - R"_(test:1:21: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("assert a: 'foo', true", + R"(test:1:16: Expected token ";" but got ",")"); + testParseError("assert a: 'foo'; (a b)", + R"_(test:1:21: Expected token ")" but got (IDENTIFIER, "b"))_"); } TEST(Parser, TestInvalidError) @@ -340,25 +291,20 @@ TEST(Parser, TestInvalidError) TEST(Parser, TestInvalidIf) { - testParseError( - "if (a b) then c", - R"_(test:1:7: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "if a b c", - R"(test:1:6: Expected token then but got (IDENTIFIER, "b"))"); - testParseError( - "if a then (b c)", - R"_(test:1:14: Expected token ")" but got (IDENTIFIER, "c"))_"); - testParseError( - "if a then b else (c d)", - R"_(test:1:21: Expected token ")" but got (IDENTIFIER, "d"))_"); + testParseError("if (a b) then c", + R"_(test:1:7: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("if a b c", + R"(test:1:6: Expected token then but got (IDENTIFIER, "b"))"); + testParseError("if a then (b c)", + R"_(test:1:14: Expected token ")" but got (IDENTIFIER, "c"))_"); + testParseError("if a then b else (c d)", + R"_(test:1:21: Expected token ")" but got (IDENTIFIER, "d"))_"); } TEST(Parser, TestInvalidFunction) { - testParseError( - "function(a) (a b)", - R"_(test:1:16: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("function(a) (a b)", + R"_(test:1:16: Expected token ")" but got (IDENTIFIER, "b"))_"); testParseError("function a a", R"(test:1:10: Expected ( but got (IDENTIFIER, "a"))"); } @@ -366,12 +312,9 @@ TEST(Parser, TestInvalidImport) { testParseError("import (a b)", R"_(test:1:11: Expected token ")" but got (IDENTIFIER, "b"))_"); testParseError("import (a+b)", "test:1:8-12: Computed imports are not allowed."); - testParseError( - "importstr (a b)", - R"_(test:1:14: Expected token ")" but got (IDENTIFIER, "b"))_"); - testParseError( - "importstr (a+b)", - "test:1:11-15: Computed imports are not allowed."); + testParseError("importstr (a b)", + R"_(test:1:14: Expected token ")" but got (IDENTIFIER, "b"))_"); + testParseError("importstr (a+b)", "test:1:11-15: Computed imports are not allowed."); } TEST(Parser, TestInvalidOperator) @@ -392,7 +335,7 @@ TEST(Parser, TestInvalidArrayAccess) TEST(Parser, TestInvalidOverride) { - testParseError( "a{b c}", R"(test:1:5: Expected token OPERATOR but got (IDENTIFIER, "c"))"); + testParseError("a{b c}", R"(test:1:5: Expected token OPERATOR but got (IDENTIFIER, "c"))"); } } // namespace diff --git a/core/pass.cpp b/core/pass.cpp index fe2404ecf..656f7e56e 100644 --- a/core/pass.cpp +++ b/core/pass.cpp @@ -28,13 +28,11 @@ void CompilerPass::specs(std::vector &specs) fodder(spec.openFodder); switch (spec.kind) { case ComprehensionSpec::FOR: - fodder(spec.varFodder); - fodder(spec.inFodder); - expr(spec.expr); - break; - case ComprehensionSpec::IF: - expr(spec.expr); - break; + fodder(spec.varFodder); + fodder(spec.inFodder); + expr(spec.expr); + break; + case ComprehensionSpec::IF: expr(spec.expr); break; } } } @@ -63,7 +61,6 @@ void CompilerPass::fieldParams(ObjectField &field) void CompilerPass::fields(ObjectFields &fields) { for (auto &field : fields) { - switch (field.kind) { case ObjectField::LOCAL: { fodder(field.fodder1); @@ -287,69 +284,68 @@ void CompilerPass::visit(Unary *ast) void CompilerPass::visitExpr(AST *&ast_) { - if (auto *ast = dynamic_cast(ast_)) { + if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { visit(ast); } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); - } } @@ -361,76 +357,75 @@ void CompilerPass::file(AST *&body, Fodder &final_fodder) /** A pass that clones the AST it is given. */ class ClonePass : public CompilerPass { - public: - ClonePass(Allocator &alloc) : CompilerPass(alloc) { } + public: + ClonePass(Allocator &alloc) : CompilerPass(alloc) {} virtual void expr(AST *&ast); }; void ClonePass::expr(AST *&ast_) { - if (auto *ast = dynamic_cast(ast_)) { + if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { ast_ = alloc.clone(ast); } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); - } CompilerPass::expr(ast_); diff --git a/core/pass.h b/core/pass.h index 10c3c9d85..230294e20 100644 --- a/core/pass.h +++ b/core/pass.h @@ -22,15 +22,14 @@ limitations under the License. /** A generic Pass that does nothing but can be extended to easily define real passes. */ class CompilerPass { - public: - - protected: + public: + protected: Allocator &alloc; - public: - CompilerPass(Allocator &alloc) : alloc(alloc) { } + public: + CompilerPass(Allocator &alloc) : alloc(alloc) {} - virtual void fodderElement(FodderElement &) { } + virtual void fodderElement(FodderElement &) {} virtual void fodder(Fodder &fodder); @@ -56,11 +55,11 @@ class CompilerPass { virtual void visit(Binary *ast); - virtual void visit(BuiltinFunction *) { } + virtual void visit(BuiltinFunction *) {} virtual void visit(Conditional *ast); - virtual void visit(Dollar *) { } + virtual void visit(Dollar *) {} virtual void visit(Error *ast); @@ -76,13 +75,13 @@ class CompilerPass { virtual void visit(Local *ast); - virtual void visit(LiteralBoolean *) { } + virtual void visit(LiteralBoolean *) {} - virtual void visit(LiteralNumber *) { } + virtual void visit(LiteralNumber *) {} - virtual void visit(LiteralString *) { } + virtual void visit(LiteralString *) {} - virtual void visit(LiteralNull *) { } + virtual void visit(LiteralNull *) {} virtual void visit(Object *ast); @@ -91,23 +90,22 @@ class CompilerPass { virtual void visit(ObjectComprehension *ast); virtual void visit(ObjectComprehensionSimple *ast); - + virtual void visit(Parens *ast); - virtual void visit(Self *) { } + virtual void visit(Self *) {} virtual void visit(SuperIndex *ast); virtual void visit(Unary *ast); - virtual void visit(Var *) { } + virtual void visit(Var *) {} virtual void visitExpr(AST *&ast_); virtual void file(AST *&body, Fodder &final_fodder); }; - /** Return an equivalent AST that can be modified without affecting the original. * * This is a deep copy. diff --git a/core/state.h b/core/state.h index b009806ab..37da15c6e 100644 --- a/core/state.h +++ b/core/state.h @@ -27,7 +27,7 @@ typedef unsigned char GarbageCollectionMark; */ struct HeapEntity { GarbageCollectionMark mark; - virtual ~HeapEntity() { } + virtual ~HeapEntity() {} }; /** Tagged union of all values. @@ -69,9 +69,9 @@ std::string type_str(Value::Type t) case Value::OBJECT: return "object"; case Value::STRING: return "string"; default: - std::cerr << "INTERNAL ERROR: Unknown type: " << t << std::endl; - std::abort(); - return ""; // Quiet, compiler. + std::cerr << "INTERNAL ERROR: Unknown type: " << t << std::endl; + std::abort(); + return ""; // Quiet, compiler. } } @@ -88,7 +88,7 @@ struct HeapThunk; * Each nested local statement, function call, and field access has its own binding frame to * give the values for the local variable, function parameters, or upValues. */ -typedef std::map BindingFrame; +typedef std::map BindingFrame; /** Supertype of all objects. Types of Value::OBJECT will point at these. */ struct HeapObject : public HeapEntity { @@ -122,8 +122,9 @@ struct HeapThunk : public HeapEntity { const AST *body; HeapThunk(const Identifier *name, HeapObject *self, unsigned offset, const AST *body) - : filled(false), name(name), self(self), offset(offset), body(body) - { } + : filled(false), name(name), self(self), offset(offset), body(body) + { + } void fill(const Value &v) { @@ -138,10 +139,8 @@ struct HeapArray : public HeapEntity { // It is convenient for this to not be const, so that we can add elements to it one at a // time after creation. Thus, elements are not GCed as the array is being // created. - std::vector elements; - HeapArray(const std::vector &elements) - : elements(elements) - { } + std::vector elements; + HeapArray(const std::vector &elements) : elements(elements) {} }; /** Supertype of all objects that are not super objects or extended objects. */ @@ -165,18 +164,19 @@ struct HeapSimpleObject : public HeapLeafObject { * These are evaluated in the captured environment and with self and super bound * dynamically. */ - const std::map fields; + const std::map fields; /** The object's invariants. * * These are evaluated in the captured environment with self and super bound. */ - std::vector asserts; + std::vector asserts; HeapSimpleObject(const BindingFrame &up_values, - const std::map fields, std::vector asserts) - : upValues(up_values), fields(fields), asserts(asserts) - { } + const std::map fields, std::vector asserts) + : upValues(up_values), fields(fields), asserts(asserts) + { + } }; /** Objects created by the + construct. */ @@ -187,22 +187,19 @@ struct HeapExtendedObject : public HeapObject { /** The right hand side of the construct. */ HeapObject *right; - HeapExtendedObject(HeapObject *left, HeapObject *right) - : left(left), right(right) - { } + HeapExtendedObject(HeapObject *left, HeapObject *right) : left(left), right(right) {} }; /** Objects created by the ObjectComprehensionSimple construct. */ struct HeapComprehensionObject : public HeapLeafObject { - /** The captured environment. */ const BindingFrame upValues; /** The expression used to compute the field values. */ - const AST* value; + const AST *value; /** The identifier of bound variable in that construct. */ - const Identifier * const id; + const Identifier *const id; /** Binding for id. * @@ -213,13 +210,13 @@ struct HeapComprehensionObject : public HeapLeafObject { * It is convenient to make this non-const to allow building up the values one by one, so that * the garbage collector can see them at each intermediate point. */ - std::map compValues; + std::map compValues; - HeapComprehensionObject(const BindingFrame &up_values, const AST *value, - const Identifier *id, - const std::map &comp_values) - : upValues(up_values), value(value), id(id), compValues(comp_values) - { } + HeapComprehensionObject(const BindingFrame &up_values, const AST *value, const Identifier *id, + const std::map &comp_values) + : upValues(up_values), value(value), id(id), compValues(comp_values) + { + } }; /** Stores the function itself and also the captured environment. @@ -239,35 +236,32 @@ struct HeapClosure : public HeapEntity { struct Param { const Identifier *id; const AST *def; - Param(const Identifier *id, const AST *def) - : id(id), def(def) - { } + Param(const Identifier *id, const AST *def) : id(id), def(def) {} }; typedef std::vector Params; const Params params; const AST *body; std::string builtinName; - HeapClosure(const BindingFrame &up_values, - HeapObject *self, - unsigned offset, - const Params ¶ms, - const AST *body, const std::string &builtin_name) - : upValues(up_values), self(self), offset(offset), - params(params), body(body), builtinName(builtin_name) - { } + HeapClosure(const BindingFrame &up_values, HeapObject *self, unsigned offset, + const Params ¶ms, const AST *body, const std::string &builtin_name) + : upValues(up_values), + self(self), + offset(offset), + params(params), + body(body), + builtinName(builtin_name) + { + } }; /** Stores a simple string on the heap. */ struct HeapString : public HeapEntity { const UString value; - HeapString(const UString &value) - : value(value) - { } + HeapString(const UString &value) : value(value) {} }; /** The heap does memory management, i.e. garbage collection. */ class Heap { - /** How many objects must exist in the heap before we bother doing garbage collection? */ unsigned gcTuneMinObjects; @@ -285,7 +279,7 @@ class Heap { * removed from the heap via O(1) swap with last element, so the ordering of entities is * arbitrary and changes every garbage collection cycle. */ - std::vector entities; + std::vector entities; /** The number of heap entities at the last garbage collection cycle. */ unsigned long lastNumEntities; @@ -293,25 +287,28 @@ class Heap { /** The number of heap entities now. */ unsigned long numEntities; - /** Add the HeapEntity inside v to vec, if the value exists on the heap. + /** Add the HeapEntity inside v to vec, if the value exists on the heap. */ - void addIfHeapEntity(Value v, std::vector &vec) + void addIfHeapEntity(Value v, std::vector &vec) { - if (v.isHeap()) vec.push_back(v.v.h); + if (v.isHeap()) + vec.push_back(v.v.h); } - /** Add the HeapEntity inside v to vec, if the value exists on the heap. + /** Add the HeapEntity inside v to vec, if the value exists on the heap. */ - void addIfHeapEntity(HeapEntity *v, std::vector &vec) + void addIfHeapEntity(HeapEntity *v, std::vector &vec) { vec.push_back(v); } - public: - + public: Heap(unsigned gc_tune_min_objects, double gc_tune_growth_trigger) - : gcTuneMinObjects(gc_tune_min_objects), gcTuneGrowthTrigger(gc_tune_growth_trigger), - lastMark(0), lastNumEntities(0), numEntities(0) + : gcTuneMinObjects(gc_tune_min_objects), + gcTuneGrowthTrigger(gc_tune_growth_trigger), + lastMark(0), + lastNumEntities(0), + numEntities(0) { } @@ -324,7 +321,8 @@ class Heap { /** Garbage collection: Mark v, and entities reachable from v. */ void markFrom(Value v) { - if (v.isHeap()) markFrom(v.v.h); + if (v.isHeap()) + markFrom(v.v.h); } /** Garbage collection: Mark heap entities reachable from the given heap entity. */ @@ -334,8 +332,8 @@ class Heap { const GarbageCollectionMark thisMark = lastMark + 1; struct State { HeapEntity *ent; - std::vector children; - State(HeapEntity *ent) : ent(ent) { } + std::vector children; + State(HeapEntity *ent) : ent(ent) {} }; std::vector stack; @@ -348,32 +346,31 @@ class Heap { if (curr->mark != thisMark) { curr->mark = thisMark; - if (auto *obj = dynamic_cast(curr)) { + if (auto *obj = dynamic_cast(curr)) { for (auto upv : obj->upValues) addIfHeapEntity(upv.second, s.children); - } else if (auto *obj = dynamic_cast(curr)) { + } else if (auto *obj = dynamic_cast(curr)) { addIfHeapEntity(obj->left, s.children); addIfHeapEntity(obj->right, s.children); - } else if (auto *obj = dynamic_cast(curr)) { + } else if (auto *obj = dynamic_cast(curr)) { for (auto upv : obj->upValues) addIfHeapEntity(upv.second, s.children); for (auto upv : obj->compValues) addIfHeapEntity(upv.second, s.children); - - } else if (auto *arr = dynamic_cast(curr)) { + } else if (auto *arr = dynamic_cast(curr)) { for (auto el : arr->elements) addIfHeapEntity(el, s.children); - } else if (auto *func = dynamic_cast(curr)) { + } else if (auto *func = dynamic_cast(curr)) { for (auto upv : func->upValues) addIfHeapEntity(upv.second, s.children); if (func->self) addIfHeapEntity(func->self, s.children); - } else if (auto *thunk = dynamic_cast(curr)) { + } else if (auto *thunk = dynamic_cast(curr)) { if (thunk->filled) { if (thunk->content.isHeap()) addIfHeapEntity(thunk->content.v.h, s.children); @@ -401,13 +398,13 @@ class Heap { { lastMark++; // Heap shrinks during this loop. Do not cache entities.size(). - for (unsigned long i=0 ; imark != lastMark) { delete x; if (i != entities.size() - 1) { // Swap it with the back. - entities[i] = entities[entities.size()-1]; + entities[i] = entities[entities.size() - 1]; } entities.pop_back(); --i; @@ -419,16 +416,17 @@ class Heap { /** Is it time to initiate a GC cycle? */ bool checkHeap(void) { - return numEntities > gcTuneMinObjects - && numEntities > gcTuneGrowthTrigger * lastNumEntities; + return numEntities > gcTuneMinObjects && + numEntities > gcTuneGrowthTrigger * lastNumEntities; } /** Allocate a heap entity. * * If the heap is large enough (\see gcTuneMinObjects) and has grown by enough since the * last collection cycle (\see gcTuneGrowthTrigger), a collection cycle is performed. - */ - template T* makeEntity(Args&&... args) + */ + template + T *makeEntity(Args &&... args) { T *r = new T(std::forward(args)...); entities.push_back(r); @@ -436,7 +434,6 @@ class Heap { numEntities = entities.size(); return r; } - }; } // namespace diff --git a/core/static_analysis.cpp b/core/static_analysis.cpp index 9f234f6b7..46567889e 100644 --- a/core/static_analysis.cpp +++ b/core/static_analysis.cpp @@ -16,9 +16,9 @@ limitations under the License. #include +#include "ast.h" #include "static_analysis.h" #include "static_error.h" -#include "ast.h" typedef std::set IdSet; @@ -39,31 +39,31 @@ static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) { IdSet r; - if (auto *ast = dynamic_cast(ast_)) { + if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->target, in_object, vars)); for (const auto &arg : ast->args) append(r, static_analysis(arg.expr, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { - for (auto & el : ast->elements) + } else if (auto *ast = dynamic_cast(ast_)) { + for (auto &el : ast->elements) append(r, static_analysis(el.expr, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->left, in_object, vars)); append(r, static_analysis(ast->right, in_object, vars)); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->cond, in_object, vars)); append(r, static_analysis(ast->branchTrue, in_object, vars)); append(r, static_analysis(ast->branchFalse, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->expr, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { auto new_vars = vars; IdSet params; for (const auto &p : ast->params) { @@ -84,53 +84,53 @@ static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) fv.erase(p.id); append(r, fv); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (!in_object) throw StaticError(ast_->location, "Can't use super outside of an object."); append(r, static_analysis(ast->element, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->target, in_object, vars)); append(r, static_analysis(ast->index, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { IdSet ast_vars; - for (const auto &bind: ast->binds) { + for (const auto &bind : ast->binds) { ast_vars.insert(bind.var); } auto new_vars = vars; append(new_vars, ast_vars); IdSet fvs; - for (const auto &bind: ast->binds) { + for (const auto &bind : ast->binds) { append(fvs, static_analysis(bind.body, in_object, new_vars)); } append(fvs, static_analysis(ast->body, in_object, new_vars)); - for (const auto &bind: ast->binds) + for (const auto &bind : ast->binds) fvs.erase(bind.var); append(r, fvs); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { // Nothing to do. - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { for (auto &field : ast->fields) { append(r, static_analysis(field.name, in_object, vars)); append(r, static_analysis(field.body, true, vars)); @@ -139,7 +139,7 @@ static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) append(r, static_analysis(assert, true, vars)); } - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { auto new_vars = vars; new_vars.insert(ast->id); append(r, static_analysis(ast->field, false, new_vars)); @@ -147,28 +147,27 @@ static IdSet static_analysis(AST *ast_, bool in_object, const IdSet &vars) r.erase(ast->id); append(r, static_analysis(ast->array, in_object, vars)); - } else if (dynamic_cast(ast_)) { + } else if (dynamic_cast(ast_)) { if (!in_object) throw StaticError(ast_->location, "Can't use self outside of an object."); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (!in_object) throw StaticError(ast_->location, "Can't use super outside of an object."); append(r, static_analysis(ast->index, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { append(r, static_analysis(ast->expr, in_object, vars)); - } else if (auto *ast = dynamic_cast(ast_)) { + } else if (auto *ast = dynamic_cast(ast_)) { if (vars.find(ast->id) == vars.end()) { - throw StaticError(ast->location, "Unknown variable: "+encode_utf8(ast->id->name)); + throw StaticError(ast->location, "Unknown variable: " + encode_utf8(ast->id->name)); } r.insert(ast->id); } else { std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_ << std::endl; std::abort(); - } for (auto *id : r) diff --git a/core/static_error.h b/core/static_error.h index 1b8b7e837..19f861e03 100644 --- a/core/static_error.h +++ b/core/static_error.h @@ -23,12 +23,8 @@ limitations under the License. struct Location { unsigned long line; unsigned long column; - Location(void) - : line(0), column(0) - { } - Location(unsigned long line_number, unsigned long column) - : line(line_number), column(column) - { } + Location(void) : line(0), column(0) {} + Location(unsigned long line_number, unsigned long column) : line(line_number), column(column) {} bool isSet(void) const { return line != 0; @@ -44,15 +40,13 @@ static inline std::ostream &operator<<(std::ostream &o, const Location &loc) struct LocationRange { std::string file; Location begin, end; - LocationRange(void) - { } + LocationRange(void) {} /** This is useful for special locations, e.g. manifestation entry point. */ - LocationRange(const std::string &msg) - : file(msg) - { } + LocationRange(const std::string &msg) : file(msg) {} LocationRange(const std::string &file, const Location &begin, const Location &end) - : file(file), begin(begin), end(end) - { } + : file(file), begin(begin), end(end) + { + } bool isSet(void) const { return begin.isSet(); @@ -82,16 +76,13 @@ static inline std::ostream &operator<<(std::ostream &o, const LocationRange &loc struct StaticError { LocationRange location; std::string msg; - StaticError(const std::string &msg) - : msg(msg) - { - } + StaticError(const std::string &msg) : msg(msg) {} StaticError(const std::string &filename, const Location &location, const std::string &msg) - : location(filename, location, location), msg(msg) + : location(filename, location, location), msg(msg) { } StaticError(const LocationRange &location, const std::string &msg) - : location(location), msg(msg) + : location(location), msg(msg) { } diff --git a/core/string_utils.cpp b/core/string_utils.cpp index da5fb6580..280b384c9 100644 --- a/core/string_utils.cpp +++ b/core/string_utils.cpp @@ -16,8 +16,8 @@ limitations under the License. #include -#include "string_utils.h" #include "static_error.h" +#include "string_utils.h" UString jsonnet_string_unparse(const UString &str, bool single) { @@ -31,7 +31,7 @@ UString jsonnet_string_unparse(const UString &str, bool single) UString jsonnet_string_escape(const UString &str, bool single) { UStringStream ss; - for (std::size_t i=0 ; i= 0x7f && c <= 0x9f)) { - //Unprintable, use \u + // Unprintable, use \u std::stringstream ss8; ss8 << "\\u" << std::hex << std::setfill('0') << std::setw(4) - << (unsigned long)(c); + << (unsigned long)(c); ss << decode_utf8(ss8.str()); } else { // Printable, write verbatim @@ -60,103 +60,83 @@ UString jsonnet_string_escape(const UString &str, bool single) return ss.str(); } - UString jsonnet_string_unescape(const LocationRange &loc, const UString &s) { UString r; const char32_t *s_ptr = s.c_str(); - for (const char32_t *c = s_ptr; *c != U'\0' ; ++c) { + for (const char32_t *c = s_ptr; *c != U'\0'; ++c) { switch (*c) { case '\\': - switch (*(++c)) { - case '"': - case '\'': - r += *c; - break; - - case '\\': - r += *c; - break; - - case '/': - r += *c; - break; - - case 'b': - r += '\b'; - break; - - case 'f': - r += '\f'; - break; - - case 'n': - r += '\n'; - break; + switch (*(++c)) { + case '"': + case '\'': r += *c; break; + + case '\\': r += *c; break; + + case '/': r += *c; break; + + case 'b': r += '\b'; break; + + case 'f': r += '\f'; break; + + case 'n': r += '\n'; break; + + case 'r': r += '\r'; break; + + case 't': r += '\t'; break; + + case 'u': { + ++c; // Consume the 'u'. + unsigned long codepoint = 0; + // Expect 4 hex digits. + for (unsigned i = 0; i < 4; ++i) { + auto x = (unsigned char)(c[i]); + unsigned digit; + if (x == '\0') { + auto msg = "Truncated unicode escape sequence in string literal."; + throw StaticError(loc, msg); + } else if (x >= '0' && x <= '9') { + digit = x - '0'; + } else if (x >= 'a' && x <= 'f') { + digit = x - 'a' + 10; + } else if (x >= 'A' && x <= 'F') { + digit = x - 'A' + 10; + } else { + std::stringstream ss; + ss << "Malformed unicode escape character, " + << "should be hex: '" << x << "'"; + throw StaticError(loc, ss.str()); + } + codepoint *= 16; + codepoint += digit; + } - case 'r': - r += '\r'; - break; + r += codepoint; - case 't': - r += '\t'; - break; + // Leave us on the last char, ready for the ++c at + // the outer for loop. + c += 3; + } break; - case 'u': { - ++c; // Consume the 'u'. - unsigned long codepoint = 0; - // Expect 4 hex digits. - for (unsigned i=0 ; i<4 ; ++i) { - auto x = (unsigned char)(c[i]); - unsigned digit; - if (x == '\0') { - auto msg = "Truncated unicode escape sequence in string literal."; - throw StaticError(loc, msg); - } else if (x >= '0' && x <= '9') { - digit = x - '0'; - } else if (x >= 'a' && x <= 'f') { - digit = x - 'a' + 10; - } else if (x >= 'A' && x <= 'F') { - digit = x - 'A' + 10; - } else { - std::stringstream ss; - ss << "Malformed unicode escape character, " - << "should be hex: '" << x << "'"; - throw StaticError(loc, ss.str()); - } - codepoint *= 16; - codepoint += digit; + case '\0': { + auto msg = "Truncated escape sequence in string literal."; + throw StaticError(loc, msg); } - r += codepoint; - - // Leave us on the last char, ready for the ++c at - // the outer for loop. - c += 3; + default: { + std::stringstream ss; + std::string utf8; + encode_utf8(*c, utf8); + ss << "Unknown escape sequence in string literal: '" << utf8 << "'"; + throw StaticError(loc, ss.str()); + } } break; - case '\0': { - auto msg = "Truncated escape sequence in string literal."; - throw StaticError(loc, msg); - } - - default: { - std::stringstream ss; - std::string utf8; - encode_utf8(*c, utf8); - ss << "Unknown escape sequence in string literal: '" << utf8 << "'"; - throw StaticError(loc, ss.str()); - } - } - break; - default: - // Just a regular letter. - r += *c; + // Just a regular letter. + r += *c; } } return r; } - - diff --git a/core/unicode.h b/core/unicode.h index f2125d1b3..5742c4ff9 100644 --- a/core/unicode.h +++ b/core/unicode.h @@ -38,23 +38,23 @@ static inline int encode_utf8(char32_t x, std::string &s) if (x < 0x80) { s.push_back((char)x); return 1; - } else if (x < 0x800) { // note that capital 'Y' bits must be 0 + } else if (x < 0x800) { // note that capital 'Y' bits must be 0 bytes |= 0xC080; s.push_back((bytes >> 8) & 0xFF); s.push_back((bytes >> 0) & 0xFF); return 2; - } else if (x < 0x10000) { // note that 'z' bits must be 0 + } else if (x < 0x10000) { // note that 'z' bits must be 0 bytes |= 0xE08080; s.push_back((bytes >> 16) & 0xFF); - s.push_back((bytes >> 8) & 0xFF); - s.push_back((bytes >> 0) & 0xFF); + s.push_back((bytes >> 8) & 0xFF); + s.push_back((bytes >> 0) & 0xFF); return 3; - } else if (x < 0x110000) { // note that capital 'Z' bits must be 0 + } else if (x < 0x110000) { // note that capital 'Z' bits must be 0 bytes |= 0xF0808080; s.push_back((bytes >> 24) & 0xFF); s.push_back((bytes >> 16) & 0xFF); - s.push_back((bytes >> 8) & 0xFF); - s.push_back((bytes >> 0) & 0xFF); + s.push_back((bytes >> 8) & 0xFF); + s.push_back((bytes >> 0) & 0xFF); return 4; } else { std::cerr << "Should never get here." << std::endl; @@ -64,18 +64,18 @@ static inline int encode_utf8(char32_t x, std::string &s) /** Convert the UTF8 byte sequence in the given string to a unicode code point. * - * \param str The string. + * \param str The string. * \param i The index of the string from which to start decoding and returns the index of the last - * byte of the encoded codepoint. + * byte of the encoded codepoint. * \returns The decoded unicode codepoint. */ static inline char32_t decode_utf8(const std::string &str, size_t &i) { char c0 = str[i]; - if ((c0 & 0x80) == 0) { //0xxxxxxx + if ((c0 & 0x80) == 0) { // 0xxxxxxx return c0; - } else if ((c0 & 0xE0) == 0xC0) { //110yyyxx 10xxxxxx - if (i+1 >= str.length()) { + } else if ((c0 & 0xE0) == 0xC0) { // 110yyyxx 10xxxxxx + if (i + 1 >= str.length()) { return JSONNET_CODEPOINT_ERROR; } char c1 = str[++i]; @@ -83,8 +83,8 @@ static inline char32_t decode_utf8(const std::string &str, size_t &i) return JSONNET_CODEPOINT_ERROR; } return ((c0 & 0x1F) << 6ul) | (c1 & 0x3F); - } else if ((c0 & 0xF0) == 0xE0) { //1110yyyy 10yyyyxx 10xxxxxx - if (i+2 >= str.length()) { + } else if ((c0 & 0xF0) == 0xE0) { // 1110yyyy 10yyyyxx 10xxxxxx + if (i + 2 >= str.length()) { return JSONNET_CODEPOINT_ERROR; } char c1 = str[++i]; @@ -96,8 +96,8 @@ static inline char32_t decode_utf8(const std::string &str, size_t &i) return JSONNET_CODEPOINT_ERROR; } return ((c0 & 0xF) << 12ul) | ((c1 & 0x3F) << 6) | (c2 & 0x3F); - } else if ((c0 & 0xF8) == 0xF0) { //11110zzz 10zzyyyy 10yyyyxx 10xxxxxx - if (i+3 >= str.length()) { + } else if ((c0 & 0xF8) == 0xF0) { // 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + if (i + 3 >= str.length()) { return JSONNET_CODEPOINT_ERROR; } char c1 = str[++i]; @@ -121,7 +121,6 @@ static inline char32_t decode_utf8(const std::string &str, size_t &i) /** A string class capable of holding unicode codepoints. */ typedef std::basic_string UString; - static inline void encode_utf8(const UString &s, std::string &r) { for (char32_t cp : s) @@ -138,21 +137,35 @@ static inline std::string encode_utf8(const UString &s) static inline UString decode_utf8(const std::string &s) { UString r; - for (size_t i = 0; i < s.length(); ++i) + for (size_t i = 0; i < s.length(); ++i) r.push_back(decode_utf8(s, i)); return r; } -/** A stringstream-like class capable of holding unicode codepoints. +/** A stringstream-like class capable of holding unicode codepoints. * The C++ standard does not support std::basic_stringstream UStringStream &operator << (T c) + + public: + UStringStream &operator<<(const UString &s) + { + buf.append(s); + return *this; + } + UStringStream &operator<<(const char32_t *s) + { + buf.append(s); + return *this; + } + UStringStream &operator<<(char32_t c) + { + buf.push_back(c); + return *this; + } + template + UStringStream &operator<<(T c) { std::stringstream ss; ss << c; @@ -160,7 +173,10 @@ class UStringStream { buf.push_back(char32_t(c)); return *this; } - UString str() { return buf; } + UString str() + { + return buf; + } }; #endif // JSONNET_UNICODE_H diff --git a/core/vm.cpp b/core/vm.cpp index 58568df16..08903e038 100644 --- a/core/vm.cpp +++ b/core/vm.cpp @@ -21,7 +21,6 @@ limitations under the License. #include #include - #include "desugarer.h" #include "json.h" #include "md5.h" @@ -39,7 +38,7 @@ std::string dir_name(const std::string &path) { size_t last_slash = path.rfind('/'); if (last_slash != std::string::npos) { - return path.substr(0, last_slash+1); + return path.substr(0, last_slash + 1); } return ""; } @@ -50,25 +49,25 @@ std::string dir_name(const std::string &path) * trace (for errors) displays. */ enum FrameKind { - FRAME_APPLY_TARGET, // e in e(...) - FRAME_BINARY_LEFT, // a in a + b - FRAME_BINARY_RIGHT, // b in a + b - FRAME_BUILTIN_FILTER, // When executing std.filter, used to hold intermediate state. + FRAME_APPLY_TARGET, // e in e(...) + FRAME_BINARY_LEFT, // a in a + b + FRAME_BINARY_RIGHT, // b in a + b + FRAME_BUILTIN_FILTER, // When executing std.filter, used to hold intermediate state. FRAME_BUILTIN_FORCE_THUNKS, // When forcing builtin args, holds intermediate state. - FRAME_CALL, // Used any time we have switched location in user code. - FRAME_ERROR, // e in error e - FRAME_IF, // e in if e then a else b - FRAME_IN_SUPER_ELEMENT, // e in 'e in super' - FRAME_INDEX_TARGET, // e in e[x] - FRAME_INDEX_INDEX, // e in x[e] - FRAME_INVARIANTS, // Caches the thunks that need to be executed one at a time. - FRAME_LOCAL, // Stores thunk bindings as we execute e in local ...; e + FRAME_CALL, // Used any time we have switched location in user code. + FRAME_ERROR, // e in error e + FRAME_IF, // e in if e then a else b + FRAME_IN_SUPER_ELEMENT, // e in 'e in super' + FRAME_INDEX_TARGET, // e in e[x] + FRAME_INDEX_INDEX, // e in x[e] + FRAME_INVARIANTS, // Caches the thunks that need to be executed one at a time. + FRAME_LOCAL, // Stores thunk bindings as we execute e in local ...; e FRAME_OBJECT, // Stores intermediate state as we execute es in { [e]: ..., [e]: ... } - FRAME_OBJECT_COMP_ARRAY, // e in {f:a for x in e] + FRAME_OBJECT_COMP_ARRAY, // e in {f:a for x in e] FRAME_OBJECT_COMP_ELEMENT, // Stores intermediate state when building object - FRAME_STRING_CONCAT, // Stores intermediate state while co-ercing objects - FRAME_SUPER_INDEX, // e in super[e] - FRAME_UNARY, // e in -e + FRAME_STRING_CONCAT, // Stores intermediate state while co-ercing objects + FRAME_SUPER_INDEX, // e in super[e] + FRAME_UNARY, // e in -e }; /** A frame on the stack. @@ -91,7 +90,6 @@ enum FrameKind { * prematurely collected. */ struct Frame { - /** Tag (tagged union). */ FrameKind kind; @@ -123,10 +121,10 @@ struct Frame { unsigned elementId; /** Used for a variety of purposes. */ - std::map elements; + std::map elements; /** Used for a variety of purposes. */ - std::vector thunks; + std::vector thunks; /** The context is used in error messages to attempt to find a reasonable name for the * object, function, or thunk value being executed. If it is a thunk, it is filled @@ -155,16 +153,28 @@ struct Frame { BindingFrame bindings; Frame(const FrameKind &kind, const AST *ast) - : kind(kind), ast(ast), location(ast->location), tailCall(false), elementId(0), - context(NULL), self(NULL), offset(0) + : kind(kind), + ast(ast), + location(ast->location), + tailCall(false), + elementId(0), + context(NULL), + self(NULL), + offset(0) { val.t = Value::NULL_TYPE; val2.t = Value::NULL_TYPE; } Frame(const FrameKind &kind, const LocationRange &location) - : kind(kind), ast(nullptr), location(location), tailCall(false), elementId(0), - context(NULL), self(NULL), offset(0) + : kind(kind), + ast(nullptr), + location(location), + tailCall(false), + elementId(0), + context(NULL), + self(NULL), + offset(0) { val.t = Value::NULL_TYPE; val2.t = Value::NULL_TYPE; @@ -175,8 +185,10 @@ struct Frame { { heap.markFrom(val); heap.markFrom(val2); - if (context) heap.markFrom(context); - if (self) heap.markFrom(self); + if (context) + heap.markFrom(context); + if (self) + heap.markFrom(self); for (const auto &bind : bindings) heap.markFrom(bind.second); for (const auto &el : elements) @@ -189,12 +201,10 @@ struct Frame { { return kind == FRAME_CALL; } - }; /** The stack holds all the stack frames and manages the stack frame limit. */ class Stack { - /** How many call frames are on the stack. */ unsigned calls; @@ -204,14 +214,10 @@ class Stack { /** The stack frames. */ std::vector stack; - public: + public: + Stack(unsigned limit) : calls(0), limit(limit) {} - Stack(unsigned limit) - : calls(0), limit(limit) - { - } - - ~Stack(void) { } + ~Stack(void) {} unsigned size(void) { @@ -221,13 +227,14 @@ class Stack { /** Search for the closest variable in scope that matches the given name. */ HeapThunk *lookUpVar(const Identifier *id) { - for (int i=stack.size()-1 ; i>=0 ; --i) { + for (int i = stack.size() - 1; i >= 0; --i) { const auto &binds = stack[i].bindings; auto it = binds.find(id); if (it != binds.end()) { return it->second; } - if (stack[i].isCall()) break; + if (stack[i].isCall()) + break; } return nullptr; } @@ -252,7 +259,8 @@ class Stack { void pop(void) { - if (top().isCall()) calls--; + if (top().isCall()) + calls--; stack.pop_back(); } @@ -264,23 +272,28 @@ class Stack { std::string getName(unsigned from_here, const HeapEntity *e) { std::string name; - for (int i=from_here-1 ; i>=0; --i) { + for (int i = from_here - 1; i >= 0; --i) { const auto &f = stack[i]; for (const auto &pair : f.bindings) { HeapThunk *thunk = pair.second; - if (!thunk->filled) continue; - if (!thunk->content.isHeap()) continue; - if (e != thunk->content.v.h) continue; + if (!thunk->filled) + continue; + if (!thunk->content.isHeap()) + continue; + if (e != thunk->content.v.h) + continue; name = encode_utf8(pair.first->name); } // Do not go into the next call frame, keep local reasoning. - if (f.isCall()) break; + if (f.isCall()) + break; } - if (name == "") name = "anonymous"; - if (dynamic_cast(e)) { + if (name == "") + name = "anonymous"; + if (dynamic_cast(e)) { return "object <" + name + ">"; - } else if (auto *thunk = dynamic_cast(e)) { + } else if (auto *thunk = dynamic_cast(e)) { if (thunk->name == nullptr) { return ""; // Argument of builtin, or root (since top level functions). } else { @@ -302,10 +315,9 @@ class Stack { */ virtual void dump(void) { - for (unsigned i=0 ; i stack_trace; stack_trace.push_back(TraceFrame(loc)); - for (int i=stack.size()-1 ; i>=0 ; --i) { + for (int i = stack.size() - 1; i >= 0; --i) { const auto &f = stack[i]; if (f.isCall()) { if (f.context != nullptr) { // Give the last line a name. - stack_trace[stack_trace.size()-1].name = getName(i, f.context); + stack_trace[stack_trace.size() - 1].name = getName(i, f.context); } if (f.location.isSet() || f.location.file.length() > 0) stack_trace.push_back(TraceFrame(f.location)); @@ -331,22 +343,24 @@ class Stack { } /** New (non-call) frame. */ - template void newFrame(Args... args) + template + void newFrame(Args... args) { stack.emplace_back(args...); } /** If there is a tailstrict annotated frame followed by some locals, pop them all. */ - void tailCallTrimStack (void) + void tailCallTrimStack(void) { - for (int i=stack.size()-1 ; i>=0 ; --i) { + for (int i = stack.size() - 1; i >= 0; --i) { switch (stack[i].kind) { case FRAME_CALL: { if (!stack[i].tailCall || stack[i].thunks.size() > 0) { return; } // Remove all stack frames including this one. - while (stack.size() > unsigned(i)) stack.pop_back(); + while (stack.size() > unsigned(i)) + stack.pop_back(); calls--; return; } break; @@ -359,8 +373,8 @@ class Stack { } /** New call frame. */ - void newCall(const LocationRange &loc, HeapEntity *context, HeapObject *self, - unsigned offset, const BindingFrame &up_values) + void newCall(const LocationRange &loc, HeapEntity *context, HeapObject *self, unsigned offset, + const BindingFrame &up_values) { tailCallTrimStack(); if (calls >= limit) { @@ -374,7 +388,7 @@ class Stack { top().bindings = up_values; top().tailCall = false; - #ifndef NDEBUG +#ifndef NDEBUG for (const auto &bind : up_values) { if (bind.second == nullptr) { std::cerr << "INTERNAL ERROR: No binding for variable " @@ -382,7 +396,7 @@ class Stack { std::abort(); } } - #endif +#endif } /** Look up the stack to find the self binding. */ @@ -390,7 +404,7 @@ class Stack { { self = nullptr; offset = 0; - for (int i=stack.size() - 1 ; i>=0 ; --i) { + for (int i = stack.size() - 1; i >= 0; --i) { if (stack[i].isCall()) { self = stack[i].self; offset = stack[i].offset; @@ -402,9 +416,10 @@ class Stack { /** Look up the stack to see if we're running assertions for this object. */ bool alreadyExecutingInvariants(HeapObject *self) { - for (int i=stack.size() - 1 ; i>=0 ; --i) { + for (int i = stack.size() - 1; i >= 0; --i) { if (stack[i].kind == FRAME_INVARIANTS) { - if (stack[i].self == self) return true; + if (stack[i].self == self) + return true; } } return false; @@ -417,7 +432,6 @@ typedef std::map ExtMap; /** Typedef to save some typing. */ typedef std::map StrMap; - class Interpreter; typedef const AST *(Interpreter::*BuiltinFunc)(const LocationRange &loc, @@ -432,7 +446,6 @@ typedef const AST *(Interpreter::*BuiltinFunc)(const LocationRange &loc, * mark are removed from the heap. */ class Interpreter { - /** The heap. */ Heap heap; @@ -501,7 +514,8 @@ class Interpreter { * \param T Something under HeapEntity * \returns The new object */ - template T* makeHeap(Args&&... args) + template + T *makeHeap(Args &&... args) { T *r = heap.makeEntity(std::forward(args)...); if (heap.checkHeap()) { // Do a GC cycle? @@ -561,7 +575,7 @@ class Interpreter { return r; } - Value makeArray(const std::vector &v) + Value makeArray(const std::vector &v) { Value r; r.t = Value::ARRAY; @@ -569,11 +583,8 @@ class Interpreter { return r; } - Value makeClosure(const BindingFrame &env, - HeapObject *self, - unsigned offset, - const HeapClosure::Params ¶ms, - AST *body) + Value makeClosure(const BindingFrame &env, HeapObject *self, unsigned offset, + const HeapClosure::Params ¶ms, AST *body) { Value r; r.t = Value::FUNCTION; @@ -599,7 +610,8 @@ class Interpreter { return r; } - template Value makeObject(Args... args) + template + Value makeObject(Args... args) { Value r; r.t = Value::OBJECT; @@ -625,22 +637,24 @@ class Interpreter { * \param counter Return the level of "super" that contained the field. * \returns The first object with the field, or nullptr if it could not be found. */ - HeapLeafObject *findObject(const Identifier *f, HeapObject *curr, - unsigned start_from, unsigned &counter) + HeapLeafObject *findObject(const Identifier *f, HeapObject *curr, unsigned start_from, + unsigned &counter) { - if (auto *ext = dynamic_cast(curr)) { + if (auto *ext = dynamic_cast(curr)) { auto *r = findObject(f, ext->right, start_from, counter); - if (r) return r; + if (r) + return r; auto *l = findObject(f, ext->left, start_from, counter); - if (l) return l; + if (l) + return l; } else { if (counter >= start_from) { - if (auto *simp = dynamic_cast(curr)) { + if (auto *simp = dynamic_cast(curr)) { auto it = simp->fields.find(f); if (it != simp->fields.end()) { return simp; } - } else if (auto *comp = dynamic_cast(curr)) { + } else if (auto *comp = dynamic_cast(curr)) { auto it = comp->compValues.find(f); if (it != comp->compValues.end()) { return comp; @@ -652,19 +666,19 @@ class Interpreter { return nullptr; } - typedef std::map IdHideMap; + typedef std::map IdHideMap; /** Auxiliary function. */ IdHideMap objectFieldsAux(const HeapObject *obj_) { IdHideMap r; - if (auto *obj = dynamic_cast(obj_)) { + if (auto *obj = dynamic_cast(obj_)) { for (const auto &f : obj->fields) { r[f.first] = f.second.hide; } - } else if (auto *obj = dynamic_cast(obj_)) { + } else if (auto *obj = dynamic_cast(obj_)) { r = objectFieldsAux(obj->right); for (const auto &pair : objectFieldsAux(obj->left)) { auto it = r.find(pair.first); @@ -677,7 +691,7 @@ class Interpreter { } } - } else if (auto *obj = dynamic_cast(obj_)) { + } else if (auto *obj = dynamic_cast(obj_)) { for (const auto &f : obj->compValues) r[f.first] = ObjectField::VISIBLE; } @@ -686,11 +700,12 @@ class Interpreter { /** Auxiliary function. */ - std::set objectFields(const HeapObject *obj_, bool manifesting) + std::set objectFields(const HeapObject *obj_, bool manifesting) { - std::set r; + std::set r; for (const auto &pair : objectFieldsAux(obj_)) { - if (!manifesting || pair.second != ObjectField::HIDDEN) r.insert(pair.first); + if (!manifesting || pair.second != ObjectField::HIDDEN) + r.insert(pair.first); } return r; } @@ -741,9 +756,11 @@ class Interpreter { int success = 0; char *found_here_cptr; - char *content = - importCallback(importCallbackContext, dir.c_str(), encode_utf8(path).c_str(), - &found_here_cptr, &success); + char *content = importCallback(importCallbackContext, + dir.c_str(), + encode_utf8(path).c_str(), + &found_here_cptr, + &success); std::string input(content); ::free(content); @@ -764,7 +781,7 @@ class Interpreter { } /** Capture the required variables from the environment. */ - BindingFrame capture(const std::vector &free_vars) + BindingFrame capture(const std::vector &free_vars) { BindingFrame env; for (auto fv : free_vars) { @@ -781,7 +798,7 @@ class Interpreter { */ unsigned countLeaves(HeapObject *obj) { - if (auto *ext = dynamic_cast(obj)) { + if (auto *ext = dynamic_cast(obj)) { return countLeaves(ext->left) + countLeaves(ext->right); } else { // Must be a HeapLeafObject. @@ -789,34 +806,27 @@ class Interpreter { } } - public: - + public: /** Create a new interpreter. * * \param loc The location range of the file to be executed. */ - Interpreter( - Allocator *alloc, - const ExtMap &ext_vars, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &native_callbacks, - JsonnetImportCallback *import_callback, - void *import_callback_context) - - : heap(gc_min_objects, gc_growth_trigger), - stack(max_stack), - alloc(alloc), - idImport(alloc->makeIdentifier(U"import")), - idArrayElement(alloc->makeIdentifier(U"array_element")), - idInvariant(alloc->makeIdentifier(U"object_assert")), - idJsonObjVar(alloc->makeIdentifier(U"_")), - jsonObjVar(alloc->make(LocationRange(), Fodder{}, idJsonObjVar)), - externalVars(ext_vars), - nativeCallbacks(native_callbacks), - importCallback(import_callback), - importCallbackContext(import_callback_context) + Interpreter(Allocator *alloc, const ExtMap &ext_vars, unsigned max_stack, double gc_min_objects, + double gc_growth_trigger, const VmNativeCallbackMap &native_callbacks, + JsonnetImportCallback *import_callback, void *import_callback_context) + + : heap(gc_min_objects, gc_growth_trigger), + stack(max_stack), + alloc(alloc), + idImport(alloc->makeIdentifier(U"import")), + idArrayElement(alloc->makeIdentifier(U"array_element")), + idInvariant(alloc->makeIdentifier(U"object_assert")), + idJsonObjVar(alloc->makeIdentifier(U"_")), + jsonObjVar(alloc->make(LocationRange(), Fodder{}, idJsonObjVar)), + externalVars(ext_vars), + nativeCallbacks(native_callbacks), + importCallback(import_callback), + importCallbackContext(import_callback_context) { scratch = makeNull(); builtins["makeArray"] = &Interpreter::builtinMakeArray; @@ -866,20 +876,18 @@ class Interpreter { scratch = v; } - /** Raise an error if the arguments aren't the expected types. */ - void validateBuiltinArgs(const LocationRange &loc, - const std::string &name, - const std::vector &args, - const std::vector params) + void validateBuiltinArgs(const LocationRange &loc, const std::string &name, + const std::vector &args, const std::vector params) { if (args.size() == params.size()) { - for (unsigned i=0 ; i &args) { Frame &f = stack.top(); - validateBuiltinArgs(loc, "makeArray", args, - {Value::DOUBLE, Value::FUNCTION}); + validateBuiltinArgs(loc, "makeArray", args, {Value::DOUBLE, Value::FUNCTION}); long sz = long(args[0].v.d); if (sz < 0) { std::stringstream ss; ss << "makeArray requires size >= 0, got " << sz; throw makeError(loc, ss.str()); } - auto *func = static_cast(args[1].v.h); - std::vector elements; + auto *func = static_cast(args[1].v.h); + std::vector elements; if (func->params.size() != 1) { std::stringstream ss; ss << "makeArray function must take 1 param, got: " << func->params.size(); throw makeError(loc, ss.str()); } elements.resize(sz); - for (long i=0 ; i(idArrayElement, func->self, func->offset, func->body); // The next line stops the new thunks from being GCed. f.thunks.push_back(th); @@ -1004,33 +1011,19 @@ class Interpreter { const AST *builtinType(const LocationRange &, const std::vector &args) { switch (args[0].t) { - case Value::NULL_TYPE: - scratch = makeString(U"null"); - return nullptr; + case Value::NULL_TYPE: scratch = makeString(U"null"); return nullptr; - case Value::BOOLEAN: - scratch = makeString(U"boolean"); - return nullptr; + case Value::BOOLEAN: scratch = makeString(U"boolean"); return nullptr; - case Value::DOUBLE: - scratch = makeString(U"number"); - return nullptr; + case Value::DOUBLE: scratch = makeString(U"number"); return nullptr; - case Value::ARRAY: - scratch = makeString(U"array"); - return nullptr; + case Value::ARRAY: scratch = makeString(U"array"); return nullptr; - case Value::FUNCTION: - scratch = makeString(U"function"); - return nullptr; + case Value::FUNCTION: scratch = makeString(U"function"); return nullptr; - case Value::OBJECT: - scratch = makeString(U"object"); - return nullptr; + case Value::OBJECT: scratch = makeString(U"object"); return nullptr; - case Value::STRING: - scratch = makeString(U"string"); - return nullptr; + case Value::STRING: scratch = makeString(U"string"); return nullptr; } return nullptr; // Quiet, compiler. } @@ -1039,8 +1032,8 @@ class Interpreter { { Frame &f = stack.top(); validateBuiltinArgs(loc, "filter", args, {Value::FUNCTION, Value::ARRAY}); - auto *func = static_cast(args[0].v.h); - auto *arr = static_cast(args[1].v.h); + auto *func = static_cast(args[0].v.h); + auto *arr = static_cast(args[1].v.h); if (func->params.size() != 1) { throw makeError(loc, "filter function takes 1 parameter."); } @@ -1064,11 +1057,10 @@ class Interpreter { const AST *builtinObjectHasEx(const LocationRange &loc, const std::vector &args) { - validateBuiltinArgs(loc, "objectHasEx", args, - {Value::OBJECT, Value::STRING, - Value::BOOLEAN}); - const auto *obj = static_cast(args[0].v.h); - const auto *str = static_cast(args[1].v.h); + validateBuiltinArgs( + loc, "objectHasEx", args, {Value::OBJECT, Value::STRING, Value::BOOLEAN}); + const auto *obj = static_cast(args[0].v.h); + const auto *str = static_cast(args[1].v.h); bool include_hidden = args[2].v.b; bool found = false; for (const auto &field : objectFields(obj, !include_hidden)) { @@ -1079,7 +1071,7 @@ class Interpreter { } scratch = makeBoolean(found); return nullptr; - } + } const AST *builtinLength(const LocationRange &loc, const std::vector &args) { @@ -1089,35 +1081,35 @@ class Interpreter { HeapEntity *e = args[0].v.h; switch (args[0].t) { case Value::OBJECT: { - auto fields = objectFields(static_cast(e), true); + auto fields = objectFields(static_cast(e), true); scratch = makeDouble(fields.size()); } break; case Value::ARRAY: - scratch = makeDouble(static_cast(e)->elements.size()); - break; + scratch = makeDouble(static_cast(e)->elements.size()); + break; case Value::STRING: - scratch = makeDouble(static_cast(e)->value.length()); - break; + scratch = makeDouble(static_cast(e)->value.length()); + break; case Value::FUNCTION: - scratch = makeDouble(static_cast(e)->params.size()); - break; + scratch = makeDouble(static_cast(e)->params.size()); + break; default: - throw makeError(loc, - "length operates on strings, objects, " - "and arrays, got " + type_str(args[0])); + throw makeError(loc, + "length operates on strings, objects, " + "and arrays, got " + + type_str(args[0])); } return nullptr; - } + } const AST *builtinObjectFieldsEx(const LocationRange &loc, const std::vector &args) { - validateBuiltinArgs(loc, "objectFieldsEx", args, - {Value::OBJECT, Value::BOOLEAN}); - const auto *obj = static_cast(args[0].v.h); + validateBuiltinArgs(loc, "objectFieldsEx", args, {Value::OBJECT, Value::BOOLEAN}); + const auto *obj = static_cast(args[0].v.h); bool include_hidden = args[1].v.b; // Stash in a set first to sort them. std::set fields; @@ -1125,30 +1117,28 @@ class Interpreter { fields.insert(field->name); } scratch = makeArray({}); - auto &elements = static_cast(scratch.v.h)->elements; + auto &elements = static_cast(scratch.v.h)->elements; for (const auto &field : fields) { auto *th = makeHeap(idArrayElement, nullptr, 0, nullptr); elements.push_back(th); th->fill(makeString(field)); } return nullptr; - } + } const AST *builtinCodepoint(const LocationRange &loc, const std::vector &args) { validateBuiltinArgs(loc, "codepoint", args, {Value::STRING}); - const UString &str = - static_cast(args[0].v.h)->value; + const UString &str = static_cast(args[0].v.h)->value; if (str.length() != 1) { std::stringstream ss; - ss << "codepoint takes a string of length 1, got length " - << str.length(); + ss << "codepoint takes a string of length 1, got length " << str.length(); throw makeError(loc, ss.str()); } - char32_t c = static_cast(args[0].v.h)->value[0]; + char32_t c = static_cast(args[0].v.h)->value[0]; scratch = makeDouble((unsigned long)(c)); return nullptr; - } + } const AST *builtinChar(const LocationRange &loc, const std::vector &args) { @@ -1167,21 +1157,21 @@ class Interpreter { char32_t c = l; scratch = makeString(UString(&c, 1)); return nullptr; - } + } const AST *builtinLog(const LocationRange &loc, const std::vector &args) { validateBuiltinArgs(loc, "log", args, {Value::DOUBLE}); scratch = makeDoubleCheck(loc, std::log(args[0].v.d)); return nullptr; - } + } const AST *builtinExp(const LocationRange &loc, const std::vector &args) { validateBuiltinArgs(loc, "exp", args, {Value::DOUBLE}); scratch = makeDoubleCheck(loc, std::exp(args[0].v.d)); return nullptr; - } + } const AST *builtinMantissa(const LocationRange &loc, const std::vector &args) { @@ -1190,7 +1180,7 @@ class Interpreter { double m = std::frexp(args[0].v.d, &exp); scratch = makeDoubleCheck(loc, m); return nullptr; - } + } const AST *builtinExponent(const LocationRange &loc, const std::vector &args) { @@ -1199,7 +1189,7 @@ class Interpreter { std::frexp(args[0].v.d, &exp); scratch = makeDoubleCheck(loc, exp); return nullptr; - } + } const AST *builtinModulo(const LocationRange &loc, const std::vector &args) { @@ -1210,13 +1200,12 @@ class Interpreter { throw makeError(loc, "Division by zero."); scratch = makeDoubleCheck(loc, std::fmod(a, b)); return nullptr; - } + } const AST *builtinExtVar(const LocationRange &loc, const std::vector &args) { validateBuiltinArgs(loc, "extVar", args, {Value::STRING}); - const UString &var = - static_cast(args[0].v.h)->value; + const UString &var = static_cast(args[0].v.h)->value; std::string var8 = encode_utf8(var); auto it = externalVars.find(var8); if (it == externalVars.end()) { @@ -1236,7 +1225,7 @@ class Interpreter { scratch = makeString(decode_utf8(ext.data)); return nullptr; } - } + } const AST *builtinPrimitiveEquals(const LocationRange &loc, const std::vector &args) { @@ -1251,41 +1240,34 @@ class Interpreter { } bool r; switch (args[0].t) { - case Value::BOOLEAN: - r = args[0].v.b == args[1].v.b; - break; + case Value::BOOLEAN: r = args[0].v.b == args[1].v.b; break; - case Value::DOUBLE: - r = args[0].v.d == args[1].v.d; - break; + case Value::DOUBLE: r = args[0].v.d == args[1].v.d; break; case Value::STRING: - r = static_cast(args[0].v.h)->value - == static_cast(args[1].v.h)->value; - break; + r = static_cast(args[0].v.h)->value == + static_cast(args[1].v.h)->value; + break; - case Value::NULL_TYPE: - r = true; - break; + case Value::NULL_TYPE: r = true; break; - case Value::FUNCTION: - throw makeError(loc, "Cannot test equality of functions"); - break; + case Value::FUNCTION: throw makeError(loc, "Cannot test equality of functions"); break; default: - throw makeError(loc, - "primitiveEquals operates on primitive " - "types, got " + type_str(args[0])); + throw makeError(loc, + "primitiveEquals operates on primitive " + "types, got " + + type_str(args[0])); } scratch = makeBoolean(r); return nullptr; - } + } const AST *builtinNative(const LocationRange &loc, const std::vector &args) { validateBuiltinArgs(loc, "native", args, {Value::STRING}); - std::string builtin_name = encode_utf8(static_cast(args[0].v.h)->value); + std::string builtin_name = encode_utf8(static_cast(args[0].v.h)->value); VmNativeCallbackMap::const_iterator nit = nativeCallbacks.find(builtin_name); if (nit == nativeCallbacks.end()) { @@ -1295,13 +1277,13 @@ class Interpreter { const VmNativeCallback &cb = nit->second; scratch = makeNativeBuiltin(builtin_name, cb.params); return nullptr; - } + } const AST *builtinMd5(const LocationRange &loc, const std::vector &args) { validateBuiltinArgs(loc, "md5", args, {Value::STRING}); - std::string value = encode_utf8(static_cast(args[0].v.h)->value); + std::string value = encode_utf8(static_cast(args[0].v.h)->value); scratch = makeString(decode_utf8(md5(value))); return nullptr; @@ -1313,30 +1295,30 @@ class Interpreter { // making the heap object. switch (v->kind) { case JsonnetJsonValue::STRING: - attach = makeString(decode_utf8(v->string)); - filled = true; - break; + attach = makeString(decode_utf8(v->string)); + filled = true; + break; case JsonnetJsonValue::BOOL: - attach = makeBoolean(v->number != 0.0); - filled = true; - break; + attach = makeBoolean(v->number != 0.0); + filled = true; + break; case JsonnetJsonValue::NUMBER: - attach = makeDouble(v->number); - filled = true; - break; + attach = makeDouble(v->number); + filled = true; + break; case JsonnetJsonValue::NULL_KIND: - attach = makeNull(); - filled = true; - break; + attach = makeNull(); + filled = true; + break; case JsonnetJsonValue::ARRAY: { - attach = makeArray(std::vector{}); + attach = makeArray(std::vector{}); filled = true; - auto *arr = static_cast(attach.v.h); - for (size_t i = 0; i < v->elements.size() ; ++i) { + auto *arr = static_cast(attach.v.h); + for (size_t i = 0; i < v->elements.size(); ++i) { arr->elements.push_back( makeHeap(idArrayElement, nullptr, 0, nullptr)); jsonToHeap(v->elements[i], arr->elements[i]->filled, arr->elements[i]->content); @@ -1347,7 +1329,7 @@ class Interpreter { attach = makeObject( BindingFrame{}, jsonObjVar, idJsonObjVar, BindingFrame{}); filled = true; - auto *obj = static_cast(attach.v.h); + auto *obj = static_cast(attach.v.h); for (const auto &pair : v->fields) { auto *thunk = makeHeap(idJsonObjVar, nullptr, 0, nullptr); obj->compValues[alloc->makeIdentifier(decode_utf8(pair.first))] = thunk; @@ -1357,14 +1339,11 @@ class Interpreter { } } - UString toString(const LocationRange &loc) { return manifestJson(loc, false, U""); } - - /** Recursively collect an object's invariants. * * \param curr @@ -1372,14 +1351,14 @@ class Interpreter { * \param offset * \param thunks */ - void objectInvariants(HeapObject *curr, HeapObject *self, - unsigned &counter, std::vector &thunks) + void objectInvariants(HeapObject *curr, HeapObject *self, unsigned &counter, + std::vector &thunks) { - if (auto *ext = dynamic_cast(curr)) { + if (auto *ext = dynamic_cast(curr)) { objectInvariants(ext->right, self, counter, thunks); objectInvariants(ext->left, self, counter, thunks); } else { - if (auto *simp = dynamic_cast(curr)) { + if (auto *simp = dynamic_cast(curr)) { for (AST *assert : simp->asserts) { auto *el_th = makeHeap(idInvariant, self, counter, assert); el_th->upValues = simp->upValues; @@ -1396,8 +1375,8 @@ class Interpreter { * \param obj The target * \param f The field */ - const AST *objectIndex(const LocationRange &loc, HeapObject *obj, - const Identifier *f, unsigned offset) + const AST *objectIndex(const LocationRange &loc, HeapObject *obj, const Identifier *f, + unsigned offset) { unsigned found_at = 0; HeapObject *self = obj; @@ -1405,7 +1384,7 @@ class Interpreter { if (found == nullptr) { throw makeError(loc, "Field does not exist: " + encode_utf8(f->name)); } - if (auto *simp = dynamic_cast(found)) { + if (auto *simp = dynamic_cast(found)) { auto it = simp->fields.find(f); const AST *body = it->second.body; @@ -1413,7 +1392,7 @@ class Interpreter { return body; } else { // If a HeapLeafObject is not HeapSimpleObject, it must be HeapComprehensionObject. - auto *comp = static_cast(found); + auto *comp = static_cast(found); auto it = comp->compValues.find(f); auto *th = it->second; BindingFrame binds = comp->upValues; @@ -1425,12 +1404,13 @@ class Interpreter { void runInvariants(const LocationRange &loc, HeapObject *self) { - if (stack.alreadyExecutingInvariants(self)) return; + if (stack.alreadyExecutingInvariants(self)) + return; unsigned counter = 0; unsigned initial_stack_size = stack.size(); stack.newFrame(FRAME_INVARIANTS, loc); - std::vector &thunks = stack.top().thunks; + std::vector &thunks = stack.top().thunks; objectInvariants(self, self, counter, thunks); if (thunks.size() == 0) { stack.pop(); @@ -1457,39 +1437,39 @@ class Interpreter { */ void evaluate(const AST *ast_, unsigned initial_stack_size) { - recurse: + recurse: switch (ast_->type) { case AST_APPLY: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_APPLY_TARGET, ast_); ast_ = ast.target; goto recurse; } break; case AST_ARRAY: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); HeapObject *self; unsigned offset; stack.getSelfBinding(self, offset); scratch = makeArray({}); - auto &elements = static_cast(scratch.v.h)->elements; + auto &elements = static_cast(scratch.v.h)->elements; for (const auto &el : ast.elements) { auto *el_th = makeHeap(idArrayElement, self, offset, el.expr); - el_th->upValues = capture(el.expr->freeVariables); + el_th->upValues = capture(el.expr->freeVariables); elements.push_back(el_th); } } break; case AST_BINARY: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_BINARY_LEFT, ast_); ast_ = ast.left; goto recurse; } break; case AST_BUILTIN_FUNCTION: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); HeapClosure::Params params; params.reserve(ast.params.size()); for (const auto &p : ast.params) { @@ -1500,21 +1480,21 @@ class Interpreter { } break; case AST_CONDITIONAL: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_IF, ast_); ast_ = ast.cond; goto recurse; } break; case AST_ERROR: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_ERROR, ast_); ast_ = ast.expr; goto recurse; } break; case AST_FUNCTION: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); auto env = capture(ast.freeVariables); HeapObject *self; unsigned offset; @@ -1528,7 +1508,7 @@ class Interpreter { } break; case AST_IMPORT: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); HeapThunk *thunk = import(ast.location, ast.file); if (thunk->filled) { scratch = thunk->content; @@ -1540,27 +1520,27 @@ class Interpreter { } break; case AST_IMPORTSTR: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); const ImportCacheValue *value = importString(ast.location, ast.file); scratch = makeString(decode_utf8(value->content)); } break; case AST_IN_SUPER: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_IN_SUPER_ELEMENT, ast_); ast_ = ast.element; goto recurse; } break; case AST_INDEX: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_INDEX_TARGET, ast_); ast_ = ast.target; goto recurse; } break; case AST_LOCAL: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_LOCAL, ast_); Frame &f = stack.top(); // First build all the thunks and bind them. @@ -1583,17 +1563,17 @@ class Interpreter { } break; case AST_LITERAL_BOOLEAN: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); scratch = makeBoolean(ast.value); } break; case AST_LITERAL_NUMBER: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); scratch = makeDoubleCheck(ast_->location, ast.value); } break; case AST_LITERAL_STRING: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); scratch = makeString(ast.value); } break; @@ -1602,7 +1582,7 @@ class Interpreter { } break; case AST_DESUGARED_OBJECT: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); if (ast.fields.empty()) { auto env = capture(ast.freeVariables); std::map fields; @@ -1618,7 +1598,7 @@ class Interpreter { } break; case AST_OBJECT_COMPREHENSION_SIMPLE: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_OBJECT_COMP_ARRAY, ast_); ast_ = ast.array; goto recurse; @@ -1633,21 +1613,21 @@ class Interpreter { } break; case AST_SUPER_INDEX: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_SUPER_INDEX, ast_); ast_ = ast.index; goto recurse; } break; case AST_UNARY: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); stack.newFrame(FRAME_UNARY, ast_); ast_ = ast.expr; goto recurse; } break; case AST_VAR: { - const auto &ast = *static_cast(ast_); + const auto &ast = *static_cast(ast_); auto *thunk = stack.lookUpVar(ast.id); if (thunk == nullptr) { std::cerr << "INTERNAL ERROR: Could not bind variable: " @@ -1664,8 +1644,8 @@ class Interpreter { } break; default: - std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_->type << std::endl; - std::abort(); + std::cerr << "INTERNAL ERROR: Unknown AST: " << ast_->type << std::endl; + std::abort(); } // To evaluate another AST, set ast to it, then goto recurse. @@ -1675,13 +1655,12 @@ class Interpreter { Frame &f = stack.top(); switch (f.kind) { case FRAME_APPLY_TARGET: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); if (scratch.t != Value::FUNCTION) { throw makeError(ast.location, - "Only functions can be called, got " - + type_str(scratch)); + "Only functions can be called, got " + type_str(scratch)); } - auto *func = static_cast(scratch.v.h); + auto *func = static_cast(scratch.v.h); std::set params_needed; for (const auto ¶m : func->params) { @@ -1689,10 +1668,10 @@ class Interpreter { } // Create thunks for arguments. - std::vector positional_args; + std::vector positional_args; BindingFrame args; bool got_named = false; - for (unsigned i=0 ; i def_arg_thunks; + std::vector def_arg_thunks; for (const auto ¶m : func->params) { - if (args.find(param.id) != args.end()) continue; + if (args.find(param.id) != args.end()) + continue; if (param.def == nullptr) { std::stringstream ss; - ss << "Function parameter " << encode_utf8(param.id->name) << - " not bound in call."; + ss << "Function parameter " << encode_utf8(param.id->name) + << " not bound in call."; throw makeError(ast.location, ss.str()); } // Special case for builtin functions -- leave identifier blank for // them in the thunk. This removes the thunk frame from the stacktrace. const Identifier *name_ = func->body == nullptr ? nullptr : param.id; - auto *thunk = makeHeap(name_, func->self, func->offset, - param.def); + auto *thunk = + makeHeap(name_, func->self, func->offset, param.def); f.thunks.push_back(thunk); def_arg_thunks.push_back(thunk); args[param.id] = thunk; @@ -1773,7 +1753,7 @@ class Interpreter { } // Cache these, because pop will invalidate them. - std::vector thunks_copy = f.thunks; + std::vector thunks_copy = f.thunks; stack.pop(); @@ -1808,7 +1788,7 @@ class Interpreter { } break; case FRAME_BINARY_LEFT: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); const Value &lhs = scratch; if (lhs.t == Value::BOOLEAN) { // Handle short-cut semantics @@ -1837,7 +1817,7 @@ class Interpreter { } break; case FRAME_BINARY_RIGHT: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); const Value &lhs = stack.top().val; const Value &rhs = scratch; @@ -1853,35 +1833,38 @@ class Interpreter { switch (ast.op) { // Equality can be used when the types don't match. case BOP_MANIFEST_EQUAL: - std::cerr << "INTERNAL ERROR: Equals not desugared" << std::endl; - abort(); + std::cerr << "INTERNAL ERROR: Equals not desugared" << std::endl; + abort(); // Equality can be used when the types don't match. case BOP_MANIFEST_UNEQUAL: - std::cerr << "INTERNAL ERROR: Notequals not desugared" << std::endl; - abort(); + std::cerr << "INTERNAL ERROR: Notequals not desugared" << std::endl; + abort(); // e in e case BOP_IN: { if (lhs.t != Value::STRING) { throw makeError(ast.location, "The left hand side of the 'in' operator should be " - "a string, got " + type_str(lhs)); + "a string, got " + + type_str(lhs)); } - auto *field = static_cast(lhs.v.h); + auto *field = static_cast(lhs.v.h); switch (rhs.t) { case Value::OBJECT: { - auto *obj = static_cast(rhs.v.h); + auto *obj = static_cast(rhs.v.h); auto *fid = alloc->makeIdentifier(field->value); unsigned unused_found_at = 0; bool in = findObject(fid, obj, 0, unused_found_at); scratch = makeBoolean(in); } break; - + default: - throw makeError(ast.location, - "The right hand side of the 'in' operator should be" - " an object, got " + type_str(rhs)); + throw makeError( + ast.location, + "The right hand side of the 'in' operator should be" + " an object, got " + + type_str(rhs)); } goto popframe; } @@ -1891,186 +1874,168 @@ class Interpreter { // Everything else requires matching types. if (lhs.t != rhs.t) { throw makeError(ast.location, - "Binary operator " + bop_string(ast.op) + " requires " - "matching types, got " + type_str(lhs) + " and " + - type_str(rhs) + "."); + "Binary operator " + bop_string(ast.op) + + " requires " + "matching types, got " + + type_str(lhs) + " and " + type_str(rhs) + "."); } switch (lhs.t) { case Value::ARRAY: - if (ast.op == BOP_PLUS) { - auto *arr_l = static_cast(lhs.v.h); - auto *arr_r = static_cast(rhs.v.h); - std::vector elements; - for (auto *el : arr_l->elements) - elements.push_back(el); - for (auto *el : arr_r->elements) - elements.push_back(el); - scratch = makeArray(elements); - } else { - throw makeError(ast.location, - "Binary operator " + bop_string(ast.op) - + " does not operate on arrays."); - } - break; + if (ast.op == BOP_PLUS) { + auto *arr_l = static_cast(lhs.v.h); + auto *arr_r = static_cast(rhs.v.h); + std::vector elements; + for (auto *el : arr_l->elements) + elements.push_back(el); + for (auto *el : arr_r->elements) + elements.push_back(el); + scratch = makeArray(elements); + } else { + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on arrays."); + } + break; case Value::BOOLEAN: - switch (ast.op) { - case BOP_AND: - scratch = makeBoolean(lhs.v.b && rhs.v.b); - break; + switch (ast.op) { + case BOP_AND: scratch = makeBoolean(lhs.v.b && rhs.v.b); break; - case BOP_OR: - scratch = makeBoolean(lhs.v.b || rhs.v.b); - break; + case BOP_OR: scratch = makeBoolean(lhs.v.b || rhs.v.b); break; - default: - throw makeError(ast.location, - "Binary operator " + bop_string(ast.op) - + " does not operate on booleans."); - } - break; + default: + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on booleans."); + } + break; case Value::DOUBLE: - switch (ast.op) { - case BOP_PLUS: - scratch = makeDoubleCheck(ast.location, lhs.v.d + rhs.v.d); - break; + switch (ast.op) { + case BOP_PLUS: + scratch = makeDoubleCheck(ast.location, lhs.v.d + rhs.v.d); + break; - case BOP_MINUS: - scratch = makeDoubleCheck(ast.location, lhs.v.d - rhs.v.d); - break; + case BOP_MINUS: + scratch = makeDoubleCheck(ast.location, lhs.v.d - rhs.v.d); + break; - case BOP_MULT: - scratch = makeDoubleCheck(ast.location, lhs.v.d * rhs.v.d); - break; + case BOP_MULT: + scratch = makeDoubleCheck(ast.location, lhs.v.d * rhs.v.d); + break; - case BOP_DIV: - if (rhs.v.d == 0) - throw makeError(ast.location, "Division by zero."); - scratch = makeDoubleCheck(ast.location, lhs.v.d / rhs.v.d); - break; + case BOP_DIV: + if (rhs.v.d == 0) + throw makeError(ast.location, "Division by zero."); + scratch = makeDoubleCheck(ast.location, lhs.v.d / rhs.v.d); + break; - // No need to check doubles made from longs + // No need to check doubles made from longs - case BOP_SHIFT_L: { - long long_l = lhs.v.d; - long long_r = rhs.v.d; - scratch = makeDouble(long_l << long_r); - } break; + case BOP_SHIFT_L: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l << long_r); + } break; - case BOP_SHIFT_R: { - long long_l = lhs.v.d; - long long_r = rhs.v.d; - scratch = makeDouble(long_l >> long_r); - } break; + case BOP_SHIFT_R: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l >> long_r); + } break; - case BOP_BITWISE_AND: { - long long_l = lhs.v.d; - long long_r = rhs.v.d; - scratch = makeDouble(long_l & long_r); - } break; + case BOP_BITWISE_AND: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l & long_r); + } break; - case BOP_BITWISE_XOR: { - long long_l = lhs.v.d; - long long_r = rhs.v.d; - scratch = makeDouble(long_l ^ long_r); - } break; + case BOP_BITWISE_XOR: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l ^ long_r); + } break; - case BOP_BITWISE_OR: { - long long_l = lhs.v.d; - long long_r = rhs.v.d; - scratch = makeDouble(long_l | long_r); - } break; + case BOP_BITWISE_OR: { + long long_l = lhs.v.d; + long long_r = rhs.v.d; + scratch = makeDouble(long_l | long_r); + } break; - case BOP_LESS_EQ: - scratch = makeBoolean(lhs.v.d <= rhs.v.d); - break; + case BOP_LESS_EQ: scratch = makeBoolean(lhs.v.d <= rhs.v.d); break; - case BOP_GREATER_EQ: - scratch = makeBoolean(lhs.v.d >= rhs.v.d); - break; + case BOP_GREATER_EQ: + scratch = makeBoolean(lhs.v.d >= rhs.v.d); + break; - case BOP_LESS: - scratch = makeBoolean(lhs.v.d < rhs.v.d); - break; + case BOP_LESS: scratch = makeBoolean(lhs.v.d < rhs.v.d); break; - case BOP_GREATER: - scratch = makeBoolean(lhs.v.d > rhs.v.d); - break; + case BOP_GREATER: scratch = makeBoolean(lhs.v.d > rhs.v.d); break; - default: - throw makeError(ast.location, - "Binary operator " + bop_string(ast.op) - + " does not operate on numbers."); - } - break; + default: + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on numbers."); + } + break; case Value::FUNCTION: - throw makeError(ast.location, "Binary operator " + bop_string(ast.op) + - " does not operate on functions."); + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on functions."); case Value::NULL_TYPE: - throw makeError(ast.location, "Binary operator " + bop_string(ast.op) + - " does not operate on null."); + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on null."); case Value::OBJECT: { if (ast.op != BOP_PLUS) { throw makeError(ast.location, "Binary operator " + bop_string(ast.op) + - " does not operate on objects."); + " does not operate on objects."); } - auto *lhs_obj = static_cast(lhs.v.h); - auto *rhs_obj = static_cast(rhs.v.h); + auto *lhs_obj = static_cast(lhs.v.h); + auto *rhs_obj = static_cast(rhs.v.h); scratch = makeObject(lhs_obj, rhs_obj); - } - break; + } break; case Value::STRING: { - const UString &lhs_str = - static_cast(lhs.v.h)->value; - const UString &rhs_str = - static_cast(rhs.v.h)->value; + const UString &lhs_str = static_cast(lhs.v.h)->value; + const UString &rhs_str = static_cast(rhs.v.h)->value; switch (ast.op) { - case BOP_PLUS: - scratch = makeString(lhs_str + rhs_str); - break; + case BOP_PLUS: scratch = makeString(lhs_str + rhs_str); break; - case BOP_LESS_EQ: - scratch = makeBoolean(lhs_str <= rhs_str); - break; + case BOP_LESS_EQ: scratch = makeBoolean(lhs_str <= rhs_str); break; case BOP_GREATER_EQ: - scratch = makeBoolean(lhs_str >= rhs_str); - break; + scratch = makeBoolean(lhs_str >= rhs_str); + break; - case BOP_LESS: - scratch = makeBoolean(lhs_str < rhs_str); - break; + case BOP_LESS: scratch = makeBoolean(lhs_str < rhs_str); break; - case BOP_GREATER: - scratch = makeBoolean(lhs_str > rhs_str); - break; + case BOP_GREATER: scratch = makeBoolean(lhs_str > rhs_str); break; default: - throw makeError(ast.location, - "Binary operator " + bop_string(ast.op) - + " does not operate on strings."); + throw makeError(ast.location, + "Binary operator " + bop_string(ast.op) + + " does not operate on strings."); } - } - break; + } break; } } break; case FRAME_BUILTIN_FILTER: { - const auto &ast = *static_cast(f.ast); - auto *func = static_cast(f.val.v.h); - auto *arr = static_cast(f.val2.v.h); + const auto &ast = *static_cast(f.ast); + auto *func = static_cast(f.val.v.h); + auto *arr = static_cast(f.val2.v.h); if (scratch.t != Value::BOOLEAN) { - throw makeError(ast.location, - "filter function must return boolean, got: " - + type_str(scratch)); + throw makeError( + ast.location, + "filter function must return boolean, got: " + type_str(scratch)); } - if (scratch.v.b) f.thunks.push_back(arr->elements[f.elementId]); + if (scratch.v.b) + f.thunks.push_back(arr->elements[f.elementId]); f.elementId++; // Iterate through arr, calling the function on each. if (f.elementId == arr->elements.size()) { @@ -2086,8 +2051,8 @@ class Interpreter { } break; case FRAME_BUILTIN_FORCE_THUNKS: { - const auto &ast = *static_cast(f.ast); - auto *func = static_cast(f.val.v.h); + const auto &ast = *static_cast(f.ast); + auto *func = static_cast(f.val.v.h); if (f.elementId == f.thunks.size()) { // All thunks forced, now the builtin implementations. const LocationRange &loc = ast.location; @@ -2113,53 +2078,52 @@ class Interpreter { for (const Value &arg : args) { switch (arg.t) { case Value::STRING: - args2.push_back(JsonnetJsonValue{ - JsonnetJsonValue::STRING, - encode_utf8(static_cast(arg.v.h)->value), - 0, - std::vector>{}, - std::map>{}, - }); - break; + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::STRING, + encode_utf8(static_cast(arg.v.h)->value), + 0, + std::vector>{}, + std::map>{}, + }); + break; case Value::BOOLEAN: - args2.push_back(JsonnetJsonValue{ - JsonnetJsonValue::BOOL, - "", - arg.v.b ? 1.0 : 0.0, - std::vector>{}, - std::map>{}, - }); - break; + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::BOOL, + "", + arg.v.b ? 1.0 : 0.0, + std::vector>{}, + std::map>{}, + }); + break; case Value::DOUBLE: - args2.push_back(JsonnetJsonValue{ - JsonnetJsonValue::NUMBER, - "", - arg.v.d, - std::vector>{}, - std::map>{}, - }); - break; + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::NUMBER, + "", + arg.v.d, + std::vector>{}, + std::map>{}, + }); + break; case Value::NULL_TYPE: - args2.push_back(JsonnetJsonValue{ - JsonnetJsonValue::NULL_KIND, - "", - 0, - std::vector>{}, - std::map>{}, - }); - break; + args2.push_back(JsonnetJsonValue{ + JsonnetJsonValue::NULL_KIND, + "", + 0, + std::vector>{}, + std::map>{}, + }); + break; default: - throw makeError(ast.location, - "Native extensions can only take primitives."); + throw makeError(ast.location, + "Native extensions can only take primitives."); } - } - std::vector args3; - for (size_t i = 0; i < args2.size() ; ++i) { + std::vector args3; + for (size_t i = 0; i < args2.size(); ++i) { args3.push_back(&args2[i]); } if (nit == nativeCallbacks.end()) { @@ -2196,16 +2160,15 @@ class Interpreter { } break; case FRAME_CALL: { - if (auto *thunk = dynamic_cast(f.context)) { + if (auto *thunk = dynamic_cast(f.context)) { // If we called a thunk, cache result. thunk->fill(scratch); - } else if (auto *closure = dynamic_cast(f.context)) { + } else if (auto *closure = dynamic_cast(f.context)) { if (f.elementId < f.thunks.size()) { // If tailstrict, force thunks HeapThunk *th = f.thunks[f.elementId++]; if (!th->filled) { - stack.newCall(f.location, th, - th->self, th->offset, th->upValues); + stack.newCall(f.location, th, th->self, th->offset, th->upValues); ast_ = th->body; goto recurse; } @@ -2223,10 +2186,10 @@ class Interpreter { } break; case FRAME_ERROR: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); UString msg; if (scratch.t == Value::STRING) { - msg = static_cast(scratch.v.h)->value; + msg = static_cast(scratch.v.h)->value; } else { msg = toString(ast.location); } @@ -2234,10 +2197,11 @@ class Interpreter { } break; case FRAME_IF: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); if (scratch.t != Value::BOOLEAN) { - throw makeError(ast.location, "Condition must be boolean, got " + - type_str(scratch) + "."); + throw makeError( + ast.location, + "Condition must be boolean, got " + type_str(scratch) + "."); } ast_ = scratch.v.b ? ast.branchTrue : ast.branchFalse; stack.pop(); @@ -2245,7 +2209,7 @@ class Interpreter { } break; case FRAME_SUPER_INDEX: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); HeapObject *self; unsigned offset; stack.getSelfBinding(self, offset); @@ -2255,13 +2219,12 @@ class Interpreter { "Attempt to use super when there is no super class."); } if (scratch.t != Value::STRING) { - throw makeError(ast.location, - "Super index must be string, got " - + type_str(scratch) + "."); + throw makeError( + ast.location, + "Super index must be string, got " + type_str(scratch) + "."); } - const UString &index_name = - static_cast(scratch.v.h)->value; + const UString &index_name = static_cast(scratch.v.h)->value; auto *fid = alloc->makeIdentifier(index_name); stack.pop(); ast_ = objectIndex(ast.location, self, fid, offset); @@ -2269,22 +2232,21 @@ class Interpreter { } break; case FRAME_IN_SUPER_ELEMENT: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); HeapObject *self; unsigned offset; stack.getSelfBinding(self, offset); offset++; if (scratch.t != Value::STRING) { throw makeError(ast.location, - "Left hand side of e in super must be string, got " - + type_str(scratch) + "."); + "Left hand side of e in super must be string, got " + + type_str(scratch) + "."); } if (offset >= countLeaves(self)) { // There is no super object. scratch = makeBoolean(false); } else { - const UString &element_name = - static_cast(scratch.v.h)->value; + const UString &element_name = static_cast(scratch.v.h)->value; auto *fid = alloc->makeIdentifier(element_name); unsigned unused_found_at = 0; bool in = findObject(fid, self, offset, unused_found_at); @@ -2293,20 +2255,20 @@ class Interpreter { } break; case FRAME_INDEX_INDEX: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); const Value &target = f.val; if (target.t == Value::ARRAY) { - const auto *array = static_cast(target.v.h); + const auto *array = static_cast(target.v.h); if (scratch.t != Value::DOUBLE) { - throw makeError(ast.location, "Array index must be number, got " - + type_str(scratch) + "."); + throw makeError( + ast.location, + "Array index must be number, got " + type_str(scratch) + "."); } long i = long(scratch.v.d); long sz = array->elements.size(); if (i < 0 || i >= sz) { std::stringstream ss; - ss << "Array bounds error: " << i - << " not within [0, " << sz << ")"; + ss << "Array bounds error: " << i << " not within [0, " << sz << ")"; throw makeError(ast.location, ss.str()); } auto *thunk = array->elements[i]; @@ -2314,39 +2276,37 @@ class Interpreter { scratch = thunk->content; } else { stack.pop(); - stack.newCall(ast.location, thunk, - thunk->self, thunk->offset, thunk->upValues); + stack.newCall( + ast.location, thunk, thunk->self, thunk->offset, thunk->upValues); ast_ = thunk->body; goto recurse; } } else if (target.t == Value::OBJECT) { - auto *obj = static_cast(target.v.h); + auto *obj = static_cast(target.v.h); assert(obj != nullptr); if (scratch.t != Value::STRING) { - throw makeError(ast.location, - "Object index must be string, got " - + type_str(scratch) + "."); + throw makeError( + ast.location, + "Object index must be string, got " + type_str(scratch) + "."); } - const UString &index_name = - static_cast(scratch.v.h)->value; + const UString &index_name = static_cast(scratch.v.h)->value; auto *fid = alloc->makeIdentifier(index_name); stack.pop(); ast_ = objectIndex(ast.location, obj, fid, 0); goto recurse; } else if (target.t == Value::STRING) { - auto *obj = static_cast(target.v.h); + auto *obj = static_cast(target.v.h); assert(obj != nullptr); if (scratch.t != Value::DOUBLE) { - throw makeError(ast.location, - "UString index must be a number, got " - + type_str(scratch) + "."); + throw makeError( + ast.location, + "UString index must be a number, got " + type_str(scratch) + "."); } long sz = obj->value.length(); long i = (long)scratch.v.d; if (i < 0 || i >= sz) { std::stringstream ss; - ss << "UString bounds error: " << i - << " not within [0, " << sz << ")"; + ss << "UString bounds error: " << i << " not within [0, " << sz << ")"; throw makeError(ast.location, ss.str()); } char32_t ch[] = {obj->value[i], U'\0'}; @@ -2358,18 +2318,17 @@ class Interpreter { } break; case FRAME_INDEX_TARGET: { - const auto &ast = *static_cast(f.ast); - if (scratch.t != Value::ARRAY - && scratch.t != Value::OBJECT - && scratch.t != Value::STRING) { + const auto &ast = *static_cast(f.ast); + if (scratch.t != Value::ARRAY && scratch.t != Value::OBJECT && + scratch.t != Value::STRING) { throw makeError(ast.location, - "Can only index objects, strings, and arrays, got " - + type_str(scratch) + "."); + "Can only index objects, strings, and arrays, got " + + type_str(scratch) + "."); } f.val = scratch; f.kind = FRAME_INDEX_INDEX; if (scratch.t == Value::OBJECT) { - auto *self = static_cast(scratch.v.h); + auto *self = static_cast(scratch.v.h); if (!stack.alreadyExecutingInvariants(self)) { stack.newFrame(FRAME_INVARIANTS, ast.location); Frame &f2 = stack.top(); @@ -2379,8 +2338,11 @@ class Interpreter { if (f2.thunks.size() > 0) { auto *thunk = f2.thunks[0]; f2.elementId = 1; - stack.newCall(ast.location, thunk, - thunk->self, thunk->offset, thunk->upValues); + stack.newCall(ast.location, + thunk, + thunk->self, + thunk->offset, + thunk->upValues); ast_ = thunk->body; goto recurse; } @@ -2398,13 +2360,12 @@ class Interpreter { } stack.pop(); Frame &f2 = stack.top(); - const auto &ast = *static_cast(f2.ast); + const auto &ast = *static_cast(f2.ast); ast_ = ast.index; goto recurse; } auto *thunk = f.thunks[f.elementId++]; - stack.newCall(f.location, thunk, - thunk->self, thunk->offset, thunk->upValues); + stack.newCall(f.location, thunk, thunk->self, thunk->offset, thunk->upValues); ast_ = thunk->body; goto recurse; } break; @@ -2414,16 +2375,16 @@ class Interpreter { } break; case FRAME_OBJECT: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); if (scratch.t != Value::NULL_TYPE) { if (scratch.t != Value::STRING) { throw makeError(ast.location, "Field name was not a string."); } - const auto &fname = static_cast(scratch.v.h)->value; + const auto &fname = static_cast(scratch.v.h)->value; const Identifier *fid = alloc->makeIdentifier(fname); if (f.objectFields.find(fid) != f.objectFields.end()) { - std::string msg = "Duplicate field name: \"" - + encode_utf8(fname) + "\""; + std::string msg = + "Duplicate field name: \"" + encode_utf8(fname) + "\""; throw makeError(ast.location, msg); } f.objectFields[fid].hide = f.fit->hide; @@ -2440,18 +2401,17 @@ class Interpreter { } break; case FRAME_OBJECT_COMP_ARRAY: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); const Value &arr_v = scratch; if (scratch.t != Value::ARRAY) { throw makeError(ast.location, - "Object comprehension needs array, got " - + type_str(arr_v)); + "Object comprehension needs array, got " + type_str(arr_v)); } - const auto *arr = static_cast(arr_v.v.h); + const auto *arr = static_cast(arr_v.v.h); if (arr->elements.size() == 0) { // Degenerate case. Just create the object now. - scratch = makeObject(BindingFrame{}, ast.value, - ast.id, BindingFrame{}); + scratch = makeObject( + BindingFrame{}, ast.value, ast.id, BindingFrame{}); } else { f.kind = FRAME_OBJECT_COMP_ELEMENT; f.val = scratch; @@ -2463,14 +2423,14 @@ class Interpreter { } break; case FRAME_OBJECT_COMP_ELEMENT: { - const auto &ast = *static_cast(f.ast); - const auto *arr = static_cast(f.val.v.h); + const auto &ast = *static_cast(f.ast); + const auto *arr = static_cast(f.val.v.h); if (scratch.t != Value::STRING) { std::stringstream ss; ss << "field must be string, got: " << type_str(scratch); throw makeError(ast.location, ss.str()); } - const auto &fname = static_cast(scratch.v.h)->value; + const auto &fname = static_cast(scratch.v.h)->value; const Identifier *fid = alloc->makeIdentifier(fname); if (f.elements.find(fid) != f.elements.end()) { throw makeError(ast.location, @@ -2481,8 +2441,8 @@ class Interpreter { if (f.elementId == arr->elements.size()) { auto env = capture(ast.freeVariables); - scratch = makeObject(env, ast.value, - ast.id, f.elements); + scratch = + makeObject(env, ast.value, ast.id, f.elements); } else { f.bindings[ast.id] = arr->elements[f.elementId]; ast_ = ast.field; @@ -2491,18 +2451,18 @@ class Interpreter { } break; case FRAME_STRING_CONCAT: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); const Value &lhs = stack.top().val; const Value &rhs = stack.top().val2; UString output; if (lhs.t == Value::STRING) { - output.append(static_cast(lhs.v.h)->value); + output.append(static_cast(lhs.v.h)->value); } else { scratch = lhs; output.append(toString(ast.left->location)); } if (rhs.t == Value::STRING) { - output.append(static_cast(rhs.v.h)->value); + output.append(static_cast(rhs.v.h)->value); } else { scratch = rhs; output.append(toString(ast.right->location)); @@ -2511,56 +2471,52 @@ class Interpreter { } break; case FRAME_UNARY: { - const auto &ast = *static_cast(f.ast); + const auto &ast = *static_cast(f.ast); switch (scratch.t) { - case Value::BOOLEAN: - if (ast.op == UOP_NOT) { - scratch = makeBoolean(!scratch.v.b); - } else { - throw makeError(ast.location, - "Unary operator " + uop_string(ast.op) - + " does not operate on booleans."); - } - break; + if (ast.op == UOP_NOT) { + scratch = makeBoolean(!scratch.v.b); + } else { + throw makeError(ast.location, + "Unary operator " + uop_string(ast.op) + + " does not operate on booleans."); + } + break; case Value::DOUBLE: - switch (ast.op) { - case UOP_PLUS: - break; + switch (ast.op) { + case UOP_PLUS: break; - case UOP_MINUS: - scratch = makeDouble(-scratch.v.d); - break; + case UOP_MINUS: scratch = makeDouble(-scratch.v.d); break; - case UOP_BITWISE_NOT: - scratch = makeDouble(~(long)(scratch.v.d)); - break; + case UOP_BITWISE_NOT: + scratch = makeDouble(~(long)(scratch.v.d)); + break; - default: - throw makeError(ast.location, - "Unary operator " + uop_string(ast.op) - + " does not operate on numbers."); - } - break; + default: + throw makeError(ast.location, + "Unary operator " + uop_string(ast.op) + + " does not operate on numbers."); + } + break; default: throw makeError(ast.location, "Unary operator " + uop_string(ast.op) + - " does not operate on type " + type_str(scratch)); + " does not operate on type " + type_str(scratch)); } } break; default: - std::cerr << "INTERNAL ERROR: Unknown FrameKind: " << f.kind << std::endl; - std::abort(); + std::cerr << "INTERNAL ERROR: Unknown FrameKind: " << f.kind << std::endl; + std::abort(); } - popframe:; + popframe:; stack.pop(); - replaceframe:; + replaceframe:; } } @@ -2579,16 +2535,14 @@ class Interpreter { UStringStream ss; switch (scratch.t) { case Value::ARRAY: { - HeapArray *arr = static_cast(scratch.v.h); + HeapArray *arr = static_cast(scratch.v.h); if (arr->elements.size() == 0) { ss << U"[ ]"; } else { const char32_t *prefix = multiline ? U"[\n" : U"["; UString indent2 = multiline ? indent + U" " : indent; for (auto *thunk : arr->elements) { - LocationRange tloc = thunk->body == nullptr - ? loc - : thunk->body->location; + LocationRange tloc = thunk->body == nullptr ? loc : thunk->body->location; if (thunk->filled) { stack.newCall(loc, thunk, nullptr, 0, BindingFrame{}); // Keep arr alive when scratch is overwritten @@ -2609,30 +2563,23 @@ class Interpreter { } ss << (multiline ? U"\n" : U"") << indent << U"]"; } - } - break; + } break; - case Value::BOOLEAN: - ss << (scratch.v.b ? U"true" : U"false"); - break; + case Value::BOOLEAN: ss << (scratch.v.b ? U"true" : U"false"); break; - case Value::DOUBLE: - ss << decode_utf8(jsonnet_unparse_number(scratch.v.d)); - break; + case Value::DOUBLE: ss << decode_utf8(jsonnet_unparse_number(scratch.v.d)); break; case Value::FUNCTION: - throw makeError(loc, "Couldn't manifest function in JSON output."); + throw makeError(loc, "Couldn't manifest function in JSON output."); - case Value::NULL_TYPE: - ss << U"null"; - break; + case Value::NULL_TYPE: ss << U"null"; break; case Value::OBJECT: { - auto *obj = static_cast(scratch.v.h); + auto *obj = static_cast(scratch.v.h); runInvariants(loc, obj); // Using std::map has the useful side-effect of ordering the fields // alphabetically. - std::map fields; + std::map fields; for (const auto &f : objectFields(obj, true)) { fields[f->name] = f; } @@ -2651,20 +2598,18 @@ class Interpreter { // get GC'd. scratch = stack.top().val; stack.pop(); - ss << prefix << indent2 << jsonnet_string_unparse(f.first, false) - << U": " << vstr; + ss << prefix << indent2 << jsonnet_string_unparse(f.first, false) << U": " + << vstr; prefix = multiline ? U",\n" : U", "; } ss << (multiline ? U"\n" : U"") << indent << U"}"; } - } - break; + } break; case Value::STRING: { - const UString &str = static_cast(scratch.v.h)->value; + const UString &str = static_cast(scratch.v.h)->value; ss << jsonnet_string_unparse(str, false); - } - break; + } break; } return ss.str(); } @@ -2676,7 +2621,7 @@ class Interpreter { ss << "Expected string result, got: " << type_str(scratch.t); throw makeError(loc, ss.str()); } - return static_cast(scratch.v.h)->value; + return static_cast(scratch.v.h)->value; } StrMap manifestMulti(bool string) @@ -2690,9 +2635,9 @@ class Interpreter { << "the JSON for that file."; throw makeError(loc, ss.str()); } - auto *obj = static_cast(scratch.v.h); + auto *obj = static_cast(scratch.v.h); runInvariants(loc, obj); - std::map fields; + std::map fields; for (const auto &f : objectFields(obj, true)) { fields[f->name] = f; } @@ -2701,8 +2646,8 @@ class Interpreter { const AST *body = objectIndex(loc, obj, f.second, 0); stack.top().val = scratch; evaluate(body, stack.size()); - auto vstr = string ? manifestString(body->location) - : manifestJson(body->location, true, U""); + auto vstr = + string ? manifestString(body->location) : manifestJson(body->location, true, U""); // Reset scratch so that the object we're manifesting doesn't // get GC'd. scratch = stack.top().val; @@ -2723,11 +2668,9 @@ class Interpreter { << "the JSON for each document in the stream."; throw makeError(loc, ss.str()); } - auto *arr = static_cast(scratch.v.h); + auto *arr = static_cast(scratch.v.h); for (auto *thunk : arr->elements) { - LocationRange tloc = thunk->body == nullptr - ? loc - : thunk->body->location; + LocationRange tloc = thunk->body == nullptr ? loc : thunk->body->location; if (thunk->filled) { stack.newCall(loc, thunk, nullptr, 0, BindingFrame{}); // Keep arr alive when scratch is overwritten @@ -2746,25 +2689,24 @@ class Interpreter { } return r; } - }; } // namespace -std::string jsonnet_vm_execute( - Allocator *alloc, - const AST *ast, - const ExtMap &ext_vars, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &natives, - JsonnetImportCallback *import_callback, - void *ctx, - bool string_output) +std::string jsonnet_vm_execute(Allocator *alloc, const AST *ast, const ExtMap &ext_vars, + unsigned max_stack, double gc_min_objects, double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, void *ctx, + bool string_output) { - Interpreter vm(alloc, ext_vars, max_stack, gc_min_objects, gc_growth_trigger, - natives, import_callback, ctx); + Interpreter vm(alloc, + ext_vars, + max_stack, + gc_min_objects, + gc_growth_trigger, + natives, + import_callback, + ctx); vm.evaluate(ast, 0); if (string_output) { return encode_utf8(vm.manifestString(LocationRange("During manifestation"))); @@ -2773,39 +2715,39 @@ std::string jsonnet_vm_execute( } } -StrMap jsonnet_vm_execute_multi( - Allocator *alloc, - const AST *ast, - const ExtMap &ext_vars, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &natives, - JsonnetImportCallback *import_callback, - void *ctx, - bool string_output) +StrMap jsonnet_vm_execute_multi(Allocator *alloc, const AST *ast, const ExtMap &ext_vars, + unsigned max_stack, double gc_min_objects, double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, void *ctx, + bool string_output) { - Interpreter vm(alloc, ext_vars, max_stack, gc_min_objects, gc_growth_trigger, - natives, import_callback, ctx); + Interpreter vm(alloc, + ext_vars, + max_stack, + gc_min_objects, + gc_growth_trigger, + natives, + import_callback, + ctx); vm.evaluate(ast, 0); return vm.manifestMulti(string_output); } -std::vector jsonnet_vm_execute_stream( - Allocator *alloc, - const AST *ast, - const ExtMap &ext_vars, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &natives, - JsonnetImportCallback *import_callback, - void *ctx) +std::vector jsonnet_vm_execute_stream(Allocator *alloc, const AST *ast, + const ExtMap &ext_vars, unsigned max_stack, + double gc_min_objects, double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, + void *ctx) { - Interpreter vm(alloc, ext_vars, max_stack, gc_min_objects, gc_growth_trigger, - natives, import_callback, ctx); + Interpreter vm(alloc, + ext_vars, + max_stack, + gc_min_objects, + gc_growth_trigger, + natives, + import_callback, + ctx); vm.evaluate(ast, 0); return vm.manifestStream(); } - - diff --git a/core/vm.h b/core/vm.h index 2f6f7bd75..cc67b6746 100644 --- a/core/vm.h +++ b/core/vm.h @@ -26,9 +26,10 @@ limitations under the License. struct TraceFrame { LocationRange location; std::string name; - TraceFrame(const LocationRange &location, const std::string &name="") - : location(location), name(name) - { } + TraceFrame(const LocationRange &location, const std::string &name = "") + : location(location), name(name) + { + } }; /** Exception that is thrown by the interpreter when it reaches an error construct, or divide by @@ -38,8 +39,9 @@ struct RuntimeError { std::vector stackTrace; std::string msg; RuntimeError(const std::vector stack_trace, const std::string &msg) - : stackTrace(stack_trace), msg(msg) - { } + : stackTrace(stack_trace), msg(msg) + { + } }; /** Holds native callback and context. */ @@ -55,13 +57,10 @@ typedef std::map VmNativeCallbackMap; struct VmExt { std::string data; bool isCode; - VmExt() : isCode(false) { } - VmExt(const std::string &data, bool is_code) - : data(data), isCode(is_code) - { } + VmExt() : isCode(false) {} + VmExt(const std::string &data, bool is_code) : data(data), isCode(is_code) {} }; - /** Execute the program and return the value as a JSON string. * * \param alloc The allocator used to create the ast. @@ -76,16 +75,12 @@ struct VmExt { * \throws RuntimeError reports runtime errors in the program. * \returns The JSON result in string form. */ -std::string jsonnet_vm_execute( - Allocator *alloc, const AST *ast, - const std::map &ext, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &natives, - JsonnetImportCallback *import_callback, - void *import_callback_ctx, - bool string_output); +std::string jsonnet_vm_execute(Allocator *alloc, const AST *ast, + const std::map &ext, unsigned max_stack, + double gc_min_objects, double gc_growth_trigger, + const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, void *import_callback_ctx, + bool string_output); /** Execute the program and return the value as a number of named JSON files. * @@ -105,16 +100,9 @@ std::string jsonnet_vm_execute( * \returns A mapping from filename to the JSON strings for that file. */ std::map jsonnet_vm_execute_multi( - Allocator *alloc, - const AST *ast, - const std::map &ext, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &natives, - JsonnetImportCallback *import_callback, - void *import_callback_ctx, - bool string_output); + Allocator *alloc, const AST *ast, const std::map &ext, unsigned max_stack, + double gc_min_objects, double gc_growth_trigger, const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, void *import_callback_ctx, bool string_output); /** Execute the program and return the value as a stream of JSON files. * @@ -135,14 +123,8 @@ std::map jsonnet_vm_execute_multi( * \returns A mapping from filename to the JSON strings for that file. */ std::vector jsonnet_vm_execute_stream( - Allocator *alloc, - const AST *ast, - const std::map &ext, - unsigned max_stack, - double gc_min_objects, - double gc_growth_trigger, - const VmNativeCallbackMap &natives, - JsonnetImportCallback *import_callback, - void *import_callback_ctx); + Allocator *alloc, const AST *ast, const std::map &ext, unsigned max_stack, + double gc_min_objects, double gc_growth_trigger, const VmNativeCallbackMap &natives, + JsonnetImportCallback *import_callback, void *import_callback_ctx); #endif diff --git a/cpp/libjsonnet++.cpp b/cpp/libjsonnet++.cpp index ed7d80d24..819f869aa 100644 --- a/cpp/libjsonnet++.cpp +++ b/cpp/libjsonnet++.cpp @@ -17,9 +17,7 @@ limitations under the License. #include "libjsonnet++.h" namespace jsonnet { - -Jsonnet::Jsonnet() -{} +Jsonnet::Jsonnet() {} Jsonnet::~Jsonnet() { @@ -34,7 +32,8 @@ std::string Jsonnet::version() return ::jsonnet_version(); } -bool Jsonnet::init() { +bool Jsonnet::init() +{ vm_ = static_cast(::jsonnet_make()); return vm_ != nullptr; } @@ -94,16 +93,15 @@ bool Jsonnet::evaluateFile(const std::string& filename, std::string* output) return true; } -bool Jsonnet::evaluateSnippet(const std::string& filename, - const std::string& snippet, +bool Jsonnet::evaluateSnippet(const std::string& filename, const std::string& snippet, std::string* output) { if (output == nullptr) { return false; } int error = 0; - const char* jsonnet_output = ::jsonnet_evaluate_snippet( - vm_, filename.c_str(), snippet.c_str(), &error); + const char* jsonnet_output = + ::jsonnet_evaluate_snippet(vm_, filename.c_str(), snippet.c_str(), &error); if (error != 0) { last_error_.assign(jsonnet_output); return false; @@ -113,16 +111,17 @@ bool Jsonnet::evaluateSnippet(const std::string& filename, } namespace { -void parseMultiOutput(const char* jsonnet_output, - std::map* outputs) +void parseMultiOutput(const char* jsonnet_output, std::map* outputs) { - for (const char* c = jsonnet_output; *c != '\0'; ) { - const char *filename = c; - const char *c2 = c; - while (*c2 != '\0') ++c2; + for (const char* c = jsonnet_output; *c != '\0';) { + const char* filename = c; + const char* c2 = c; + while (*c2 != '\0') + ++c2; ++c2; - const char *json = c2; - while (*c2 != '\0') ++c2; + const char* json = c2; + while (*c2 != '\0') + ++c2; ++c2; c = c2; outputs->insert(std::make_pair(filename, json)); @@ -137,8 +136,7 @@ bool Jsonnet::evaluateFileMulti(const std::string& filename, return false; } int error = 0; - const char* jsonnet_output = - ::jsonnet_evaluate_file_multi(vm_, filename.c_str(), &error); + const char* jsonnet_output = ::jsonnet_evaluate_file_multi(vm_, filename.c_str(), &error); if (error != 0) { last_error_.assign(jsonnet_output); return false; @@ -147,16 +145,15 @@ bool Jsonnet::evaluateFileMulti(const std::string& filename, return true; } -bool Jsonnet::evaluateSnippetMulti(const std::string& filename, - const std::string& snippet, +bool Jsonnet::evaluateSnippetMulti(const std::string& filename, const std::string& snippet, std::map* outputs) { if (outputs == nullptr) { return false; } int error = 0; - const char* jsonnet_output = ::jsonnet_evaluate_snippet_multi( - vm_, filename.c_str(), snippet.c_str(), &error); + const char* jsonnet_output = + ::jsonnet_evaluate_snippet_multi(vm_, filename.c_str(), snippet.c_str(), &error); if (error != 0) { last_error_.assign(jsonnet_output); return false; diff --git a/cpp/libjsonnet++_test.cpp b/cpp/libjsonnet++_test.cpp index bc02665d1..8a753bd08 100644 --- a/cpp/libjsonnet++_test.cpp +++ b/cpp/libjsonnet++_test.cpp @@ -16,14 +16,13 @@ limitations under the License. #include "libjsonnet++.h" -#include #include #include +#include #include "gtest/gtest.h" namespace jsonnet { - std::string readFile(const std::string& filename) { std::ifstream in(filename); @@ -51,8 +50,7 @@ TEST(JsonnetTest, TestEvaluateInvalidSnippet) Jsonnet jsonnet; ASSERT_TRUE(jsonnet.init()); std::string output; - EXPECT_FALSE(jsonnet.evaluateSnippet("cpp/testdata/invalid.jsonnet", - input, &output)); + EXPECT_FALSE(jsonnet.evaluateSnippet("cpp/testdata/invalid.jsonnet", input, &output)); EXPECT_EQ("", output); EXPECT_EQ(error, jsonnet.lastError()); } diff --git a/include/libjsonnet++.h b/include/libjsonnet++.h index 4cd6da19d..7b4b857cc 100644 --- a/include/libjsonnet++.h +++ b/include/libjsonnet++.h @@ -17,17 +17,16 @@ limitations under the License. #ifndef CPP_JSONNET_H_ #define CPP_JSONNET_H_ -#include #include -#include +#include #include +#include extern "C" { - #include "libjsonnet.h" +#include "libjsonnet.h" } namespace jsonnet { - class Jsonnet { public: Jsonnet(); @@ -99,8 +98,7 @@ class Jsonnet { /// @param output Pointer to string to contain the output. /// @return true if the Jsonnet code was successfully evaluated, false /// otherwise. - bool evaluateSnippet(const std::string& filename, - const std::string& snippet, + bool evaluateSnippet(const std::string& filename, const std::string& snippet, std::string* output); /// Evaluate a file containing Jsonnet code, return a number of JSON files. @@ -127,14 +125,13 @@ class Jsonnet { /// to JSON string. /// @return true if the Jsonnet code was successfully evaluated, false /// otherwise. - bool evaluateSnippetMulti(const std::string& filename, - const std::string& snippet, + bool evaluateSnippetMulti(const std::string& filename, const std::string& snippet, std::map* outputs); /// Returns the last error raised by Jsonnet. std::string lastError() const; - private: + private: struct JsonnetVm* vm_; std::string last_error_; }; diff --git a/include/libjsonnet.h b/include/libjsonnet.h index a5337296f..29b0d62c9 100644 --- a/include/libjsonnet.h +++ b/include/libjsonnet.h @@ -24,10 +24,8 @@ limitations under the License. * of using the library. */ - #define LIB_JSONNET_VERSION "v0.9.4" - /** Return the version string of the Jsonnet interpreter. Conforms to semantic versioning * http://semver.org/ If this does not match LIB_JSONNET_VERSION then there is a mismatch between * header and compiled library. @@ -66,7 +64,8 @@ void jsonnet_string_output(struct JsonnetVm *vm, int v); * \param success Set this byref param to 1 to indicate success and 0 for failure. * \returns The content of the imported file, or an error message. */ -typedef char *JsonnetImportCallback(void *ctx, const char *base, const char *rel, char **found_here, int *success); +typedef char *JsonnetImportCallback(void *ctx, const char *base, const char *rel, char **found_here, + int *success); /** An opaque type which can only be utilized via the jsonnet_json_* family of functions. */ @@ -78,7 +77,8 @@ const char *jsonnet_json_extract_string(struct JsonnetVm *vm, const struct Jsonn /** If the value is a number, return 1 and store the number in out, otherwise return 0. */ -int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonValue *v, double *out); +int jsonnet_json_extract_number(struct JsonnetVm *vm, const struct JsonnetJsonValue *v, + double *out); /** Return 0 if the value is false, 1 if it is true, and 2 if it is not a bool. */ @@ -112,8 +112,7 @@ struct JsonnetJsonValue *jsonnet_json_make_array(struct JsonnetVm *vm); /** Add v to the end of the array. */ -void jsonnet_json_array_append(struct JsonnetVm *vm, - struct JsonnetJsonValue *arr, +void jsonnet_json_array_append(struct JsonnetVm *vm, struct JsonnetJsonValue *arr, struct JsonnetJsonValue *v); /** Make a JsonnetJsonValue representing an object with the given number of fields. @@ -126,9 +125,7 @@ struct JsonnetJsonValue *jsonnet_json_make_object(struct JsonnetVm *vm); * * This replaces any previous binding of the field. */ -void jsonnet_json_object_append(struct JsonnetVm *vm, - struct JsonnetJsonValue *obj, - const char *f, +void jsonnet_json_object_append(struct JsonnetVm *vm, struct JsonnetJsonValue *obj, const char *f, struct JsonnetJsonValue *v); /** Clean up a JSON subtree. @@ -150,7 +147,7 @@ void jsonnet_json_destroy(struct JsonnetVm *vm, struct JsonnetJsonValue *v); * \returns The content of the imported file, or an error message. */ typedef struct JsonnetJsonValue *JsonnetNativeCallback(void *ctx, - const struct JsonnetJsonValue * const *argv, + const struct JsonnetJsonValue *const *argv, int *success); /** Allocate, resize, or free a buffer. This will abort if the memory cannot be allocated. It will @@ -180,7 +177,7 @@ void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, vo * \param params NULL-terminated array of the names of the params. Must be valid identifiers. */ void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNativeCallback *cb, - void *ctx, const char * const *params); + void *ctx, const char *const *params); /** Bind a Jsonnet external var to the given string. * @@ -257,9 +254,7 @@ void jsonnet_fmt_debug_desugaring(struct JsonnetVm *vm, int v); * \param error Return by reference whether or not there was an error. * \returns Either Jsonnet code or the error message. */ -char *jsonnet_fmt_file(struct JsonnetVm *vm, - const char *filename, - int *error); +char *jsonnet_fmt_file(struct JsonnetVm *vm, const char *filename, int *error); /** Evaluate a string containing Jsonnet code, return a Jsonnet string. * @@ -270,9 +265,7 @@ char *jsonnet_fmt_file(struct JsonnetVm *vm, * \param error Return by reference whether or not there was an error. * \returns Either JSON or the error message. */ -char *jsonnet_fmt_snippet(struct JsonnetVm *vm, - const char *filename, - const char *snippet, +char *jsonnet_fmt_snippet(struct JsonnetVm *vm, const char *filename, const char *snippet, int *error); /** Set the number of lines of stack trace to display (0 for all of them). */ @@ -289,9 +282,7 @@ void jsonnet_jpath_add(struct JsonnetVm *vm, const char *v); * \param error Return by reference whether or not there was an error. * \returns Either JSON or the error message. */ -char *jsonnet_evaluate_file(struct JsonnetVm *vm, - const char *filename, - int *error); +char *jsonnet_evaluate_file(struct JsonnetVm *vm, const char *filename, int *error); /** Evaluate a string containing Jsonnet code, return a JSON string. * @@ -302,9 +293,7 @@ char *jsonnet_evaluate_file(struct JsonnetVm *vm, * \param error Return by reference whether or not there was an error. * \returns Either JSON or the error message. */ -char *jsonnet_evaluate_snippet(struct JsonnetVm *vm, - const char *filename, - const char *snippet, +char *jsonnet_evaluate_snippet(struct JsonnetVm *vm, const char *filename, const char *snippet, int *error); /** Evaluate a file containing Jsonnet code, return a number of named JSON files. @@ -316,9 +305,7 @@ char *jsonnet_evaluate_snippet(struct JsonnetVm *vm, * \param error Return by reference whether or not there was an error. * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. */ -char *jsonnet_evaluate_file_multi(struct JsonnetVm *vm, - const char *filename, - int *error); +char *jsonnet_evaluate_file_multi(struct JsonnetVm *vm, const char *filename, int *error); /** Evaluate a string containing Jsonnet code, return a number of named JSON files. * @@ -330,10 +317,8 @@ char *jsonnet_evaluate_file_multi(struct JsonnetVm *vm, * \param error Return by reference whether or not there was an error. * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. */ -char *jsonnet_evaluate_snippet_multi(struct JsonnetVm *vm, - const char *filename, - const char *snippet, - int *error); +char *jsonnet_evaluate_snippet_multi(struct JsonnetVm *vm, const char *filename, + const char *snippet, int *error); /** Evaluate a file containing Jsonnet code, return a number of JSON files. * @@ -344,9 +329,7 @@ char *jsonnet_evaluate_snippet_multi(struct JsonnetVm *vm, * \param error Return by reference whether or not there was an error. * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. */ -char *jsonnet_evaluate_file_stream(struct JsonnetVm *vm, - const char *filename, - int *error); +char *jsonnet_evaluate_file_stream(struct JsonnetVm *vm, const char *filename, int *error); /** Evaluate a string containing Jsonnet code, return a number of JSON files. * @@ -358,10 +341,8 @@ char *jsonnet_evaluate_file_stream(struct JsonnetVm *vm, * \param error Return by reference whether or not there was an error. * \returns Either the error, or a sequence of strings separated by \0, terminated with \0\0. */ -char *jsonnet_evaluate_snippet_stream(struct JsonnetVm *vm, - const char *filename, - const char *snippet, - int *error); +char *jsonnet_evaluate_snippet_stream(struct JsonnetVm *vm, const char *filename, + const char *snippet, int *error); /** Complement of \see jsonnet_vm_make. */ void jsonnet_destroy(struct JsonnetVm *vm);