// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "src/torque/earley-parser.h" #include "src/torque/torque-parser.h" #include "src/torque/utils.h" namespace v8 { namespace internal { namespace torque { DEFINE_CONTEXTUAL_VARIABLE(CurrentAst); using TypeList = std::vector; using GenericParameters = std::vector; struct ExpressionWithSource { Expression* expression; std::string source; }; struct TypeswitchCase { SourcePosition pos; base::Optional name; TypeExpression* type; Statement* block; }; enum class ParseResultHolderBase::TypeId { kStdString, kBool, kStdVectorOfString, kExpressionPtr, kLocationExpressionPtr, kStatementPtr, kDeclarationPtr, kTypeExpressionPtr, kLabelBlockPtr, kNameAndTypeExpression, kStdVectorOfNameAndTypeExpression, kIncrementDecrementOperator, kOptionalStdString, kStdVectorOfStatementPtr, kStdVectorOfDeclarationPtr, kStdVectorOfExpressionPtr, kExpressionWithSource, kParameterList, kRangeExpression, kOptionalRangeExpression, kTypeList, kOptionalTypeList, kLabelAndTypes, kStdVectorOfLabelAndTypes, kStdVectorOfLabelBlockPtr, kOptionalStatementPtr, kOptionalExpressionPtr, kTypeswitchCase, kStdVectorOfTypeswitchCase }; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kStdString; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kBool; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfString; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kDeclarationPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kTypeExpressionPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kLabelBlockPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kExpressionPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kLocationExpressionPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kStatementPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kNameAndTypeExpression; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfNameAndTypeExpression; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kIncrementDecrementOperator; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kOptionalStdString; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfStatementPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfDeclarationPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfExpressionPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kExpressionWithSource; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kParameterList; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kRangeExpression; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kOptionalRangeExpression; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kTypeList; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kOptionalTypeList; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kLabelAndTypes; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfLabelAndTypes; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfLabelBlockPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kOptionalStatementPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kOptionalExpressionPtr; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder::id = ParseResultTypeId::kTypeswitchCase; template <> V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder>::id = ParseResultTypeId::kStdVectorOfTypeswitchCase; namespace { base::Optional AddGlobalDeclaration( ParseResultIterator* child_results) { auto declaration = child_results->NextAs(); CurrentAst::Get().declarations().push_back(declaration); return base::nullopt; } template T* MakeNode(Args... args) { return CurrentAst::Get().AddNode(std::unique_ptr( new T(CurrentSourcePosition::Get(), std::move(args)...))); } void LintGenericParameters(const GenericParameters& parameters) { for (const std::string& parameter : parameters) { if (!IsUpperCamelCase(parameter)) { NamingConventionError("Generic parameter", parameter, "UpperCamelCase"); } } } void CheckNotDeferredStatement(Statement* statement) { if (BlockStatement* block = BlockStatement::DynamicCast(statement)) { if (block->deferred) { LintError( "cannot use deferred with a statement block here, it will have no " "effect"); } } } Expression* MakeCall(const std::string& callee, bool is_operator, const std::vector& generic_arguments, const std::vector& arguments, const std::vector& otherwise) { std::vector labels; // All IdentifierExpressions are treated as label names and can be directly // used as labels identifiers. All other statements in a call's otherwise // must create intermediate Labels for the otherwise's statement code. size_t label_id = 0; std::vector temp_labels; for (auto* statement : otherwise) { if (auto* e = ExpressionStatement::DynamicCast(statement)) { if (auto* id = IdentifierExpression::DynamicCast(e->expression)) { if (id->generic_arguments.size() != 0) { ReportError("An otherwise label cannot have generic parameters"); } labels.push_back(id->name); continue; } } auto label_name = std::string("_label") + std::to_string(label_id++); labels.push_back(label_name); auto* label_block = MakeNode(label_name, ParameterList::Empty(), statement); temp_labels.push_back(label_block); } // Create nested try-label expression for all of the temporary Labels that // were created. Expression* result = MakeNode( callee, false, generic_arguments, arguments, labels); for (auto* label : temp_labels) { result = MakeNode(result, label); } return result; } base::Optional MakeCall(ParseResultIterator* child_results) { auto callee = child_results->NextAs(); auto generic_args = child_results->NextAs(); auto args = child_results->NextAs>(); auto otherwise = child_results->NextAs>(); return ParseResult{MakeCall(callee, false, generic_args, args, otherwise)}; } base::Optional MakeBinaryOperator( ParseResultIterator* child_results) { auto left = child_results->NextAs(); auto op = child_results->NextAs(); auto right = child_results->NextAs(); return ParseResult{MakeCall(op, true, TypeList{}, std::vector{left, right}, std::vector{})}; } base::Optional MakeUnaryOperator( ParseResultIterator* child_results) { auto op = child_results->NextAs(); auto e = child_results->NextAs(); return ParseResult{MakeCall(op, true, TypeList{}, std::vector{e}, std::vector{})}; } template base::Optional MakeParameterListFromTypes( ParseResultIterator* child_results) { auto types = child_results->NextAs(); ParameterList result; result.types = std::move(types); result.has_varargs = has_varargs; return ParseResult{std::move(result)}; } template base::Optional MakeParameterListFromNameAndTypeList( ParseResultIterator* child_results) { auto params = child_results->NextAs>(); std::string arguments_variable = ""; if (child_results->HasNext()) { arguments_variable = child_results->NextAs(); } ParameterList result; for (NameAndTypeExpression& pair : params) { if (!IsLowerCamelCase(pair.name)) { NamingConventionError("Parameter", pair.name, "lowerCamelCase"); } result.names.push_back(std::move(pair.name)); result.types.push_back(pair.type); } result.has_varargs = has_varargs; result.arguments_variable = arguments_variable; return ParseResult{std::move(result)}; } base::Optional MakeAssertStatement( ParseResultIterator* child_results) { auto kind = child_results->NextAs(); auto expr_with_source = child_results->NextAs(); DCHECK(kind == "assert" || kind == "check"); Statement* result = MakeNode( kind == "assert", expr_with_source.expression, expr_with_source.source); return ParseResult{result}; } base::Optional MakeDebugStatement( ParseResultIterator* child_results) { auto kind = child_results->NextAs(); DCHECK(kind == "unreachable" || kind == "debug"); Statement* result = MakeNode(kind, kind == "unreachable"); return ParseResult{result}; } base::Optional MakeVoidType(ParseResultIterator* child_results) { TypeExpression* result = MakeNode(false, "void"); return ParseResult{result}; } base::Optional MakeExternalMacro( ParseResultIterator* child_results) { auto operator_name = child_results->NextAs>(); auto name = child_results->NextAs(); auto generic_parameters = child_results->NextAs(); LintGenericParameters(generic_parameters); auto args = child_results->NextAs(); auto return_type = child_results->NextAs(); auto labels = child_results->NextAs(); MacroDeclaration* macro = MakeNode( name, operator_name, args, return_type, labels); Declaration* result; if (generic_parameters.empty()) { result = MakeNode(macro, nullptr); } else { result = MakeNode(macro, generic_parameters); } return ParseResult{result}; } base::Optional MakeTorqueMacroDeclaration( ParseResultIterator* child_results) { auto operator_name = child_results->NextAs>(); auto name = child_results->NextAs(); if (!IsUpperCamelCase(name)) { NamingConventionError("Macro", name, "UpperCamelCase"); } auto generic_parameters = child_results->NextAs(); LintGenericParameters(generic_parameters); auto args = child_results->NextAs(); auto return_type = child_results->NextAs(); auto labels = child_results->NextAs(); auto body = child_results->NextAs>(); MacroDeclaration* macro = MakeNode( name, operator_name, args, return_type, labels); Declaration* result; if (generic_parameters.empty()) { if (!body) ReportError("A non-generic declaration needs a body."); result = MakeNode(macro, *body); } else { result = MakeNode(macro, generic_parameters, body); } return ParseResult{result}; } base::Optional MakeTorqueBuiltinDeclaration( ParseResultIterator* child_results) { auto javascript_linkage = child_results->NextAs(); auto name = child_results->NextAs(); if (!IsUpperCamelCase(name)) { NamingConventionError("Builtin", name, "UpperCamelCase"); } auto generic_parameters = child_results->NextAs(); LintGenericParameters(generic_parameters); auto args = child_results->NextAs(); auto return_type = child_results->NextAs(); auto body = child_results->NextAs>(); BuiltinDeclaration* builtin = MakeNode( javascript_linkage, name, args, return_type); Declaration* result; if (generic_parameters.empty()) { if (!body) ReportError("A non-generic declaration needs a body."); result = MakeNode(builtin, *body); } else { result = MakeNode(builtin, generic_parameters, body); } return ParseResult{result}; } base::Optional MakeConstDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); if (!IsValidModuleConstName(name)) { NamingConventionError("Constant", name, "kUpperCamelCase"); } auto type = child_results->NextAs(); auto expression = child_results->NextAs(); Declaration* result = MakeNode(std::move(name), type, expression); return ParseResult{result}; } base::Optional MakeExternConstDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto type = child_results->NextAs(); auto literal = child_results->NextAs(); Declaration* result = MakeNode(std::move(name), type, std::move(literal)); return ParseResult{result}; } base::Optional MakeTypeAliasDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto type = child_results->NextAs(); Declaration* result = MakeNode(std::move(name), type); return ParseResult{result}; } base::Optional MakeTypeDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); if (!IsValidTypeName(name)) { NamingConventionError("Type", name, "UpperCamelCase"); } auto extends = child_results->NextAs>(); auto generates = child_results->NextAs>(); auto constexpr_generates = child_results->NextAs>(); Declaration* result = MakeNode( std::move(name), std::move(extends), std::move(generates), std::move(constexpr_generates)); return ParseResult{result}; } base::Optional MakeExplicitModuleDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); if (!IsSnakeCase(name)) { NamingConventionError("Module", name, "snake_case"); } auto declarations = child_results->NextAs>(); Declaration* result = MakeNode( std::move(name), std::move(declarations)); return ParseResult{result}; } base::Optional MakeSpecializationDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto generic_parameters = child_results->NextAs>(); auto parameters = child_results->NextAs(); auto return_type = child_results->NextAs(); auto labels = child_results->NextAs(); auto body = child_results->NextAs(); CheckNotDeferredStatement(body); Declaration* result = MakeNode( std::move(name), std::move(generic_parameters), std::move(parameters), return_type, std::move(labels), body); return ParseResult{result}; } base::Optional MakeStructDeclaration( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto fields = child_results->NextAs>(); Declaration* result = MakeNode(std::move(name), std::move(fields)); return ParseResult{result}; } base::Optional MakeExternalBuiltin( ParseResultIterator* child_results) { auto js_linkage = child_results->NextAs(); auto name = child_results->NextAs(); auto generic_parameters = child_results->NextAs(); LintGenericParameters(generic_parameters); auto args = child_results->NextAs(); auto return_type = child_results->NextAs(); BuiltinDeclaration* builtin = MakeNode(js_linkage, name, args, return_type); Declaration* result; if (generic_parameters.empty()) { result = MakeNode(builtin, nullptr); } else { result = MakeNode(builtin, generic_parameters); } return ParseResult{result}; } base::Optional MakeExternalRuntime( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto args = child_results->NextAs(); auto return_type = child_results->NextAs(); ExternalRuntimeDeclaration* runtime = MakeNode(name, args, return_type); Declaration* result = MakeNode(runtime, nullptr); return ParseResult{result}; } base::Optional StringLiteralUnquoteAction( ParseResultIterator* child_results) { return ParseResult{ StringLiteralUnquote(child_results->NextAs())}; } base::Optional MakeBasicTypeExpression( ParseResultIterator* child_results) { auto is_constexpr = child_results->NextAs(); auto name = child_results->NextAs(); TypeExpression* result = MakeNode(is_constexpr, std::move(name)); return ParseResult{result}; } base::Optional MakeFunctionTypeExpression( ParseResultIterator* child_results) { auto parameters = child_results->NextAs>(); auto return_type = child_results->NextAs(); TypeExpression* result = MakeNode(std::move(parameters), return_type); return ParseResult{result}; } base::Optional MakeUnionTypeExpression( ParseResultIterator* child_results) { auto a = child_results->NextAs(); auto b = child_results->NextAs(); TypeExpression* result = MakeNode(a, b); return ParseResult{result}; } base::Optional MakeExpressionStatement( ParseResultIterator* child_results) { auto expression = child_results->NextAs(); Statement* result = MakeNode(expression); return ParseResult{result}; } base::Optional MakeIfStatement( ParseResultIterator* child_results) { auto is_constexpr = child_results->NextAs(); auto condition = child_results->NextAs(); auto if_true = child_results->NextAs(); auto if_false = child_results->NextAs>(); if (if_false && !(BlockStatement::DynamicCast(if_true) && (BlockStatement::DynamicCast(*if_false) || IfStatement::DynamicCast(*if_false)))) { ReportError("if-else statements require curly braces"); } Statement* result = MakeNode(is_constexpr, condition, if_true, if_false); return ParseResult{result}; } base::Optional MakeTypeswitchStatement( ParseResultIterator* child_results) { auto expression = child_results->NextAs(); auto cases = child_results->NextAs>(); CurrentSourcePosition::Scope current_source_position( child_results->matched_input().pos); // typeswitch (expression) case (x1 : T1) { // ...b1 // } case (x2 : T2) { // ...b2 // } case (x3 : T3) { // ...b3 // } // // desugars to // // { // const _value = expression; // try { // const x1 : T1 = cast(_value) otherwise _NextCase; // ...b1 // } label _NextCase { // try { // const x2 : T2 = cast(%assume_impossible(_value)); // ...b2 // } label _NextCase { // const x3 : T3 = %assume_impossible(_value); // ...b3 // } // } // } BlockStatement* current_block = MakeNode(); Statement* result = current_block; { CurrentSourcePosition::Scope current_source_position(expression->pos); current_block->statements.push_back(MakeNode( true, "_value", base::nullopt, expression)); } TypeExpression* accumulated_types; for (size_t i = 0; i < cases.size(); ++i) { CurrentSourcePosition::Scope current_source_position(cases[i].pos); Expression* value = MakeNode("_value"); if (i >= 1) { value = MakeNode(accumulated_types, value); } BlockStatement* case_block; if (i < cases.size() - 1) { value = MakeCall("Cast", false, std::vector{cases[i].type}, std::vector{value}, std::vector{MakeNode( MakeNode("_NextCase"))}); case_block = MakeNode(); } else { case_block = current_block; } std::string name = "_case_value"; if (cases[i].name) name = *cases[i].name; case_block->statements.push_back( MakeNode(true, name, cases[i].type, value)); case_block->statements.push_back(cases[i].block); if (i < cases.size() - 1) { BlockStatement* next_block = MakeNode(); current_block->statements.push_back( MakeNode(MakeNode( MakeNode(case_block), MakeNode("_NextCase", ParameterList::Empty(), next_block)))); current_block = next_block; } accumulated_types = i > 0 ? MakeNode(accumulated_types, cases[i].type) : cases[i].type; } return ParseResult{result}; } base::Optional MakeTypeswitchCase( ParseResultIterator* child_results) { auto name = child_results->NextAs>(); auto type = child_results->NextAs(); auto block = child_results->NextAs(); CheckNotDeferredStatement(block); return ParseResult{TypeswitchCase{child_results->matched_input().pos, std::move(name), type, block}}; } base::Optional MakeWhileStatement( ParseResultIterator* child_results) { auto condition = child_results->NextAs(); auto body = child_results->NextAs(); Statement* result = MakeNode(condition, body); CheckNotDeferredStatement(result); return ParseResult{result}; } base::Optional MakeReturnStatement( ParseResultIterator* child_results) { auto value = child_results->NextAs>(); Statement* result = MakeNode(value); return ParseResult{result}; } base::Optional MakeTailCallStatement( ParseResultIterator* child_results) { auto value = child_results->NextAs(); Statement* result = MakeNode(CallExpression::cast(value)); return ParseResult{result}; } base::Optional MakeVarDeclarationStatement( ParseResultIterator* child_results) { auto kind = child_results->NextAs(); bool const_qualified = kind == "const"; if (!const_qualified) DCHECK_EQ("let", kind); auto name = child_results->NextAs(); if (!IsLowerCamelCase(name)) { NamingConventionError("Variable", name, "lowerCamelCase"); } auto type = child_results->NextAs(); base::Optional initializer; if (child_results->HasNext()) initializer = child_results->NextAs(); Statement* result = MakeNode( const_qualified, std::move(name), type, initializer); return ParseResult{result}; } base::Optional MakeBreakStatement( ParseResultIterator* child_results) { Statement* result = MakeNode(); return ParseResult{result}; } base::Optional MakeContinueStatement( ParseResultIterator* child_results) { Statement* result = MakeNode(); return ParseResult{result}; } base::Optional MakeGotoStatement( ParseResultIterator* child_results) { auto label = child_results->NextAs(); auto arguments = child_results->NextAs>(); Statement* result = MakeNode(std::move(label), std::move(arguments)); return ParseResult{result}; } base::Optional MakeBlockStatement( ParseResultIterator* child_results) { auto deferred = child_results->NextAs(); auto statements = child_results->NextAs>(); Statement* result = MakeNode(deferred, std::move(statements)); return ParseResult{result}; } base::Optional MakeTryLabelExpression( ParseResultIterator* child_results) { auto try_block = child_results->NextAs(); CheckNotDeferredStatement(try_block); Statement* result = try_block; auto label_blocks = child_results->NextAs>(); for (auto block : label_blocks) { result = MakeNode(MakeNode( MakeNode(result), block)); } return ParseResult{result}; } base::Optional MakeForOfLoopStatement( ParseResultIterator* child_results) { auto var_decl = child_results->NextAs(); CheckNotDeferredStatement(var_decl); auto iterable = child_results->NextAs(); auto range = child_results->NextAs>(); auto body = child_results->NextAs(); CheckNotDeferredStatement(body); Statement* result = MakeNode(var_decl, iterable, range, body); return ParseResult{result}; } base::Optional MakeForLoopStatement( ParseResultIterator* child_results) { auto var_decl = child_results->NextAs>(); auto test = child_results->NextAs>(); auto action = child_results->NextAs>(); auto body = child_results->NextAs(); CheckNotDeferredStatement(body); Statement* result = MakeNode(var_decl, test, action, body); return ParseResult{result}; } base::Optional MakeLabelBlock(ParseResultIterator* child_results) { auto label = child_results->NextAs(); if (!IsUpperCamelCase(label)) { NamingConventionError("Label", label, "UpperCamelCase"); } auto parameters = child_results->NextAs(); auto body = child_results->NextAs(); LabelBlock* result = MakeNode(std::move(label), std::move(parameters), body); return ParseResult{result}; } base::Optional MakeRangeExpression( ParseResultIterator* child_results) { auto begin = child_results->NextAs>(); auto end = child_results->NextAs>(); RangeExpression result = {begin, end}; return ParseResult{result}; } base::Optional MakeExpressionWithSource( ParseResultIterator* child_results) { auto e = child_results->NextAs(); return ParseResult{ ExpressionWithSource{e, child_results->matched_input().ToString()}}; } base::Optional MakeIdentifierExpression( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto generic_arguments = child_results->NextAs>(); LocationExpression* result = MakeNode( std::move(name), std::move(generic_arguments)); return ParseResult{result}; } base::Optional MakeFieldAccessExpression( ParseResultIterator* child_results) { auto object = child_results->NextAs(); auto field = child_results->NextAs(); LocationExpression* result = MakeNode(object, std::move(field)); return ParseResult{result}; } base::Optional MakeElementAccessExpression( ParseResultIterator* child_results) { auto object = child_results->NextAs(); auto field = child_results->NextAs(); LocationExpression* result = MakeNode(object, field); return ParseResult{result}; } base::Optional MakeStructExpression( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto expressions = child_results->NextAs>(); Expression* result = MakeNode(std::move(name), std::move(expressions)); return ParseResult{result}; } base::Optional MakeAssignmentExpression( ParseResultIterator* child_results) { auto location = child_results->NextAs(); auto op = child_results->NextAs>(); auto value = child_results->NextAs(); Expression* result = MakeNode(location, std::move(op), value); return ParseResult{result}; } base::Optional MakeNumberLiteralExpression( ParseResultIterator* child_results) { auto number = child_results->NextAs(); Expression* result = MakeNode(std::move(number)); return ParseResult{result}; } base::Optional MakeStringLiteralExpression( ParseResultIterator* child_results) { auto literal = child_results->NextAs(); Expression* result = MakeNode(std::move(literal)); return ParseResult{result}; } base::Optional MakeIncrementDecrementExpressionPostfix( ParseResultIterator* child_results) { auto location = child_results->NextAs(); auto op = child_results->NextAs(); Expression* result = MakeNode(location, op, true); return ParseResult{result}; } base::Optional MakeIncrementDecrementExpressionPrefix( ParseResultIterator* child_results) { auto op = child_results->NextAs(); auto location = child_results->NextAs(); Expression* result = MakeNode(location, op, false); return ParseResult{result}; } base::Optional MakeLogicalOrExpression( ParseResultIterator* child_results) { auto left = child_results->NextAs(); auto right = child_results->NextAs(); Expression* result = MakeNode(left, right); return ParseResult{result}; } base::Optional MakeLogicalAndExpression( ParseResultIterator* child_results) { auto left = child_results->NextAs(); auto right = child_results->NextAs(); Expression* result = MakeNode(left, right); return ParseResult{result}; } base::Optional MakeConditionalExpression( ParseResultIterator* child_results) { auto condition = child_results->NextAs(); auto if_true = child_results->NextAs(); auto if_false = child_results->NextAs(); Expression* result = MakeNode(condition, if_true, if_false); return ParseResult{result}; } base::Optional MakeLabelAndTypes( ParseResultIterator* child_results) { auto name = child_results->NextAs(); if (!IsUpperCamelCase(name)) { NamingConventionError("Label", name, "UpperCamelCase"); } auto types = child_results->NextAs>(); return ParseResult{LabelAndTypes{std::move(name), std::move(types)}}; } base::Optional MakeNameAndType( ParseResultIterator* child_results) { auto name = child_results->NextAs(); auto type = child_results->NextAs(); return ParseResult{NameAndTypeExpression{std::move(name), type}}; } base::Optional ExtractAssignmentOperator( ParseResultIterator* child_results) { auto op = child_results->NextAs(); base::Optional result = std::string(op.begin(), op.end() - 1); return ParseResult(std::move(result)); } struct TorqueGrammar : Grammar { static bool MatchWhitespace(InputPosition* pos) { while (true) { if (MatchChar(std::isspace, pos)) continue; if (MatchString("//", pos)) { while (MatchChar([](char c) { return c != '\n'; }, pos)) { } continue; } return true; } } static bool MatchIdentifier(InputPosition* pos) { if (!MatchChar(std::isalpha, pos)) return false; while (MatchChar(std::isalnum, pos) || MatchString("_", pos)) { } return true; } static bool MatchStringLiteral(InputPosition* pos) { InputPosition current = *pos; if (MatchString("\"", ¤t)) { while ( (MatchString("\\", ¤t) && MatchAnyChar(¤t)) || MatchChar([](char c) { return c != '"' && c != '\n'; }, ¤t)) { } if (MatchString("\"", ¤t)) { *pos = current; return true; } } current = *pos; if (MatchString("'", ¤t)) { while ( (MatchString("\\", ¤t) && MatchAnyChar(¤t)) || MatchChar([](char c) { return c != '\'' && c != '\n'; }, ¤t)) { } if (MatchString("'", ¤t)) { *pos = current; return true; } } return false; } static bool MatchHexLiteral(InputPosition* pos) { InputPosition current = *pos; MatchString("-", ¤t); if (MatchString("0x", ¤t) && MatchChar(std::isxdigit, ¤t)) { while (MatchChar(std::isxdigit, ¤t)) { } *pos = current; return true; } return false; } static bool MatchDecimalLiteral(InputPosition* pos) { InputPosition current = *pos; bool found_digit = false; MatchString("-", ¤t); while (MatchChar(std::isdigit, ¤t)) found_digit = true; MatchString(".", ¤t); while (MatchChar(std::isdigit, ¤t)) found_digit = true; if (!found_digit) return false; *pos = current; if ((MatchString("e", ¤t) || MatchString("E", ¤t)) && (MatchString("+", ¤t) || MatchString("-", ¤t) || true) && MatchChar(std::isdigit, ¤t)) { while (MatchChar(std::isdigit, ¤t)) { } *pos = current; return true; } return true; } TorqueGrammar() : Grammar(&file) { SetWhitespace(MatchWhitespace); } // Result: std::string Symbol identifier = {Rule({Pattern(MatchIdentifier)}, YieldMatchedInput)}; // Result: std::string Symbol stringLiteral = { Rule({Pattern(MatchStringLiteral)}, YieldMatchedInput)}; // Result: std::string Symbol externalString = {Rule({&stringLiteral}, StringLiteralUnquoteAction)}; // Result: std::string Symbol decimalLiteral = { Rule({Pattern(MatchDecimalLiteral)}, YieldMatchedInput), Rule({Pattern(MatchHexLiteral)}, YieldMatchedInput)}; // Result: TypeList Symbol* typeList = List(&type, Token(",")); // Result: TypeExpression* Symbol simpleType = { Rule({Token("("), &type, Token(")")}), Rule({CheckIf(Token("constexpr")), &identifier}, MakeBasicTypeExpression), Rule({Token("builtin"), Token("("), typeList, Token(")"), Token("=>"), &simpleType}, MakeFunctionTypeExpression)}; // Result: TypeExpression* Symbol type = {Rule({&simpleType}), Rule({&type, Token("|"), &simpleType}, MakeUnionTypeExpression)}; // Result: GenericParameters Symbol genericParameters = { Rule({Token("<"), List( Sequence({&identifier, Token(":"), Token("type")}), Token(",")), Token(">")})}; // Result: TypeList Symbol genericSpecializationTypeList = { Rule({Token("<"), typeList, Token(">")})}; // Result: base::Optional Symbol* optionalGenericParameters = Optional(&genericParameters); // Result: ParameterList Symbol typeListMaybeVarArgs = { Rule({Token("("), List(Sequence({&type, Token(",")})), Token("..."), Token(")")}, MakeParameterListFromTypes), Rule({Token("("), typeList, Token(")")}, MakeParameterListFromTypes)}; // Result: LabelAndTypes Symbol labelParameter = {Rule( {&identifier, TryOrDefault(Sequence({Token("("), typeList, Token(")")}))}, MakeLabelAndTypes)}; // Result: TypeExpression* Symbol optionalReturnType = {Rule({Token(":"), &type}), Rule({}, MakeVoidType)}; // Result: LabelAndTypesVector Symbol* optionalLabelList{TryOrDefault( Sequence({Token("labels"), NonemptyList(&labelParameter, Token(","))}))}; // Result: std::vector Symbol* optionalOtherwise{TryOrDefault>( Sequence({Token("otherwise"), NonemptyList(&atomarStatement, Token(","))}))}; // Result: NameAndTypeExpression Symbol nameAndType = { Rule({&identifier, Token(":"), &type}, MakeNameAndType)}; // Result: ParameterList Symbol parameterListNoVararg = { Rule({Token("("), List(&nameAndType, Token(",")), Token(")")}, MakeParameterListFromNameAndTypeList)}; // Result: ParameterList Symbol parameterListAllowVararg = { Rule({¶meterListNoVararg}), Rule({Token("("), NonemptyList(&nameAndType, Token(",")), Token(","), Token("..."), &identifier, Token(")")}, MakeParameterListFromNameAndTypeList)}; // Result: std::string Symbol* OneOf(const std::vector& alternatives) { Symbol* result = NewSymbol(); for (const std::string& s : alternatives) { result->AddRule(Rule({Token(s)}, YieldMatchedInput)); } return result; } // Result: Expression* Symbol* BinaryOperator(Symbol* nextLevel, Symbol* op) { Symbol* result = NewSymbol(); *result = {Rule({nextLevel}), Rule({result, op, nextLevel}, MakeBinaryOperator)}; return result; } // Result: Expression* Symbol* expression = &assignmentExpression; // Result: IncrementDecrementOperator Symbol incrementDecrementOperator = { Rule({Token("++")}, YieldIntegralConstant), Rule({Token("--")}, YieldIntegralConstant)}; // Result: LocationExpression* Symbol locationExpression = { Rule( {&identifier, TryOrDefault(&genericSpecializationTypeList)}, MakeIdentifierExpression), Rule({&primaryExpression, Token("."), &identifier}, MakeFieldAccessExpression), Rule({&primaryExpression, Token("["), expression, Token("]")}, MakeElementAccessExpression)}; // Result: std::vector Symbol argumentList = {Rule( {Token("("), List(expression, Token(",")), Token(")")})}; // Result: Expression* Symbol callExpression = { Rule({&identifier, TryOrDefault(&genericSpecializationTypeList), &argumentList, optionalOtherwise}, MakeCall)}; // Result: Expression* Symbol primaryExpression = { Rule({&callExpression}), Rule({&locationExpression}, CastParseResult), Rule({&decimalLiteral}, MakeNumberLiteralExpression), Rule({&stringLiteral}, MakeStringLiteralExpression), Rule({&identifier, Token("{"), List(expression, Token(",")), Token("}")}, MakeStructExpression), Rule({Token("("), expression, Token(")")})}; // Result: Expression* Symbol unaryExpression = { Rule({&primaryExpression}), Rule({OneOf({"+", "-", "!", "~"}), &unaryExpression}, MakeUnaryOperator), Rule({&incrementDecrementOperator, &locationExpression}, MakeIncrementDecrementExpressionPrefix), Rule({&locationExpression, &incrementDecrementOperator}, MakeIncrementDecrementExpressionPostfix)}; // Result: Expression* Symbol* multiplicativeExpression = BinaryOperator(&unaryExpression, OneOf({"*", "/", "%"})); // Result: Expression* Symbol* additiveExpression = BinaryOperator(multiplicativeExpression, OneOf({"+", "-"})); // Result: Expression* Symbol* shiftExpression = BinaryOperator(additiveExpression, OneOf({"<<", ">>", ">>>"})); // Do not allow expressions like a < b > c because this is never // useful and ambiguous with template parameters. // Result: Expression* Symbol relationalExpression = { Rule({shiftExpression}), Rule({shiftExpression, OneOf({"<", ">", "<=", ">="}), shiftExpression}, MakeBinaryOperator)}; // Result: Expression* Symbol* equalityExpression = BinaryOperator(&relationalExpression, OneOf({"==", "!="})); // Result: Expression* Symbol* bitwiseExpression = BinaryOperator(equalityExpression, OneOf({"&", "|"})); // Result: Expression* Symbol logicalAndExpression = { Rule({bitwiseExpression}), Rule({&logicalAndExpression, Token("&&"), bitwiseExpression}, MakeLogicalAndExpression)}; // Result: Expression* Symbol logicalOrExpression = { Rule({&logicalAndExpression}), Rule({&logicalOrExpression, Token("||"), &logicalAndExpression}, MakeLogicalOrExpression)}; // Result: Expression* Symbol conditionalExpression = { Rule({&logicalOrExpression}), Rule({&logicalOrExpression, Token("?"), expression, Token(":"), &conditionalExpression}, MakeConditionalExpression)}; // Result: base::Optional Symbol assignmentOperator = { Rule({Token("=")}, YieldDefaultValue>), Rule({OneOf({"*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|="})}, ExtractAssignmentOperator)}; // Result: Expression* Symbol assignmentExpression = { Rule({&conditionalExpression}), Rule({&locationExpression, &assignmentOperator, &assignmentExpression}, MakeAssignmentExpression)}; // Result: Statement* Symbol block = {Rule({CheckIf(Token("deferred")), Token("{"), List(&statement), Token("}")}, MakeBlockStatement)}; // Result: LabelBlock* Symbol labelBlock = { Rule({Token("label"), &identifier, TryOrDefault(¶meterListNoVararg), &block}, MakeLabelBlock)}; // Result: ExpressionWithSource Symbol expressionWithSource = {Rule({expression}, MakeExpressionWithSource)}; // Result: RangeExpression Symbol rangeSpecifier = { Rule({Token("["), Optional(expression), Token(":"), Optional(expression), Token("]")}, MakeRangeExpression)}; // Result: Statement* Symbol varDeclaration = { Rule({OneOf({"let", "const"}), &identifier, Token(":"), &type}, MakeVarDeclarationStatement)}; // Result: Statement* Symbol varDeclarationWithInitialization = { Rule({OneOf({"let", "const"}), &identifier, Token(":"), &type, Token("="), expression}, MakeVarDeclarationStatement)}; // Result: Statement* Symbol atomarStatement = { Rule({expression}, MakeExpressionStatement), Rule({Token("return"), Optional(expression)}, MakeReturnStatement), Rule({Token("tail"), &callExpression}, MakeTailCallStatement), Rule({Token("break")}, MakeBreakStatement), Rule({Token("continue")}, MakeContinueStatement), Rule({Token("goto"), &identifier, TryOrDefault>(&argumentList)}, MakeGotoStatement), Rule({OneOf({"debug", "unreachable"})}, MakeDebugStatement)}; // Result: Statement* Symbol statement = { Rule({&block}), Rule({&atomarStatement, Token(";")}), Rule({&varDeclaration, Token(";")}), Rule({&varDeclarationWithInitialization, Token(";")}), Rule({Token("if"), CheckIf(Token("constexpr")), Token("("), expression, Token(")"), &statement, Optional(Sequence({Token("else"), &statement}))}, MakeIfStatement), Rule( { Token("typeswitch"), Token("("), expression, Token(")"), Token("{"), NonemptyList(&typeswitchCase), Token("}"), }, MakeTypeswitchStatement), Rule({Token("try"), &block, NonemptyList(&labelBlock)}, MakeTryLabelExpression), Rule({OneOf({"assert", "check"}), Token("("), &expressionWithSource, Token(")"), Token(";")}, MakeAssertStatement), Rule({Token("while"), Token("("), expression, Token(")"), &statement}, MakeWhileStatement), Rule({Token("for"), Token("("), &varDeclaration, Token("of"), expression, Optional(&rangeSpecifier), Token(")"), &statement}, MakeForOfLoopStatement), Rule({Token("for"), Token("("), Optional(&varDeclarationWithInitialization), Token(";"), Optional(expression), Token(";"), Optional(expression), Token(")"), &statement}, MakeForLoopStatement)}; // Result: TypeswitchCase Symbol typeswitchCase = { Rule({Token("case"), Token("("), Optional(Sequence({&identifier, Token(":")})), &type, Token(")"), Token(":"), &block}, MakeTypeswitchCase)}; // Result: base::Optional Symbol optionalBody = { Rule({&block}, CastParseResult>), Rule({Token(";")}, YieldDefaultValue>)}; // Result: Declaration* Symbol declaration = { Rule({Token("const"), &identifier, Token(":"), &type, Token("="), expression, Token(";")}, MakeConstDeclaration), Rule({Token("const"), &identifier, Token(":"), &type, Token("generates"), &externalString, Token(";")}, MakeExternConstDeclaration), Rule({Token("type"), &identifier, Optional(Sequence({Token("extends"), &identifier})), Optional( Sequence({Token("generates"), &externalString})), Optional( Sequence({Token("constexpr"), &externalString})), Token(";")}, MakeTypeDeclaration), Rule({Token("type"), &identifier, Token("="), &type, Token(";")}, MakeTypeAliasDeclaration), Rule({Token("extern"), Optional( Sequence({Token("operator"), &externalString})), Token("macro"), &identifier, TryOrDefault(&genericParameters), &typeListMaybeVarArgs, &optionalReturnType, optionalLabelList, Token(";")}, MakeExternalMacro), Rule({Token("extern"), CheckIf(Token("javascript")), Token("builtin"), &identifier, TryOrDefault(&genericParameters), &typeListMaybeVarArgs, &optionalReturnType, Token(";")}, MakeExternalBuiltin), Rule({Token("extern"), Token("runtime"), &identifier, &typeListMaybeVarArgs, &optionalReturnType, Token(";")}, MakeExternalRuntime), Rule({Optional( Sequence({Token("operator"), &externalString})), Token("macro"), &identifier, TryOrDefault(&genericParameters), ¶meterListNoVararg, &optionalReturnType, optionalLabelList, &optionalBody}, MakeTorqueMacroDeclaration), Rule({CheckIf(Token("javascript")), Token("builtin"), &identifier, TryOrDefault(&genericParameters), ¶meterListAllowVararg, &optionalReturnType, &optionalBody}, MakeTorqueBuiltinDeclaration), Rule({&identifier, &genericSpecializationTypeList, ¶meterListAllowVararg, &optionalReturnType, optionalLabelList, &block}, MakeSpecializationDeclaration), Rule({Token("struct"), &identifier, Token("{"), List(Sequence({&nameAndType, Token(";")})), Token("}")}, MakeStructDeclaration)}; // Result: Declaration* Symbol moduleDeclaration = { Rule({Token("module"), &identifier, Token("{"), List(&declaration), Token("}")}, MakeExplicitModuleDeclaration)}; Symbol file = {Rule({&file, &moduleDeclaration}, AddGlobalDeclaration), Rule({&file, &declaration}, AddGlobalDeclaration), Rule({})}; }; } // namespace void ParseTorque(const std::string& input) { TorqueGrammar().Parse(input); } } // namespace torque } // namespace internal } // namespace v8