| // 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 "src/torque/torque-parser.h" |
| |
| #include <algorithm> |
| #include <cctype> |
| #include <set> |
| #include <stdexcept> |
| #include <unordered_map> |
| |
| #include "src/flags/flags.h" |
| #include "src/torque/ast.h" |
| #include "src/torque/constants.h" |
| #include "src/torque/declarations.h" |
| #include "src/torque/earley-parser.h" |
| #include "src/torque/utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace torque { |
| |
| DEFINE_CONTEXTUAL_VARIABLE(CurrentAst) |
| |
| using TypeList = std::vector<TypeExpression*>; |
| |
| struct ExpressionWithSource { |
| Expression* expression; |
| std::string source; |
| }; |
| |
| struct TypeswitchCase { |
| SourcePosition pos; |
| base::Optional<std::string> name; |
| TypeExpression* type; |
| Statement* block; |
| }; |
| |
| struct EnumEntry { |
| Identifier* name; |
| base::Optional<TypeExpression*> type; |
| }; |
| |
| class BuildFlags : public ContextualClass<BuildFlags> { |
| public: |
| BuildFlags() { |
| build_flags_["V8_SFI_HAS_UNIQUE_ID"] = V8_SFI_HAS_UNIQUE_ID; |
| build_flags_["TAGGED_SIZE_8_BYTES"] = TAGGED_SIZE_8_BYTES; |
| build_flags_["V8_DOUBLE_FIELDS_UNBOXING"] = V8_DOUBLE_FIELDS_UNBOXING; |
| build_flags_["TRUE_FOR_TESTING"] = true; |
| build_flags_["FALSE_FOR_TESTING"] = false; |
| } |
| static bool GetFlag(const std::string& name, const char* production) { |
| auto it = Get().build_flags_.find(name); |
| if (it == Get().build_flags_.end()) { |
| ReportError("Unknown flag used in ", production, ": ", name, |
| ". Please add it to the list in BuildFlags."); |
| } |
| return it->second; |
| } |
| |
| private: |
| std::unordered_map<std::string, bool> build_flags_; |
| }; |
| DEFINE_CONTEXTUAL_VARIABLE(BuildFlags) |
| |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<std::string>::id = |
| ParseResultTypeId::kStdString; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<bool>::id = |
| ParseResultTypeId::kBool; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<int32_t>::id = |
| ParseResultTypeId::kInt32; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<std::string>>::id = |
| ParseResultTypeId::kStdVectorOfString; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Declaration*>::id = |
| ParseResultTypeId::kDeclarationPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<TypeExpression*>::id = |
| ParseResultTypeId::kTypeExpressionPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<TypeExpression*>>::id = |
| ParseResultTypeId::kOptionalTypeExpressionPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<TryHandler*>::id = |
| ParseResultTypeId::kTryHandlerPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Expression*>::id = |
| ParseResultTypeId::kExpressionPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Identifier*>::id = |
| ParseResultTypeId::kIdentifierPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<Identifier*>>::id = |
| ParseResultTypeId::kOptionalIdentifierPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Statement*>::id = |
| ParseResultTypeId::kStatementPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<NameAndTypeExpression>::id = |
| ParseResultTypeId::kNameAndTypeExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<EnumEntry>::id = |
| ParseResultTypeId::kEnumEntry; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<EnumEntry>>::id = |
| ParseResultTypeId::kStdVectorOfEnumEntry; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<NameAndExpression>::id = |
| ParseResultTypeId::kNameAndExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Annotation>::id = |
| ParseResultTypeId::kAnnotation; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<Annotation>>::id = |
| ParseResultTypeId::kVectorOfAnnotation; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<AnnotationParameter>::id = |
| ParseResultTypeId::kAnnotationParameter; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<AnnotationParameter>>::id = |
| ParseResultTypeId::kOptionalAnnotationParameter; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<ClassFieldExpression>::id = |
| ParseResultTypeId::kClassFieldExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<StructFieldExpression>::id = |
| ParseResultTypeId::kStructFieldExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<BitFieldDeclaration>::id = |
| ParseResultTypeId::kBitFieldDeclaration; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<NameAndTypeExpression>>::id = |
| ParseResultTypeId::kStdVectorOfNameAndTypeExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<ImplicitParameters>::id = |
| ParseResultTypeId::kImplicitParameters; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<ImplicitParameters>>::id = |
| ParseResultTypeId::kOptionalImplicitParameters; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<NameAndExpression>>::id = |
| ParseResultTypeId::kStdVectorOfNameAndExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<ClassFieldExpression>>::id = |
| ParseResultTypeId::kStdVectorOfClassFieldExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<StructFieldExpression>>::id = |
| ParseResultTypeId::kStdVectorOfStructFieldExpression; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<BitFieldDeclaration>>::id = |
| ParseResultTypeId::kStdVectorOfBitFieldDeclaration; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<IncrementDecrementOperator>::id = |
| ParseResultTypeId::kIncrementDecrementOperator; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<std::string>>::id = |
| ParseResultTypeId::kOptionalStdString; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<Statement*>>::id = |
| ParseResultTypeId::kStdVectorOfStatementPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<Declaration*>>::id = |
| ParseResultTypeId::kStdVectorOfDeclarationPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<std::vector<Declaration*>>>::id = |
| ParseResultTypeId::kStdVectorOfStdVectorOfDeclarationPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<Expression*>>::id = |
| ParseResultTypeId::kStdVectorOfExpressionPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<ExpressionWithSource>::id = |
| ParseResultTypeId::kExpressionWithSource; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<ParameterList>::id = |
| ParseResultTypeId::kParameterList; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<TypeList>::id = |
| ParseResultTypeId::kTypeList; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<TypeList>>::id = |
| ParseResultTypeId::kOptionalTypeList; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<LabelAndTypes>::id = |
| ParseResultTypeId::kLabelAndTypes; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<LabelAndTypes>>::id = |
| ParseResultTypeId::kStdVectorOfLabelAndTypes; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<TryHandler*>>::id = |
| ParseResultTypeId::kStdVectorOfTryHandlerPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<Statement*>>::id = |
| ParseResultTypeId::kOptionalStatementPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<Expression*>>::id = |
| ParseResultTypeId::kOptionalExpressionPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<TypeswitchCase>::id = ParseResultTypeId::kTypeswitchCase; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<TypeswitchCase>>::id = |
| ParseResultTypeId::kStdVectorOfTypeswitchCase; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<std::vector<Identifier*>>::id = |
| ParseResultTypeId::kStdVectorOfIdentifierPtr; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<base::Optional<ClassBody*>>::id = |
| ParseResultTypeId::kOptionalClassBody; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<GenericParameter>::id = |
| ParseResultTypeId::kGenericParameter; |
| template <> |
| V8_EXPORT_PRIVATE const ParseResultTypeId |
| ParseResultHolder<GenericParameters>::id = |
| ParseResultTypeId::kGenericParameters; |
| |
| namespace { |
| |
| base::Optional<ParseResult> AddGlobalDeclarations( |
| ParseResultIterator* child_results) { |
| auto declarations = child_results->NextAs<std::vector<Declaration*>>(); |
| for (Declaration* declaration : declarations) { |
| CurrentAst::Get().declarations().push_back(declaration); |
| } |
| return base::nullopt; |
| } |
| |
| void NamingConventionError(const std::string& type, const std::string& name, |
| const std::string& convention, |
| SourcePosition pos = CurrentSourcePosition::Get()) { |
| Lint(type, " \"", name, "\" does not follow \"", convention, |
| "\" naming convention.") |
| .Position(pos); |
| } |
| |
| void NamingConventionError(const std::string& type, const Identifier* name, |
| const std::string& convention) { |
| NamingConventionError(type, name->value, convention, name->pos); |
| } |
| |
| void LintGenericParameters(const GenericParameters& parameters) { |
| for (auto parameter : parameters) { |
| if (!IsUpperCamelCase(parameter.name->value)) { |
| NamingConventionError("Generic parameter", parameter.name, |
| "UpperCamelCase"); |
| } |
| } |
| } |
| |
| base::Optional<ParseResult> ConcatList(ParseResultIterator* child_results) { |
| auto list_of_lists = |
| child_results->NextAs<std::vector<std::vector<Declaration*>>>(); |
| std::vector<Declaration*> result; |
| for (auto& list : list_of_lists) { |
| result.insert(result.end(), list.begin(), list.end()); |
| } |
| return ParseResult{result}; |
| } |
| |
| void CheckNotDeferredStatement(Statement* statement) { |
| CurrentSourcePosition::Scope source_position(statement->pos); |
| if (BlockStatement* block = BlockStatement::DynamicCast(statement)) { |
| if (block->deferred) { |
| Lint( |
| "cannot use deferred with a statement block here, it will have no " |
| "effect"); |
| } |
| } |
| } |
| |
| TypeExpression* AddConstexpr(TypeExpression* type) { |
| BasicTypeExpression* basic = BasicTypeExpression::DynamicCast(type); |
| if (!basic) Error("Unsupported extends clause.").Throw(); |
| return MakeNode<BasicTypeExpression>(basic->namespace_qualification, |
| CONSTEXPR_TYPE_PREFIX + basic->name, |
| basic->generic_arguments); |
| } |
| |
| Expression* MakeCall(IdentifierExpression* callee, |
| base::Optional<Expression*> target, |
| std::vector<Expression*> arguments, |
| const std::vector<Statement*>& otherwise) { |
| std::vector<Identifier*> 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<TryHandler*> 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++); |
| auto label_id = MakeNode<Identifier>(label_name); |
| label_id->pos = SourcePosition::Invalid(); |
| labels.push_back(label_id); |
| auto* handler = |
| MakeNode<TryHandler>(TryHandler::HandlerKind::kLabel, label_id, |
| ParameterList::Empty(), statement); |
| temp_labels.push_back(handler); |
| } |
| |
| // Create nested try-label expression for all of the temporary Labels that |
| // were created. |
| Expression* result = nullptr; |
| if (target) { |
| result = MakeNode<CallMethodExpression>(*target, callee, arguments, labels); |
| } else { |
| result = MakeNode<CallExpression>(callee, arguments, labels); |
| } |
| |
| for (auto* label : temp_labels) { |
| result = MakeNode<TryLabelExpression>(result, label); |
| } |
| return result; |
| } |
| |
| Expression* MakeCall(Identifier* callee, |
| const std::vector<TypeExpression*>& generic_arguments, |
| const std::vector<Expression*>& arguments, |
| const std::vector<Statement*>& otherwise) { |
| return MakeCall(MakeNode<IdentifierExpression>(callee, generic_arguments), |
| base::nullopt, arguments, otherwise); |
| } |
| |
| base::Optional<ParseResult> MakeCall(ParseResultIterator* child_results) { |
| auto callee = child_results->NextAs<Expression*>(); |
| auto args = child_results->NextAs<std::vector<Expression*>>(); |
| auto otherwise = child_results->NextAs<std::vector<Statement*>>(); |
| IdentifierExpression* target = IdentifierExpression::cast(callee); |
| return ParseResult{MakeCall(target, base::nullopt, args, otherwise)}; |
| } |
| |
| base::Optional<ParseResult> MakeMethodCall(ParseResultIterator* child_results) { |
| auto this_arg = child_results->NextAs<Expression*>(); |
| auto callee = child_results->NextAs<std::string>(); |
| auto args = child_results->NextAs<std::vector<Expression*>>(); |
| auto otherwise = child_results->NextAs<std::vector<Statement*>>(); |
| return ParseResult{ |
| MakeCall(MakeNode<IdentifierExpression>(MakeNode<Identifier>(callee)), |
| this_arg, args, otherwise)}; |
| } |
| |
| base::Optional<ParseResult> MakeNewExpression( |
| ParseResultIterator* child_results) { |
| bool pretenured = child_results->NextAs<bool>(); |
| |
| auto type = child_results->NextAs<TypeExpression*>(); |
| auto initializers = child_results->NextAs<std::vector<NameAndExpression>>(); |
| |
| Expression* result = |
| MakeNode<NewExpression>(type, std::move(initializers), pretenured); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeBinaryOperator( |
| ParseResultIterator* child_results) { |
| auto left = child_results->NextAs<Expression*>(); |
| auto op = child_results->NextAs<Identifier*>(); |
| auto right = child_results->NextAs<Expression*>(); |
| return ParseResult{MakeCall(op, TypeList{}, |
| std::vector<Expression*>{left, right}, |
| std::vector<Statement*>{})}; |
| } |
| |
| base::Optional<ParseResult> MakeIntrinsicCallExpression( |
| ParseResultIterator* child_results) { |
| auto callee = child_results->NextAs<Identifier*>(); |
| auto generic_arguments = |
| child_results->NextAs<std::vector<TypeExpression*>>(); |
| auto args = child_results->NextAs<std::vector<Expression*>>(); |
| Expression* result = |
| MakeNode<IntrinsicCallExpression>(callee, generic_arguments, args); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeUnaryOperator( |
| ParseResultIterator* child_results) { |
| auto op = child_results->NextAs<Identifier*>(); |
| auto e = child_results->NextAs<Expression*>(); |
| return ParseResult{MakeCall(op, TypeList{}, std::vector<Expression*>{e}, |
| std::vector<Statement*>{})}; |
| } |
| |
| base::Optional<ParseResult> MakeSpreadExpression( |
| ParseResultIterator* child_results) { |
| auto spreadee = child_results->NextAs<Expression*>(); |
| Expression* result = MakeNode<SpreadExpression>(spreadee); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeImplicitParameterList( |
| ParseResultIterator* child_results) { |
| auto kind = child_results->NextAs<Identifier*>(); |
| auto parameters = child_results->NextAs<std::vector<NameAndTypeExpression>>(); |
| return ParseResult{ImplicitParameters{kind, parameters}}; |
| } |
| |
| void AddParameter(ParameterList* parameter_list, |
| const NameAndTypeExpression& param) { |
| if (!IsLowerCamelCase(param.name->value)) { |
| NamingConventionError("Parameter", param.name, "lowerCamelCase"); |
| } |
| parameter_list->names.push_back(param.name); |
| parameter_list->types.push_back(param.type); |
| } |
| |
| template <bool has_varargs, bool has_explicit_parameter_names> |
| base::Optional<ParseResult> MakeParameterList( |
| ParseResultIterator* child_results) { |
| auto implicit_params = |
| child_results->NextAs<base::Optional<ImplicitParameters>>(); |
| ParameterList result; |
| result.has_varargs = has_varargs; |
| result.implicit_count = 0; |
| result.implicit_kind = ImplicitKind::kNoImplicit; |
| if (implicit_params) { |
| result.implicit_count = implicit_params->parameters.size(); |
| if (implicit_params->kind->value == "implicit") { |
| result.implicit_kind = ImplicitKind::kImplicit; |
| } else { |
| DCHECK_EQ(implicit_params->kind->value, "js-implicit"); |
| result.implicit_kind = ImplicitKind::kJSImplicit; |
| } |
| result.implicit_kind_pos = implicit_params->kind->pos; |
| for (NameAndTypeExpression& implicit_param : implicit_params->parameters) { |
| AddParameter(&result, implicit_param); |
| } |
| } |
| if (has_explicit_parameter_names) { |
| auto explicit_params = |
| child_results->NextAs<std::vector<NameAndTypeExpression>>(); |
| std::string arguments_variable = ""; |
| if (has_varargs) { |
| arguments_variable = child_results->NextAs<std::string>(); |
| } |
| for (NameAndTypeExpression& param : explicit_params) { |
| AddParameter(&result, param); |
| } |
| result.arguments_variable = arguments_variable; |
| } else { |
| auto explicit_types = child_results->NextAs<TypeList>(); |
| for (auto* explicit_type : explicit_types) { |
| result.types.push_back(explicit_type); |
| } |
| } |
| return ParseResult{std::move(result)}; |
| } |
| |
| base::Optional<ParseResult> MakeAssertStatement( |
| ParseResultIterator* child_results) { |
| auto kind_string = child_results->NextAs<Identifier*>()->value; |
| auto expr_with_source = child_results->NextAs<ExpressionWithSource>(); |
| AssertStatement::AssertKind kind; |
| if (kind_string == "assert") { |
| kind = AssertStatement::AssertKind::kAssert; |
| } else if (kind_string == "check") { |
| kind = AssertStatement::AssertKind::kCheck; |
| } else if (kind_string == "static_assert") { |
| kind = AssertStatement::AssertKind::kStaticAssert; |
| } else { |
| UNREACHABLE(); |
| } |
| Statement* result = MakeNode<AssertStatement>( |
| kind, expr_with_source.expression, expr_with_source.source); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeDebugStatement( |
| ParseResultIterator* child_results) { |
| auto kind = child_results->NextAs<Identifier*>()->value; |
| DCHECK(kind == "unreachable" || kind == "debug"); |
| Statement* result = MakeNode<DebugStatement>(kind, kind == "unreachable"); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeVoidType(ParseResultIterator* child_results) { |
| TypeExpression* result = MakeNode<BasicTypeExpression>( |
| std::vector<std::string>{}, "void", std::vector<TypeExpression*>{}); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeExternalMacro( |
| ParseResultIterator* child_results) { |
| auto transitioning = child_results->NextAs<bool>(); |
| auto operator_name = child_results->NextAs<base::Optional<std::string>>(); |
| auto external_assembler_name = |
| child_results->NextAs<base::Optional<std::string>>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| LintGenericParameters(generic_parameters); |
| |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| auto labels = child_results->NextAs<LabelAndTypesVector>(); |
| |
| Declaration* result = MakeNode<ExternalMacroDeclaration>( |
| transitioning, |
| external_assembler_name ? *external_assembler_name : "CodeStubAssembler", |
| name, operator_name, args, return_type, labels); |
| if (!generic_parameters.empty()) { |
| Error("External builtins cannot be generic."); |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeIntrinsicDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| LintGenericParameters(generic_parameters); |
| |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| auto body = child_results->NextAs<base::Optional<Statement*>>(); |
| LabelAndTypesVector labels; |
| CallableDeclaration* declaration; |
| if (body) { |
| declaration = MakeNode<TorqueMacroDeclaration>( |
| false, name, base::Optional<std::string>{}, args, return_type, labels, |
| false, body); |
| } else { |
| declaration = MakeNode<IntrinsicDeclaration>(name, args, return_type); |
| } |
| Declaration* result = declaration; |
| if (!generic_parameters.empty()) { |
| result = |
| MakeNode<GenericCallableDeclaration>(generic_parameters, declaration); |
| } |
| return ParseResult{result}; |
| } |
| |
| namespace { |
| bool HasAnnotation(ParseResultIterator* child_results, const char* annotation, |
| const char* declaration) { |
| auto annotations = child_results->NextAs<std::vector<Annotation>>(); |
| if (annotations.size()) { |
| if (annotations.size() > 1 || annotations[0].name->value != annotation) { |
| Error(declaration, " declarations only support a single ", annotation, |
| " annotation"); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| bool HasExportAnnotation(ParseResultIterator* child_results, |
| const char* declaration) { |
| return HasAnnotation(child_results, ANNOTATION_EXPORT, declaration); |
| } |
| } // namespace |
| |
| base::Optional<ParseResult> MakeTorqueMacroDeclaration( |
| ParseResultIterator* child_results) { |
| bool export_to_csa = HasExportAnnotation(child_results, "macro"); |
| auto transitioning = child_results->NextAs<bool>(); |
| auto operator_name = child_results->NextAs<base::Optional<std::string>>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsUpperCamelCase(name->value)) { |
| NamingConventionError("Macro", name, "UpperCamelCase"); |
| } |
| |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| LintGenericParameters(generic_parameters); |
| |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| auto labels = child_results->NextAs<LabelAndTypesVector>(); |
| auto body = child_results->NextAs<base::Optional<Statement*>>(); |
| CallableDeclaration* declaration = MakeNode<TorqueMacroDeclaration>( |
| transitioning, name, operator_name, args, return_type, labels, |
| export_to_csa, body); |
| Declaration* result = declaration; |
| if (generic_parameters.empty()) { |
| if (!body) ReportError("A non-generic declaration needs a body."); |
| } else { |
| if (export_to_csa) ReportError("Cannot export generics to CSA."); |
| result = |
| MakeNode<GenericCallableDeclaration>(generic_parameters, declaration); |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeTorqueBuiltinDeclaration( |
| ParseResultIterator* child_results) { |
| auto transitioning = child_results->NextAs<bool>(); |
| auto javascript_linkage = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsUpperCamelCase(name->value)) { |
| NamingConventionError("Builtin", name, "UpperCamelCase"); |
| } |
| |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| LintGenericParameters(generic_parameters); |
| |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| auto body = child_results->NextAs<base::Optional<Statement*>>(); |
| CallableDeclaration* declaration = MakeNode<TorqueBuiltinDeclaration>( |
| transitioning, javascript_linkage, name, args, return_type, body); |
| Declaration* result = declaration; |
| if (generic_parameters.empty()) { |
| if (!body) ReportError("A non-generic declaration needs a body."); |
| } else { |
| result = |
| MakeNode<GenericCallableDeclaration>(generic_parameters, declaration); |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeConstDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsValidNamespaceConstName(name->value)) { |
| NamingConventionError("Constant", name, "kUpperCamelCase"); |
| } |
| |
| auto type = child_results->NextAs<TypeExpression*>(); |
| auto expression = child_results->NextAs<Expression*>(); |
| Declaration* result = MakeNode<ConstDeclaration>(name, type, expression); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeExternConstDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| auto literal = child_results->NextAs<std::string>(); |
| Declaration* result = |
| MakeNode<ExternConstDeclaration>(name, type, std::move(literal)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeTypeAliasDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| Declaration* result = MakeNode<TypeAliasDeclaration>(name, type); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeAbstractTypeDeclaration( |
| ParseResultIterator* child_results) { |
| bool use_parent_type_checker = HasAnnotation( |
| child_results, ANNOTATION_USE_PARENT_TYPE_CHECKER, "abstract type"); |
| auto transient = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsValidTypeName(name->value)) { |
| NamingConventionError("Type", name, "UpperCamelCase"); |
| } |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| auto extends = child_results->NextAs<base::Optional<TypeExpression*>>(); |
| auto generates = child_results->NextAs<base::Optional<std::string>>(); |
| AbstractTypeFlags flags(AbstractTypeFlag::kNone); |
| if (transient) flags |= AbstractTypeFlag::kTransient; |
| if (use_parent_type_checker) flags |= AbstractTypeFlag::kUseParentTypeChecker; |
| TypeDeclaration* type_decl = MakeNode<AbstractTypeDeclaration>( |
| name, flags, extends, std::move(generates)); |
| Declaration* decl = type_decl; |
| if (!generic_parameters.empty()) { |
| decl = MakeNode<GenericTypeDeclaration>(generic_parameters, type_decl); |
| } |
| |
| auto constexpr_generates = |
| child_results->NextAs<base::Optional<std::string>>(); |
| std::vector<Declaration*> result{decl}; |
| |
| if (constexpr_generates) { |
| // Create a AbstractTypeDeclaration for the associated constexpr type. |
| Identifier* constexpr_name = |
| MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + name->value); |
| constexpr_name->pos = name->pos; |
| |
| base::Optional<TypeExpression*> constexpr_extends; |
| if (extends) { |
| constexpr_extends = AddConstexpr(*extends); |
| } |
| TypeDeclaration* constexpr_decl = MakeNode<AbstractTypeDeclaration>( |
| constexpr_name, flags | AbstractTypeFlag::kConstexpr, constexpr_extends, |
| constexpr_generates); |
| constexpr_decl->pos = name->pos; |
| Declaration* decl = constexpr_decl; |
| if (!generic_parameters.empty()) { |
| decl = |
| MakeNode<GenericTypeDeclaration>(generic_parameters, constexpr_decl); |
| } |
| result.push_back(decl); |
| } |
| |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeMethodDeclaration( |
| ParseResultIterator* child_results) { |
| auto transitioning = child_results->NextAs<bool>(); |
| auto operator_name = child_results->NextAs<base::Optional<std::string>>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsUpperCamelCase(name->value)) { |
| NamingConventionError("Method", name, "UpperCamelCase"); |
| } |
| |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| auto labels = child_results->NextAs<LabelAndTypesVector>(); |
| auto body = child_results->NextAs<Statement*>(); |
| Declaration* result = |
| MakeNode<TorqueMacroDeclaration>(transitioning, name, operator_name, args, |
| return_type, labels, false, body); |
| return ParseResult{result}; |
| } |
| |
| class AnnotationSet { |
| public: |
| AnnotationSet(ParseResultIterator* iter, |
| const std::set<std::string>& allowed_without_param, |
| const std::set<std::string>& allowed_with_param) { |
| auto list = iter->NextAs<std::vector<Annotation>>(); |
| for (const Annotation& a : list) { |
| if (a.param.has_value()) { |
| if (allowed_with_param.find(a.name->value) == |
| allowed_with_param.end()) { |
| const char* error_message = |
| allowed_without_param.find(a.name->value) == |
| allowed_without_param.end() |
| ? " is not allowed here" |
| : " cannot have parameter here"; |
| Lint("Annotation ", a.name->value, error_message) |
| .Position(a.name->pos); |
| } |
| if (!map_.insert({a.name->value, {*a.param, a.name->pos}}).second) { |
| Lint("Duplicate annotation ", a.name->value).Position(a.name->pos); |
| } |
| } else { |
| if (allowed_without_param.find(a.name->value) == |
| allowed_without_param.end()) { |
| const char* error_message = |
| allowed_with_param.find(a.name->value) == allowed_with_param.end() |
| ? " is not allowed here" |
| : " requires a parameter here"; |
| Lint("Annotation ", a.name->value, error_message) |
| .Position(a.name->pos); |
| } |
| if (!set_.insert(a.name->value).second) { |
| Lint("Duplicate annotation ", a.name->value).Position(a.name->pos); |
| } |
| } |
| } |
| } |
| |
| bool Contains(const std::string& s) const { |
| return set_.find(s) != set_.end(); |
| } |
| base::Optional<std::string> GetStringParam(const std::string& s) const { |
| auto it = map_.find(s); |
| if (it == map_.end()) { |
| return {}; |
| } |
| if (it->second.first.is_int) { |
| Error("Annotation ", s, " requires a string parameter but has an int") |
| .Position(it->second.second); |
| } |
| return it->second.first.string_value; |
| } |
| base::Optional<int32_t> GetIntParam(const std::string& s) const { |
| auto it = map_.find(s); |
| if (it == map_.end()) { |
| return {}; |
| } |
| if (!it->second.first.is_int) { |
| Error("Annotation ", s, " requires an int parameter but has a string") |
| .Position(it->second.second); |
| } |
| return it->second.first.int_value; |
| } |
| |
| private: |
| std::set<std::string> set_; |
| std::map<std::string, std::pair<AnnotationParameter, SourcePosition>> map_; |
| }; |
| |
| base::Optional<ParseResult> MakeInt32(ParseResultIterator* child_results) { |
| std::string value = child_results->NextAs<std::string>(); |
| size_t num_chars_converted = 0; |
| int result = 0; |
| try { |
| result = std::stoi(value, &num_chars_converted, 0); |
| } catch (const std::invalid_argument&) { |
| Error("Expected an integer"); |
| return ParseResult{result}; |
| } catch (const std::out_of_range&) { |
| Error("Integer out of 32-bit range"); |
| return ParseResult{result}; |
| } |
| // Tokenizer shouldn't have included extra trailing characters. |
| DCHECK_EQ(num_chars_converted, value.size()); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeStringAnnotationParameter( |
| ParseResultIterator* child_results) { |
| std::string value = child_results->NextAs<std::string>(); |
| AnnotationParameter result{value, 0, false}; |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeIntAnnotationParameter( |
| ParseResultIterator* child_results) { |
| int32_t value = child_results->NextAs<int32_t>(); |
| AnnotationParameter result{"", value, true}; |
| return ParseResult{result}; |
| } |
| |
| int GetAnnotationValue(const AnnotationSet& annotations, const char* name, |
| int default_value) { |
| auto opt_value = annotations.GetIntParam(name); |
| return opt_value.has_value() ? *opt_value : default_value; |
| } |
| |
| InstanceTypeConstraints MakeInstanceTypeConstraints( |
| const AnnotationSet& annotations) { |
| InstanceTypeConstraints result; |
| result.value = |
| GetAnnotationValue(annotations, ANNOTATION_INSTANCE_TYPE_VALUE, -1); |
| result.num_flags_bits = GetAnnotationValue( |
| annotations, ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE, -1); |
| return result; |
| } |
| |
| base::Optional<ParseResult> MakeClassBody(ParseResultIterator* child_results) { |
| auto methods = child_results->NextAs<std::vector<Declaration*>>(); |
| auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>(); |
| base::Optional<ClassBody*> result = |
| MakeNode<ClassBody>(std::move(methods), std::move(fields)); |
| return ParseResult(result); |
| } |
| |
| base::Optional<ParseResult> MakeClassDeclaration( |
| ParseResultIterator* child_results) { |
| AnnotationSet annotations( |
| child_results, |
| {ANNOTATION_GENERATE_PRINT, ANNOTATION_NO_VERIFIER, ANNOTATION_ABSTRACT, |
| ANNOTATION_HAS_SAME_INSTANCE_TYPE_AS_PARENT, |
| ANNOTATION_GENERATE_CPP_CLASS, ANNOTATION_CUSTOM_CPP_CLASS, |
| ANNOTATION_CUSTOM_MAP, ANNOTATION_GENERATE_BODY_DESCRIPTOR, |
| ANNOTATION_EXPORT, ANNOTATION_DO_NOT_GENERATE_CAST, |
| ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT, |
| ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT}, |
| {ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE, |
| ANNOTATION_INSTANCE_TYPE_VALUE}); |
| ClassFlags flags = ClassFlag::kNone; |
| bool generate_print = annotations.Contains(ANNOTATION_GENERATE_PRINT); |
| if (generate_print) flags |= ClassFlag::kGeneratePrint; |
| bool generate_verify = !annotations.Contains(ANNOTATION_NO_VERIFIER); |
| if (generate_verify) flags |= ClassFlag::kGenerateVerify; |
| if (annotations.Contains(ANNOTATION_ABSTRACT)) { |
| flags |= ClassFlag::kAbstract; |
| } |
| if (annotations.Contains(ANNOTATION_HAS_SAME_INSTANCE_TYPE_AS_PARENT)) { |
| flags |= ClassFlag::kHasSameInstanceTypeAsParent; |
| } |
| if (annotations.Contains(ANNOTATION_GENERATE_CPP_CLASS)) { |
| flags |= ClassFlag::kGenerateCppClassDefinitions; |
| } |
| if (annotations.Contains(ANNOTATION_CUSTOM_CPP_CLASS)) { |
| flags |= ClassFlag::kCustomCppClass; |
| } |
| if (annotations.Contains(ANNOTATION_CUSTOM_MAP)) { |
| flags |= ClassFlag::kCustomMap; |
| } |
| if (annotations.Contains(ANNOTATION_DO_NOT_GENERATE_CAST)) { |
| flags |= ClassFlag::kDoNotGenerateCast; |
| } |
| if (annotations.Contains(ANNOTATION_GENERATE_BODY_DESCRIPTOR)) { |
| flags |= ClassFlag::kGenerateBodyDescriptor; |
| } |
| if (annotations.Contains(ANNOTATION_EXPORT)) { |
| flags |= ClassFlag::kExport; |
| } |
| if (annotations.Contains(ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT)) { |
| flags |= ClassFlag::kHighestInstanceTypeWithinParent; |
| } |
| if (annotations.Contains(ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT)) { |
| flags |= ClassFlag::kLowestInstanceTypeWithinParent; |
| } |
| |
| auto is_extern = child_results->NextAs<bool>(); |
| if (is_extern) flags |= ClassFlag::kExtern; |
| auto transient = child_results->NextAs<bool>(); |
| if (transient) flags |= ClassFlag::kTransient; |
| std::string kind = child_results->NextAs<Identifier*>()->value; |
| if (kind == "shape") { |
| flags |= ClassFlag::kIsShape; |
| flags |= ClassFlag::kTransient; |
| flags |= ClassFlag::kHasSameInstanceTypeAsParent; |
| flags |= ClassFlag::kDoNotGenerateCast; |
| } else { |
| DCHECK_EQ(kind, "class"); |
| } |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsValidTypeName(name->value)) { |
| NamingConventionError("Type", name, "UpperCamelCase"); |
| } |
| auto extends = child_results->NextAs<TypeExpression*>(); |
| if (!BasicTypeExpression::DynamicCast(extends)) { |
| ReportError("Expected type name in extends clause."); |
| } |
| auto generates = child_results->NextAs<base::Optional<std::string>>(); |
| auto body = child_results->NextAs<base::Optional<ClassBody*>>(); |
| std::vector<Declaration*> methods; |
| std::vector<ClassFieldExpression> fields_raw; |
| if (body.has_value()) { |
| methods = (*body)->methods; |
| fields_raw = (*body)->fields; |
| } else { |
| flags |= ClassFlag::kUndefinedLayout; |
| } |
| |
| // Filter to only include fields that should be present based on decoration. |
| std::vector<ClassFieldExpression> fields; |
| std::copy_if( |
| fields_raw.begin(), fields_raw.end(), std::back_inserter(fields), |
| [](const ClassFieldExpression& exp) { |
| for (const ConditionalAnnotation& condition : exp.conditions) { |
| if (condition.type == ConditionalAnnotationType::kPositive |
| ? !BuildFlags::GetFlag(condition.condition, ANNOTATION_IF) |
| : BuildFlags::GetFlag(condition.condition, |
| ANNOTATION_IFNOT)) { |
| return false; |
| } |
| } |
| return true; |
| }); |
| |
| std::vector<Declaration*> result; |
| |
| result.push_back(MakeNode<ClassDeclaration>( |
| name, flags, extends, std::move(generates), std::move(methods), fields, |
| MakeInstanceTypeConstraints(annotations))); |
| |
| Identifier* constexpr_name = |
| MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + name->value); |
| constexpr_name->pos = name->pos; |
| TypeExpression* constexpr_extends = AddConstexpr(extends); |
| AbstractTypeFlags abstract_type_flags(AbstractTypeFlag::kConstexpr); |
| if (transient) abstract_type_flags |= AbstractTypeFlag::kTransient; |
| TypeDeclaration* constexpr_decl = MakeNode<AbstractTypeDeclaration>( |
| constexpr_name, abstract_type_flags, constexpr_extends, name->value); |
| constexpr_decl->pos = name->pos; |
| result.push_back(constexpr_decl); |
| |
| if ((flags & ClassFlag::kDoNotGenerateCast) == 0 && |
| (flags & ClassFlag::kIsShape) == 0) { |
| ParameterList parameters; |
| parameters.names.push_back(MakeNode<Identifier>("obj")); |
| parameters.types.push_back( |
| MakeNode<BasicTypeExpression>(std::vector<std::string>{}, "HeapObject", |
| std::vector<TypeExpression*>{})); |
| LabelAndTypesVector labels; |
| labels.push_back(LabelAndTypes{MakeNode<Identifier>("CastError"), |
| std::vector<TypeExpression*>{}}); |
| |
| TypeExpression* class_type = |
| MakeNode<BasicTypeExpression>(std::vector<std::string>{}, name->value, |
| std::vector<TypeExpression*>{}); |
| |
| std::vector<std::string> namespace_qualification{ |
| TORQUE_INTERNAL_NAMESPACE_STRING}; |
| |
| IdentifierExpression* internal_downcast_target = |
| MakeNode<IdentifierExpression>( |
| namespace_qualification, |
| MakeNode<Identifier>("DownCastForTorqueClass"), |
| std::vector<TypeExpression*>{class_type}); |
| IdentifierExpression* internal_downcast_otherwise = |
| MakeNode<IdentifierExpression>(std::vector<std::string>{}, |
| MakeNode<Identifier>("CastError")); |
| |
| Expression* argument = MakeNode<IdentifierExpression>( |
| std::vector<std::string>{}, MakeNode<Identifier>("obj")); |
| |
| auto value = MakeCall(internal_downcast_target, base::nullopt, |
| std::vector<Expression*>{argument}, |
| std::vector<Statement*>{MakeNode<ExpressionStatement>( |
| internal_downcast_otherwise)}); |
| |
| auto cast_body = MakeNode<ReturnStatement>(value); |
| |
| std::vector<TypeExpression*> generic_parameters; |
| generic_parameters.push_back( |
| MakeNode<BasicTypeExpression>(std::vector<std::string>{}, name->value, |
| std::vector<TypeExpression*>{})); |
| |
| Declaration* specialization = MakeNode<SpecializationDeclaration>( |
| false, MakeNode<Identifier>("Cast"), generic_parameters, |
| std::move(parameters), class_type, std::move(labels), cast_body); |
| result.push_back(specialization); |
| } |
| |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeNamespaceDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<std::string>(); |
| if (!IsSnakeCase(name)) { |
| NamingConventionError("Namespace", name, "snake_case"); |
| } |
| auto declarations = child_results->NextAs<std::vector<Declaration*>>(); |
| Declaration* result = |
| MakeNode<NamespaceDeclaration>(std::move(name), std::move(declarations)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeSpecializationDeclaration( |
| ParseResultIterator* child_results) { |
| auto transitioning = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto generic_parameters = |
| child_results->NextAs<std::vector<TypeExpression*>>(); |
| auto parameters = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| auto labels = child_results->NextAs<LabelAndTypesVector>(); |
| auto body = child_results->NextAs<Statement*>(); |
| CheckNotDeferredStatement(body); |
| Declaration* result = MakeNode<SpecializationDeclaration>( |
| transitioning, std::move(name), std::move(generic_parameters), |
| std::move(parameters), return_type, std::move(labels), body); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeStructDeclaration( |
| ParseResultIterator* child_results) { |
| bool is_export = HasExportAnnotation(child_results, "Struct"); |
| |
| StructFlags flags = StructFlag::kNone; |
| if (is_export) flags |= StructFlag::kExport; |
| |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsValidTypeName(name->value)) { |
| NamingConventionError("Struct", name, "UpperCamelCase"); |
| } |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| LintGenericParameters(generic_parameters); |
| auto methods = child_results->NextAs<std::vector<Declaration*>>(); |
| auto fields = child_results->NextAs<std::vector<StructFieldExpression>>(); |
| TypeDeclaration* struct_decl = MakeNode<StructDeclaration>( |
| flags, name, std::move(methods), std::move(fields)); |
| Declaration* result = struct_decl; |
| if (!generic_parameters.empty()) { |
| result = MakeNode<GenericTypeDeclaration>(generic_parameters, struct_decl); |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeBitFieldStructDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsValidTypeName(name->value)) { |
| NamingConventionError("Bitfield struct", name, "UpperCamelCase"); |
| } |
| auto extends = child_results->NextAs<TypeExpression*>(); |
| auto fields = child_results->NextAs<std::vector<BitFieldDeclaration>>(); |
| Declaration* decl = |
| MakeNode<BitFieldStructDeclaration>(name, extends, std::move(fields)); |
| return ParseResult{decl}; |
| } |
| |
| base::Optional<ParseResult> MakeCppIncludeDeclaration( |
| ParseResultIterator* child_results) { |
| auto include_path = child_results->NextAs<std::string>(); |
| Declaration* result = |
| MakeNode<CppIncludeDeclaration>(std::move(include_path)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> ProcessTorqueImportDeclaration( |
| ParseResultIterator* child_results) { |
| auto import_path = child_results->NextAs<std::string>(); |
| if (!SourceFileMap::FileRelativeToV8RootExists(import_path)) { |
| Error("File '", import_path, "' not found."); |
| } |
| |
| auto import_id = SourceFileMap::GetSourceId(import_path); |
| if (!import_id.IsValid()) { |
| // TODO(szuend): Instead of reporting and error. Queue the file up |
| // for compilation. |
| Error("File '", import_path, "'is not part of the source set.").Throw(); |
| } |
| |
| CurrentAst::Get().DeclareImportForCurrentFile(import_id); |
| |
| return base::nullopt; |
| } |
| |
| base::Optional<ParseResult> MakeExternalBuiltin( |
| ParseResultIterator* child_results) { |
| auto transitioning = child_results->NextAs<bool>(); |
| auto js_linkage = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto generic_parameters = child_results->NextAs<GenericParameters>(); |
| LintGenericParameters(generic_parameters); |
| |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| Declaration* result = MakeNode<ExternalBuiltinDeclaration>( |
| transitioning, js_linkage, name, args, return_type); |
| if (!generic_parameters.empty()) { |
| Error("External builtins cannot be generic."); |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeExternalRuntime( |
| ParseResultIterator* child_results) { |
| auto transitioning = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto args = child_results->NextAs<ParameterList>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| Declaration* result = MakeNode<ExternalRuntimeDeclaration>( |
| transitioning, name, args, return_type); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> StringLiteralUnquoteAction( |
| ParseResultIterator* child_results) { |
| return ParseResult{ |
| StringLiteralUnquote(child_results->NextAs<std::string>())}; |
| } |
| |
| base::Optional<ParseResult> MakeBasicTypeExpression( |
| ParseResultIterator* child_results) { |
| auto namespace_qualification = |
| child_results->NextAs<std::vector<std::string>>(); |
| auto is_constexpr = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<std::string>(); |
| auto generic_arguments = |
| child_results->NextAs<std::vector<TypeExpression*>>(); |
| TypeExpression* result = MakeNode<BasicTypeExpression>( |
| std::move(namespace_qualification), |
| is_constexpr ? GetConstexprName(name) : std::move(name), |
| std::move(generic_arguments)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeFunctionTypeExpression( |
| ParseResultIterator* child_results) { |
| auto parameters = child_results->NextAs<std::vector<TypeExpression*>>(); |
| auto return_type = child_results->NextAs<TypeExpression*>(); |
| TypeExpression* result = |
| MakeNode<FunctionTypeExpression>(std::move(parameters), return_type); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeReferenceTypeExpression( |
| ParseResultIterator* child_results) { |
| auto is_const = child_results->NextAs<bool>(); |
| auto referenced_type = child_results->NextAs<TypeExpression*>(); |
| std::vector<std::string> namespace_qualification{ |
| TORQUE_INTERNAL_NAMESPACE_STRING}; |
| std::vector<TypeExpression*> generic_arguments{referenced_type}; |
| TypeExpression* result = MakeNode<BasicTypeExpression>( |
| namespace_qualification, |
| is_const ? CONST_REFERENCE_TYPE_STRING : MUTABLE_REFERENCE_TYPE_STRING, |
| generic_arguments); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeUnionTypeExpression( |
| ParseResultIterator* child_results) { |
| auto a = child_results->NextAs<TypeExpression*>(); |
| auto b = child_results->NextAs<TypeExpression*>(); |
| TypeExpression* result = MakeNode<UnionTypeExpression>(a, b); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeGenericParameter( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto constraint = child_results->NextAs<base::Optional<TypeExpression*>>(); |
| return ParseResult{GenericParameter{name, constraint}}; |
| } |
| |
| base::Optional<ParseResult> MakeExpressionStatement( |
| ParseResultIterator* child_results) { |
| auto expression = child_results->NextAs<Expression*>(); |
| Statement* result = MakeNode<ExpressionStatement>(expression); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeIfStatement( |
| ParseResultIterator* child_results) { |
| auto is_constexpr = child_results->NextAs<bool>(); |
| auto condition = child_results->NextAs<Expression*>(); |
| auto if_true = child_results->NextAs<Statement*>(); |
| auto if_false = child_results->NextAs<base::Optional<Statement*>>(); |
| |
| if (if_false && !(BlockStatement::DynamicCast(if_true) && |
| (BlockStatement::DynamicCast(*if_false) || |
| IfStatement::DynamicCast(*if_false)))) { |
| ReportError("if-else statements require curly braces"); |
| } |
| |
| if (is_constexpr) { |
| CheckNotDeferredStatement(if_true); |
| if (if_false) CheckNotDeferredStatement(*if_false); |
| } |
| |
| Statement* result = |
| MakeNode<IfStatement>(is_constexpr, condition, if_true, if_false); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeEnumDeclaration( |
| ParseResultIterator* child_results) { |
| const bool is_extern = child_results->NextAs<bool>(); |
| auto name_identifier = child_results->NextAs<Identifier*>(); |
| auto name = name_identifier->value; |
| auto base_type_expression = |
| child_results->NextAs<base::Optional<TypeExpression*>>(); |
| auto constexpr_generates_opt = |
| child_results->NextAs<base::Optional<std::string>>(); |
| auto entries = child_results->NextAs<std::vector<EnumEntry>>(); |
| const bool is_open = child_results->NextAs<bool>(); |
| CurrentSourcePosition::Scope current_source_position( |
| child_results->matched_input().pos); |
| |
| if (!is_extern) { |
| ReportError("non-extern enums are not supported yet"); |
| } |
| |
| if (!IsValidTypeName(name)) { |
| NamingConventionError("Type", name, "UpperCamelCase"); |
| } |
| |
| auto constexpr_generates = |
| constexpr_generates_opt ? *constexpr_generates_opt : name; |
| const bool generate_nonconstexpr = base_type_expression.has_value(); |
| |
| std::vector<Declaration*> result; |
| // Build non-constexpr types. |
| if (generate_nonconstexpr) { |
| DCHECK(base_type_expression.has_value()); |
| |
| if (is_open) { |
| // For open enumerations, we define an abstract type and inherit all |
| // entries' types from that: |
| // type Enum extends Base; |
| // namespace Enum { |
| // type kEntry0 extends Enum; |
| // ... |
| // type kEntryN extends Enum; |
| // } |
| auto type_decl = MakeNode<AbstractTypeDeclaration>( |
| name_identifier, AbstractTypeFlag::kNone, base_type_expression, |
| base::nullopt); |
| |
| TypeExpression* name_type_expression = |
| MakeNode<BasicTypeExpression>(name_identifier->value); |
| name_type_expression->pos = name_identifier->pos; |
| |
| std::vector<Declaration*> entry_decls; |
| for (const auto& entry : entries) { |
| entry_decls.push_back(MakeNode<AbstractTypeDeclaration>( |
| entry.name, AbstractTypeFlag::kNone, |
| entry.type.value_or(name_type_expression), base::nullopt)); |
| } |
| |
| result.push_back(type_decl); |
| result.push_back( |
| MakeNode<NamespaceDeclaration>(name, std::move(entry_decls))); |
| } else { |
| // For closed enumerations, we define abstract types for all entries and |
| // define the enumeration as a union of those: |
| // namespace Enum { |
| // type kEntry0 extends Base; |
| // ... |
| // type kEntryN extends Base; |
| // } |
| // type Enum = Enum::kEntry0 | ... | Enum::kEntryN; |
| TypeExpression* union_type = nullptr; |
| std::vector<Declaration*> entry_decls; |
| for (const auto& entry : entries) { |
| entry_decls.push_back(MakeNode<AbstractTypeDeclaration>( |
| entry.name, AbstractTypeFlag::kNone, |
| entry.type.value_or(*base_type_expression), base::nullopt)); |
| |
| auto entry_type = MakeNode<BasicTypeExpression>( |
| std::vector<std::string>{name}, entry.name->value, |
| std::vector<TypeExpression*>{}); |
| if (union_type) { |
| union_type = MakeNode<UnionTypeExpression>(union_type, entry_type); |
| } else { |
| union_type = entry_type; |
| } |
| } |
| |
| result.push_back( |
| MakeNode<NamespaceDeclaration>(name, std::move(entry_decls))); |
| result.push_back( |
| MakeNode<TypeAliasDeclaration>(name_identifier, union_type)); |
| } |
| } |
| |
| // Build constexpr types. |
| { |
| // The constexpr entries inherit from an abstract enumeration type: |
| // type constexpr Enum extends constexpr Base; |
| // namespace Enum { |
| // type constexpr kEntry0 extends constexpr Enum; |
| // ... |
| // type constexpr kEntry1 extends constexpr Enum; |
| // } |
| Identifier* constexpr_type_identifier = |
| MakeNode<Identifier>(std::string(CONSTEXPR_TYPE_PREFIX) + name); |
| TypeExpression* constexpr_type_expression = MakeNode<BasicTypeExpression>( |
| std::string(CONSTEXPR_TYPE_PREFIX) + name); |
| base::Optional<TypeExpression*> base_constexpr_type_expression = |
| base::nullopt; |
| if (base_type_expression) { |
| base_constexpr_type_expression = AddConstexpr(*base_type_expression); |
| } |
| result.push_back(MakeNode<AbstractTypeDeclaration>( |
| constexpr_type_identifier, AbstractTypeFlag::kConstexpr, |
| base_constexpr_type_expression, constexpr_generates)); |
| |
| TypeExpression* type_expr = nullptr; |
| Identifier* fromconstexpr_identifier = nullptr; |
| Identifier* fromconstexpr_parameter_identifier = nullptr; |
| Statement* fromconstexpr_body = nullptr; |
| if (generate_nonconstexpr) { |
| DCHECK(base_type_expression.has_value()); |
| type_expr = MakeNode<BasicTypeExpression>( |
| std::vector<std::string>{}, name, std::vector<TypeExpression*>{}); |
| |
| // return %RawDownCast<Enum>(%FromConstexpr<Base>(o))) |
| fromconstexpr_identifier = MakeNode<Identifier>("FromConstexpr"); |
| fromconstexpr_parameter_identifier = MakeNode<Identifier>("o"); |
| fromconstexpr_body = |
| MakeNode<ReturnStatement>(MakeNode<IntrinsicCallExpression>( |
| MakeNode<Identifier>("%RawDownCast"), |
| std::vector<TypeExpression*>{type_expr}, |
| std::vector<Expression*>{MakeNode<IntrinsicCallExpression>( |
| MakeNode<Identifier>("%FromConstexpr"), |
| std::vector<TypeExpression*>{*base_type_expression}, |
| std::vector<Expression*>{MakeNode<IdentifierExpression>( |
| std::vector<std::string>{}, |
| fromconstexpr_parameter_identifier)})})); |
| } |
| |
| EnumDescription enum_description{CurrentSourcePosition::Get(), name, |
| constexpr_generates, is_open}; |
| std::vector<Declaration*> entry_decls; |
| for (const auto& entry : entries) { |
| const std::string entry_name = entry.name->value; |
| const std::string entry_constexpr_type = |
| CONSTEXPR_TYPE_PREFIX + entry_name; |
| enum_description.entries.push_back(constexpr_generates + |
| "::" + entry_name); |
| |
| entry_decls.push_back(MakeNode<AbstractTypeDeclaration>( |
| MakeNode<Identifier>(entry_constexpr_type), |
| AbstractTypeFlag::kConstexpr, constexpr_type_expression, |
| constexpr_generates)); |
| |
| bool generate_typed_constant = entry.type.has_value(); |
| if (generate_typed_constant) { |
| // namespace Enum { |
| // const constexpr_constant_kEntry0: constexpr kEntry0 constexpr |
| // 'Enum::kEntry0'; const kEntry0 = %RawDownCast<T, |
| // Base>(FromConstexpr<Enum>(constexpr_constant_kEntry0)); |
| // } |
| if (!generate_nonconstexpr) { |
| Error( |
| "Enum constants with custom types require an enum with an " |
| "extends clause.") |
| .Position((*entry.type)->pos); |
| } |
| Identifier* constexpr_constant_name = |
| MakeNode<Identifier>("constexpr constant " + entry_name); |
| entry_decls.push_back(MakeNode<ExternConstDeclaration>( |
| constexpr_constant_name, |
| MakeNode<BasicTypeExpression>(std::vector<std::string>{}, |
| entry_constexpr_type, |
| std::vector<TypeExpression*>{}), |
| constexpr_generates + "::" + entry_name)); |
| entry_decls.push_back(MakeNode<ConstDeclaration>( |
| entry.name, *entry.type, |
| MakeNode<IntrinsicCallExpression>( |
| MakeNode<Identifier>("%RawDownCast"), |
| std::vector<TypeExpression*>{*entry.type, |
| *base_type_expression}, |
| std::vector<Expression*>{MakeCall( |
| MakeNode<Identifier>("FromConstexpr"), {type_expr}, |
| {MakeNode<IdentifierExpression>(std::vector<std::string>{}, |
| constexpr_constant_name)}, |
| {})}))); |
| } else { |
| // namespace Enum { |
| // const kEntry0: constexpr kEntry0 constexpr 'Enum::kEntry0'; |
| // } |
| entry_decls.push_back(MakeNode<ExternConstDeclaration>( |
| entry.name, |
| MakeNode<BasicTypeExpression>(std::vector<std::string>{}, |
| entry_constexpr_type, |
| std::vector<TypeExpression*>{}), |
| constexpr_generates + "::" + entry_name)); |
| } |
| |
| // FromConstexpr<Enum, Enum::constexpr kEntry0>( |
| // : Enum::constexpr kEntry0): Enum |
| if (generate_nonconstexpr) { |
| TypeExpression* entry_constexpr_type_expr = |
| MakeNode<BasicTypeExpression>(std::vector<std::string>{name}, |
| entry_constexpr_type, |
| std::vector<TypeExpression*>{}); |
| |
| ParameterList parameters; |
| parameters.names.push_back(fromconstexpr_parameter_identifier); |
| parameters.types.push_back(entry_constexpr_type_expr); |
| result.push_back(MakeNode<SpecializationDeclaration>( |
| false, fromconstexpr_identifier, |
| std::vector<TypeExpression*>{type_expr, entry_constexpr_type_expr}, |
| std::move(parameters), type_expr, LabelAndTypesVector{}, |
| fromconstexpr_body)); |
| } |
| } |
| |
| result.push_back( |
| MakeNode<NamespaceDeclaration>(name, std::move(entry_decls))); |
| CurrentAst::Get().AddEnumDescription(std::move(enum_description)); |
| } |
| |
| return ParseResult{std::move(result)}; |
| } |
| |
| base::Optional<ParseResult> MakeTypeswitchStatement( |
| ParseResultIterator* child_results) { |
| auto expression = child_results->NextAs<Expression*>(); |
| auto cases = child_results->NextAs<std::vector<TypeswitchCase>>(); |
| 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<T1>(_value) otherwise _NextCase; |
| // ...b1 |
| // } label _NextCase { |
| // try { |
| // const x2 : T2 = cast<T2>(%assume_impossible<T1>(_value)); |
| // ...b2 |
| // } label _NextCase { |
| // const x3 : T3 = %assume_impossible<T1|T2>(_value); |
| // ...b3 |
| // } |
| // } |
| // } |
| |
| BlockStatement* current_block = MakeNode<BlockStatement>(); |
| Statement* result = current_block; |
| { |
| CurrentSourcePosition::Scope current_source_position(expression->pos); |
| current_block->statements.push_back(MakeNode<VarDeclarationStatement>( |
| true, MakeNode<Identifier>("__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<IdentifierExpression>(MakeNode<Identifier>("__value")); |
| if (i >= 1) { |
| value = |
| MakeNode<AssumeTypeImpossibleExpression>(accumulated_types, value); |
| } |
| BlockStatement* case_block; |
| if (i < cases.size() - 1) { |
| value = MakeCall(MakeNode<Identifier>("Cast"), |
| std::vector<TypeExpression*>{cases[i].type}, |
| std::vector<Expression*>{value}, |
| std::vector<Statement*>{MakeNode<ExpressionStatement>( |
| MakeNode<IdentifierExpression>( |
| MakeNode<Identifier>(kNextCaseLabelName)))}); |
| case_block = MakeNode<BlockStatement>(); |
| } else { |
| case_block = current_block; |
| } |
| std::string name = "__case_value"; |
| if (cases[i].name) name = *cases[i].name; |
| case_block->statements.push_back(MakeNode<VarDeclarationStatement>( |
| true, MakeNode<Identifier>(name), cases[i].type, value)); |
| case_block->statements.push_back(cases[i].block); |
| if (i < cases.size() - 1) { |
| BlockStatement* next_block = MakeNode<BlockStatement>(); |
| current_block->statements.push_back( |
| MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>( |
| MakeNode<StatementExpression>(case_block), |
| MakeNode<TryHandler>(TryHandler::HandlerKind::kLabel, |
| MakeNode<Identifier>(kNextCaseLabelName), |
| ParameterList::Empty(), next_block)))); |
| current_block = next_block; |
| } |
| accumulated_types = |
| i > 0 ? MakeNode<UnionTypeExpression>(accumulated_types, cases[i].type) |
| : cases[i].type; |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeTypeswitchCase( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<base::Optional<std::string>>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| auto block = child_results->NextAs<Statement*>(); |
| return ParseResult{TypeswitchCase{child_results->matched_input().pos, |
| std::move(name), type, block}}; |
| } |
| |
| base::Optional<ParseResult> MakeWhileStatement( |
| ParseResultIterator* child_results) { |
| auto condition = child_results->NextAs<Expression*>(); |
| auto body = child_results->NextAs<Statement*>(); |
| Statement* result = MakeNode<WhileStatement>(condition, body); |
| CheckNotDeferredStatement(result); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeReturnStatement( |
| ParseResultIterator* child_results) { |
| auto value = child_results->NextAs<base::Optional<Expression*>>(); |
| Statement* result = MakeNode<ReturnStatement>(value); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeTailCallStatement( |
| ParseResultIterator* child_results) { |
| auto value = child_results->NextAs<Expression*>(); |
| Statement* result = MakeNode<TailCallStatement>(CallExpression::cast(value)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeVarDeclarationStatement( |
| ParseResultIterator* child_results) { |
| auto kind = child_results->NextAs<Identifier*>(); |
| bool const_qualified = kind->value == "const"; |
| if (!const_qualified) DCHECK_EQ("let", kind->value); |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsLowerCamelCase(name->value)) { |
| NamingConventionError("Variable", name, "lowerCamelCase"); |
| } |
| |
| auto type = child_results->NextAs<base::Optional<TypeExpression*>>(); |
| base::Optional<Expression*> initializer; |
| if (child_results->HasNext()) |
| initializer = child_results->NextAs<Expression*>(); |
| if (!initializer && !type) { |
| ReportError("Declaration is missing a type."); |
| } |
| Statement* result = MakeNode<VarDeclarationStatement>(const_qualified, name, |
| type, initializer); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeBreakStatement( |
| ParseResultIterator* child_results) { |
| Statement* result = MakeNode<BreakStatement>(); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeContinueStatement( |
| ParseResultIterator* child_results) { |
| Statement* result = MakeNode<ContinueStatement>(); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeGotoStatement( |
| ParseResultIterator* child_results) { |
| auto label = child_results->NextAs<Identifier*>(); |
| auto arguments = child_results->NextAs<std::vector<Expression*>>(); |
| Statement* result = MakeNode<GotoStatement>(label, std::move(arguments)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeBlockStatement( |
| ParseResultIterator* child_results) { |
| auto deferred = child_results->NextAs<bool>(); |
| auto statements = child_results->NextAs<std::vector<Statement*>>(); |
| for (Statement* statement : statements) { |
| CheckNotDeferredStatement(statement); |
| } |
| Statement* result = MakeNode<BlockStatement>(deferred, std::move(statements)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeTryLabelExpression( |
| ParseResultIterator* child_results) { |
| auto try_block = child_results->NextAs<Statement*>(); |
| CheckNotDeferredStatement(try_block); |
| Statement* result = try_block; |
| auto handlers = child_results->NextAs<std::vector<TryHandler*>>(); |
| if (handlers.empty()) { |
| Error("Try blocks without catch or label don't make sense."); |
| } |
| for (size_t i = 0; i < handlers.size(); ++i) { |
| if (i != 0 && |
| handlers[i]->handler_kind == TryHandler::HandlerKind::kCatch) { |
| Error( |
| "A catch handler always has to be first, before any label handler, " |
| "to avoid ambiguity about whether it catches exceptions from " |
| "preceding handlers or not.") |
| .Position(handlers[i]->pos); |
| } |
| result = MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>( |
| MakeNode<StatementExpression>(result), handlers[i])); |
| } |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeForLoopStatement( |
| ParseResultIterator* child_results) { |
| auto var_decl = child_results->NextAs<base::Optional<Statement*>>(); |
| auto test = child_results->NextAs<base::Optional<Expression*>>(); |
| auto action = child_results->NextAs<base::Optional<Expression*>>(); |
| base::Optional<Statement*> action_stmt; |
| if (action) action_stmt = MakeNode<ExpressionStatement>(*action); |
| auto body = child_results->NextAs<Statement*>(); |
| CheckNotDeferredStatement(body); |
| Statement* result = |
| MakeNode<ForLoopStatement>(var_decl, test, action_stmt, body); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeLabelBlock(ParseResultIterator* child_results) { |
| auto label = child_results->NextAs<Identifier*>(); |
| if (!IsUpperCamelCase(label->value)) { |
| NamingConventionError("Label", label, "UpperCamelCase"); |
| } |
| auto parameters = child_results->NextAs<ParameterList>(); |
| auto body = child_results->NextAs<Statement*>(); |
| TryHandler* result = MakeNode<TryHandler>(TryHandler::HandlerKind::kLabel, |
| label, std::move(parameters), body); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) { |
| auto variable = child_results->NextAs<std::string>(); |
| auto body = child_results->NextAs<Statement*>(); |
| if (!IsLowerCamelCase(variable)) { |
| NamingConventionError("Exception", variable, "lowerCamelCase"); |
| } |
| ParameterList parameters; |
| parameters.names.push_back(MakeNode<Identifier>(variable)); |
| parameters.types.push_back(MakeNode<BasicTypeExpression>( |
| std::vector<std::string>{}, "JSAny", std::vector<TypeExpression*>{})); |
| parameters.has_varargs = false; |
| TryHandler* result = MakeNode<TryHandler>( |
| TryHandler::HandlerKind::kCatch, MakeNode<Identifier>(kCatchLabelName), |
| std::move(parameters), body); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeExpressionWithSource( |
| ParseResultIterator* child_results) { |
| auto e = child_results->NextAs<Expression*>(); |
| return ParseResult{ |
| ExpressionWithSource{e, child_results->matched_input().ToString()}}; |
| } |
| |
| base::Optional<ParseResult> MakeIdentifier(ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<std::string>(); |
| Identifier* result = MakeNode<Identifier>(std::move(name)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeIdentifierFromMatchedInput( |
| ParseResultIterator* child_results) { |
| return ParseResult{ |
| MakeNode<Identifier>(child_results->matched_input().ToString())}; |
| } |
| |
| base::Optional<ParseResult> MakeRightShiftIdentifier( |
| ParseResultIterator* child_results) { |
| std::string str = child_results->matched_input().ToString(); |
| for (auto character : str) { |
| if (character != '>') { |
| ReportError("right-shift operators may not contain any whitespace"); |
| } |
| } |
| return ParseResult{MakeNode<Identifier>(str)}; |
| } |
| |
| base::Optional<ParseResult> MakeNamespaceQualification( |
| ParseResultIterator* child_results) { |
| bool global_namespace = child_results->NextAs<bool>(); |
| auto namespace_qualification = |
| child_results->NextAs<std::vector<std::string>>(); |
| if (global_namespace) { |
| namespace_qualification.insert(namespace_qualification.begin(), ""); |
| } |
| return ParseResult(std::move(namespace_qualification)); |
| } |
| |
| base::Optional<ParseResult> MakeIdentifierExpression( |
| ParseResultIterator* child_results) { |
| auto namespace_qualification = |
| child_results->NextAs<std::vector<std::string>>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto generic_arguments = |
| child_results->NextAs<std::vector<TypeExpression*>>(); |
| Expression* result = MakeNode<IdentifierExpression>( |
| std::move(namespace_qualification), name, std::move(generic_arguments)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeFieldAccessExpression( |
| ParseResultIterator* child_results) { |
| auto object = child_results->NextAs<Expression*>(); |
| auto field = child_results->NextAs<Identifier*>(); |
| Expression* result = MakeNode<FieldAccessExpression>(object, field); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeReferenceFieldAccessExpression( |
| ParseResultIterator* child_results) { |
| auto object = child_results->NextAs<Expression*>(); |
| auto field = child_results->NextAs<Identifier*>(); |
| // `a->b` is equivalent to `(*a).b`. |
| Expression* deref = MakeNode<DereferenceExpression>(object); |
| Expression* result = MakeNode<FieldAccessExpression>(deref, field); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeElementAccessExpression( |
| ParseResultIterator* child_results) { |
| auto object = child_results->NextAs<Expression*>(); |
| auto field = child_results->NextAs<Expression*>(); |
| Expression* result = MakeNode<ElementAccessExpression>(object, field); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeDereferenceExpression( |
| ParseResultIterator* child_results) { |
| auto reference = child_results->NextAs<Expression*>(); |
| Expression* result = MakeNode<DereferenceExpression>(reference); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeStructExpression( |
| ParseResultIterator* child_results) { |
| auto type = child_results->NextAs<TypeExpression*>(); |
| auto initializers = child_results->NextAs<std::vector<NameAndExpression>>(); |
| Expression* result = |
| MakeNode<StructExpression>(type, std::move(initializers)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeAssignmentExpression( |
| ParseResultIterator* child_results) { |
| auto location = child_results->NextAs<Expression*>(); |
| auto op = child_results->NextAs<base::Optional<std::string>>(); |
| auto value = child_results->NextAs<Expression*>(); |
| Expression* result = |
| MakeNode<AssignmentExpression>(location, std::move(op), value); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeNumberLiteralExpression( |
| ParseResultIterator* child_results) { |
| auto number = child_results->NextAs<std::string>(); |
| // TODO(tebbi): Support 64bit literals. |
| // Meanwhile, we type it as constexpr float64 when out of int32 range. |
| double value = 0; |
| try { |
| value = std::stod(number); |
| } catch (const std::out_of_range&) { |
| Error("double literal out-of-range").Throw(); |
| } |
| Expression* result = MakeNode<NumberLiteralExpression>(value); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeStringLiteralExpression( |
| ParseResultIterator* child_results) { |
| auto literal = child_results->NextAs<std::string>(); |
| Expression* result = MakeNode<StringLiteralExpression>(std::move(literal)); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeIncrementDecrementExpressionPostfix( |
| ParseResultIterator* child_results) { |
| auto location = child_results->NextAs<Expression*>(); |
| auto op = child_results->NextAs<IncrementDecrementOperator>(); |
| Expression* result = |
| MakeNode<IncrementDecrementExpression>(location, op, true); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeIncrementDecrementExpressionPrefix( |
| ParseResultIterator* child_results) { |
| auto op = child_results->NextAs<IncrementDecrementOperator>(); |
| auto location = child_results->NextAs<Expression*>(); |
| Expression* result = |
| MakeNode<IncrementDecrementExpression>(location, op, false); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeLogicalOrExpression( |
| ParseResultIterator* child_results) { |
| auto left = child_results->NextAs<Expression*>(); |
| auto right = child_results->NextAs<Expression*>(); |
| Expression* result = MakeNode<LogicalOrExpression>(left, right); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeLogicalAndExpression( |
| ParseResultIterator* child_results) { |
| auto left = child_results->NextAs<Expression*>(); |
| auto right = child_results->NextAs<Expression*>(); |
| Expression* result = MakeNode<LogicalAndExpression>(left, right); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeConditionalExpression( |
| ParseResultIterator* child_results) { |
| auto condition = child_results->NextAs<Expression*>(); |
| auto if_true = child_results->NextAs<Expression*>(); |
| auto if_false = child_results->NextAs<Expression*>(); |
| Expression* result = |
| MakeNode<ConditionalExpression>(condition, if_true, if_false); |
| return ParseResult{result}; |
| } |
| |
| base::Optional<ParseResult> MakeLabelAndTypes( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| if (!IsUpperCamelCase(name->value)) { |
| NamingConventionError("Label", name, "UpperCamelCase"); |
| } |
| auto types = child_results->NextAs<std::vector<TypeExpression*>>(); |
| return ParseResult{LabelAndTypes{name, std::move(types)}}; |
| } |
| |
| base::Optional<ParseResult> MakeNameAndType( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| return ParseResult{NameAndTypeExpression{name, type}}; |
| } |
| |
| base::Optional<ParseResult> MakeEnumEntry(ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto type = child_results->NextAs<base::Optional<TypeExpression*>>(); |
| return ParseResult{EnumEntry{name, type}}; |
| } |
| |
| base::Optional<ParseResult> MakeNameAndExpression( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto expression = child_results->NextAs<Expression*>(); |
| return ParseResult{NameAndExpression{name, expression}}; |
| } |
| |
| base::Optional<ParseResult> MakeNameAndExpressionFromExpression( |
| ParseResultIterator* child_results) { |
| auto expression = child_results->NextAs<Expression*>(); |
| if (auto* id = IdentifierExpression::DynamicCast(expression)) { |
| if (!id->generic_arguments.empty() || |
| !id->namespace_qualification.empty()) { |
| ReportError("expected a plain identifier without qualification"); |
| } |
| return ParseResult{NameAndExpression{id->name, id}}; |
| } |
| ReportError("Constructor parameters need to be named."); |
| } |
| |
| base::Optional<ParseResult> MakeAnnotation(ParseResultIterator* child_results) { |
| return ParseResult{ |
| Annotation{child_results->NextAs<Identifier*>(), |
| child_results->NextAs<base::Optional<AnnotationParameter>>()}}; |
| } |
| |
| base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) { |
| AnnotationSet annotations(child_results, {ANNOTATION_NO_VERIFIER}, |
| {ANNOTATION_IF, ANNOTATION_IFNOT}); |
| bool generate_verify = !annotations.Contains(ANNOTATION_NO_VERIFIER); |
| std::vector<ConditionalAnnotation> conditions; |
| base::Optional<std::string> if_condition = |
| annotations.GetStringParam(ANNOTATION_IF); |
| base::Optional<std::string> ifnot_condition = |
| annotations.GetStringParam(ANNOTATION_IFNOT); |
| if (if_condition.has_value()) { |
| conditions.push_back({*if_condition, ConditionalAnnotationType::kPositive}); |
| } |
| if (ifnot_condition.has_value()) { |
| conditions.push_back( |
| {*ifnot_condition, ConditionalAnnotationType::kNegative}); |
| } |
| auto weak = child_results->NextAs<bool>(); |
| auto const_qualified = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto index = child_results->NextAs<base::Optional<Expression*>>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| return ParseResult{ClassFieldExpression{{name, type}, |
| index, |
| std::move(conditions), |
| weak, |
| const_qualified, |
| generate_verify}}; |
| } |
| |
| base::Optional<ParseResult> MakeStructField( |
| ParseResultIterator* child_results) { |
| auto const_qualified = child_results->NextAs<bool>(); |
| auto name = child_results->NextAs<Identifier*>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| return ParseResult{StructFieldExpression{{name, type}, const_qualified}}; |
| } |
| |
| base::Optional<ParseResult> MakeBitFieldDeclaration( |
| ParseResultIterator* child_results) { |
| auto name = child_results->NextAs<Identifier*>(); |
| auto type = child_results->NextAs<TypeExpression*>(); |
| auto num_bits = child_results->NextAs<int32_t>(); |
| return ParseResult{BitFieldDeclaration{{name, type}, num_bits}}; |
| } |
| |
| base::Optional<ParseResult> ExtractAssignmentOperator( |
| ParseResultIterator* child_results) { |
| auto op = child_results->NextAs<Identifier*>(); |
| base::Optional<std::string> result = |
| std::string(op->value.begin(), op->value.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; |
| } |
| if (MatchString("/*", pos)) { |
| while (!MatchString("*/", pos)) ++*pos; |
| continue; |
| } |
| return true; |
| } |
| } |
| |
| static bool MatchIdentifier(InputPosition* pos) { |
| InputPosition current = *pos; |
| MatchString("_", ¤t); |
| if (!MatchChar(std::isalpha, ¤t)) return false; |
| while (MatchChar(std::isalnum, ¤t) || MatchString("_", ¤t)) { |
| } |
| *pos = current; |
| return true; |
| } |
| |
| static bool MatchAnnotation(InputPosition* pos) { |
| InputPosition current = *pos; |
| if (!MatchString("@", ¤t)) return false; |
| if (!MatchIdentifier(¤t)) return false; |
| *pos = current; |
| return true; |
| } |
| |
| static bool MatchIntrinsicName(InputPosition* pos) { |
| InputPosition current = *pos; |
| if (!MatchString("%", ¤t)) return false; |
| if (!MatchIdentifier(¤t)) return false; |
| *pos = current; |
| 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: Expression* |
| Symbol* expression = &assignmentExpression; |
| |
| // Result: std::string |
| Symbol identifier = {Rule({Pattern(MatchIdentifier)}, YieldMatchedInput), |
| Rule({Token("runtime")}, YieldMatchedInput)}; |
| |
| // Result: Identifier* |
| Symbol name = {Rule({&identifier}, MakeIdentifier)}; |
| |
| // Result: Identifier* |
| Symbol annotationName = { |
| Rule({Pattern(MatchAnnotation)}, MakeIdentifierFromMatchedInput)}; |
| |
| // Result: std::string |
| Symbol intrinsicName = { |
| Rule({Pattern(MatchIntrinsicName)}, MakeIdentifierFromMatchedInput)}; |
| |
| // 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: int32_t |
| Symbol int32Literal = {Rule({&decimalLiteral}, MakeInt32)}; |
| |
| // Result: AnnotationParameter |
| Symbol annotationParameter = { |
| Rule({&identifier}, MakeStringAnnotationParameter), |
| Rule({&int32Literal}, MakeIntAnnotationParameter), |
| Rule({&externalString}, MakeStringAnnotationParameter)}; |
| |
| // Result: AnnotationParameter |
| Symbol annotationParameters = { |
| Rule({Token("("), &annotationParameter, Token(")")})}; |
| |
| // Result: Annotation |
| Symbol annotation = {Rule( |
| {&annotationName, Optional<AnnotationParameter>(&annotationParameters)}, |
| MakeAnnotation)}; |
| |
| // Result: std::vector<Annotation> |
| Symbol* annotations = List<Annotation>(&annotation); |
| |
| // Result: std::vector<std::string> |
| Symbol namespaceQualification = { |
| Rule({CheckIf(Token("::")), |
| List<std::string>(Sequence({&identifier, Token("::")}))}, |
| MakeNamespaceQualification)}; |
| |
| // Result: TypeList |
| Symbol* typeList = List<TypeExpression*>(&type, Token(",")); |
| |
| // Result: TypeExpression* |
| Symbol simpleType = { |
| Rule({Token("("), &type, Token(")")}), |
| Rule({&namespaceQualification, CheckIf(Token("constexpr")), &identifier, |
| TryOrDefault<std::vector<TypeExpression*>>( |
| &genericSpecializationTypeList)}, |
| MakeBasicTypeExpression), |
| Rule({Token("builtin"), Token("("), typeList, Token(")"), Token("=>"), |
| &simpleType}, |
| MakeFunctionTypeExpression), |
| Rule({CheckIf(Token("const")), Token("&"), &simpleType}, |
| MakeReferenceTypeExpression)}; |
| |
| // Result: TypeExpression* |
| Symbol type = {Rule({&simpleType}), Rule({&type, Token("|"), &simpleType}, |
| MakeUnionTypeExpression)}; |
| |
| // Result: GenericParameter |
| Symbol genericParameter = { |
| Rule({&name, Token(":"), Token("type"), |
| Optional<TypeExpression*>(Sequence({Token("extends"), &type}))}, |
| MakeGenericParameter)}; |
| |
| // Result: GenericParameters |
| Symbol genericParameters = { |
| Rule({Token("<"), List<GenericParameter>(&genericParameter, Token(",")), |
| Token(">")})}; |
| |
| // Result: TypeList |
| Symbol genericSpecializationTypeList = { |
| Rule({Token("<"), typeList, Token(">")})}; |
| |
| // Result: base::Optional<GenericParameters> |
| Symbol* optionalGenericParameters = Optional<TypeList>(&genericParameters); |
| |
| Symbol implicitParameterList{ |
| Rule({Token("("), OneOf({"implicit", "js-implicit"}), |
| List<NameAndTypeExpression>(&nameAndType, Token(",")), Token(")")}, |
| MakeImplicitParameterList)}; |
| |
| Symbol* optionalImplicitParameterList{ |
| Optional<ImplicitParameters>(&implicitParameterList)}; |
| |
| // Result: ParameterList |
| Symbol typeListMaybeVarArgs = { |
| Rule({optionalImplicitParameterList, Token("("), |
| List<TypeExpression*>(Sequence({&type, Token(",")})), Token("..."), |
| Token(")")}, |
| MakeParameterList<true, false>), |
| Rule({optionalImplicitParameterList, Token("("), typeList, Token(")")}, |
| MakeParameterList<false, false>)}; |
| |
| // Result: LabelAndTypes |
| Symbol labelParameter = {Rule( |
| {&name, |
| TryOrDefault<TypeList>(Sequence({Token("("), typeList, Token(")")}))}, |
| MakeLabelAndTypes)}; |
| |
| // Result: TypeExpression* |
| Symbol optionalReturnType = {Rule({Token(":"), &type}), |
| Rule({}, MakeVoidType)}; |
| |
| // Result: LabelAndTypesVector |
| Symbol* optionalLabelList{TryOrDefault<LabelAndTypesVector>( |
| Sequence({Token("labels"), |
| NonemptyList<LabelAndTypes>(&labelParameter, Token(","))}))}; |
| |
| // Result: std::vector<Statement*> |
| Symbol* optionalOtherwise{TryOrDefault<std::vector<Statement*>>( |
| Sequence({Token("otherwise"), |
| NonemptyList<Statement*>(&atomarStatement, Token(","))}))}; |
| |
| // Result: NameAndTypeExpression |
| Symbol nameAndType = {Rule({&name, Token(":"), &type}, MakeNameAndType)}; |
| |
| // Result: base::Optional<Expression*> |
| Symbol* optionalArraySpecifier = |
| Optional<Expression*>(Sequence({Token("["), expression, Token("]")})); |
| |
| // Result: ClassFieldExpression |
| Symbol classField = { |
| Rule({annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name, |
| optionalArraySpecifier, Token(":"), &type, Token(";")}, |
| MakeClassField)}; |
| |
| // Result: StructFieldExpression |
| Symbol structField = { |
| Rule({CheckIf(Token("const")), &name, Token(":"), &type, Token(";")}, |
| MakeStructField)}; |
| |
| // Result: BitFieldDeclaration |
| Symbol bitFieldDeclaration = {Rule({&name, Token(":"), &type, Token(":"), |
| &int32Literal, Token("bit"), Token(";")}, |
| MakeBitFieldDeclaration)}; |
| |
| // Result: ParameterList |
| Symbol parameterListNoVararg = { |
| Rule({optionalImplicitParameterList, Token("("), |
| List<NameAndTypeExpression>(&nameAndType, Token(",")), Token(")")}, |
| MakeParameterList<false, true>)}; |
| |
| // Result: ParameterList |
| Symbol parameterListAllowVararg = { |
| Rule({¶meterListNoVararg}), |
| Rule({optionalImplicitParameterList, Token("("), |
| List<NameAndTypeExpression>(Sequence({&nameAndType, Token(",")})), |
| Token("..."), &identifier, Token(")")}, |
| MakeParameterList<true, true>)}; |
| |
| // Result: Identifier* |
| Symbol* OneOf(const std::vector<std::string>& alternatives) { |
| Symbol* result = NewSymbol(); |
| for (const std::string& s : alternatives) { |
| result->AddRule(Rule({Token(s)}, MakeIdentifierFromMatchedInput)); |
| } |
| return result; |
| } |
| |
| // Result: Expression* |
| Symbol* BinaryOperator(Symbol* nextLevel, Symbol* op) { |
| Symbol* result = NewSymbol(); |
| *result = {Rule({nextLevel}), |
| Rule({result, op, nextLevel}, MakeBinaryOperator)}; |
| return result; |
| } |
| |
| // Result: IncrementDecrementOperator |
| Symbol incrementDecrementOperator = { |
| Rule({Token("++")}, |
| YieldIntegralConstant<IncrementDecrementOperator, |
| IncrementDecrementOperator::kIncrement>), |
| Rule({Token("--")}, |
| YieldIntegralConstant<IncrementDecrementOperator, |
| IncrementDecrementOperator::kDecrement>)}; |
| |
| // Result: Expression* |
| Symbol identifierExpression = { |
| Rule({&namespaceQualification, &name, |
| TryOrDefault<TypeList>(&genericSpecializationTypeList)}, |
| MakeIdentifierExpression), |
| }; |
| |
| // Result: std::vector<Expression*> |
| Symbol argumentList = {Rule( |
| {Token("("), List<Expression*>(expression, Token(",")), Token(")")})}; |
| |
| // Result: Expression* |
| Symbol callExpression = {Rule( |
| {&identifierExpression, &argumentList, optionalOtherwise}, MakeCall)}; |
| |
| // Result: Expression* |
| Symbol callMethodExpression = { |
| Rule({&primaryExpression, Token("."), &identifier, &argumentList, |
| optionalOtherwise}, |
| MakeMethodCall)}; |
| |
| // Result: NameAndExpression |
| Symbol namedExpression = { |
| Rule({&name, Token(":"), expression}, MakeNameAndExpression), |
| Rule({expression}, MakeNameAndExpressionFromExpression)}; |
| |
| // Result: std::vector<NameAndExpression> |
| Symbol initializerList = { |
| Rule({Token("{"), List<NameAndExpression>(&namedExpression, Token(",")), |
| Token("}")})}; |
| |
| // Result: Expression* |
| Symbol intrinsicCallExpression = {Rule( |
| {&intrinsicName, TryOrDefault<TypeList>(&genericSpecializationTypeList), |
| &argumentList}, |
| MakeIntrinsicCallExpression)}; |
| |
| // Result: Expression* |
| Symbol newExpression = { |
| Rule({Token("new"), |
| CheckIf(Sequence({Token("("), Token("Pretenured"), Token(")")})), |
| &simpleType, &initializerList}, |
| MakeNewExpression)}; |
| |
| // Result: Expression* |
| Symbol primaryExpression = { |
| Rule({&callExpression}), |
| Rule({&callMethodExpression}), |
| Rule({&intrinsicCallExpression}), |
| Rule({&identifierExpression}), |
| Rule({&primaryExpression, Token("."), &name}, MakeFieldAccessExpression), |
| Rule({&primaryExpression, Token("->"), &name}, |
| MakeReferenceFieldAccessExpression), |
| Rule({&primaryExpression, Token("["), expression, Token("]")}, |
| MakeElementAccessExpression), |
| Rule({&decimalLiteral}, MakeNumberLiteralExpression), |
| Rule({&stringLiteral}, MakeStringLiteralExpression), |
| Rule({&simpleType, &initializerList}, MakeStructExpression), |
| Rule({&newExpression}), |
| Rule({Token("("), expression, Token(")")})}; |
| |
| // Result: Expression* |
| Symbol unaryExpression = { |
| Rule({&primaryExpression}), |
| Rule({OneOf({"+", "-", "!", "~", "&"}), &unaryExpression}, |
| MakeUnaryOperator), |
| Rule({Token("*"), &unaryExpression}, MakeDereferenceExpression), |
| Rule({Token("..."), &unaryExpression}, MakeSpreadExpression), |
| Rule({&incrementDecrementOperator, &unaryExpression}, |
| MakeIncrementDecrementExpressionPrefix), |
| Rule({&unaryExpression, &incrementDecrementOperator}, |
| MakeIncrementDecrementExpressionPostfix)}; |
| |
| // Result: Expression* |
| Symbol* multiplicativeExpression = |
| BinaryOperator(&unaryExpression, OneOf({"*", "/", "%"})); |
| |
| // Result: Expression* |
| Symbol* additiveExpression = |
| BinaryOperator(multiplicativeExpression, OneOf({"+", "-"})); |
| |
| // Result: Identifier* |
| Symbol shiftOperator = { |
| Rule({Token("<<")}, MakeIdentifierFromMatchedInput), |
| Rule({Token(">"), Token(">")}, MakeRightShiftIdentifier), |
| Rule({Token(">"), Token(">"), Token(">")}, MakeRightShiftIdentifier)}; |
| |
| // Result: Expression* |
| Symbol* shiftExpression = BinaryOperator(additiveExpression, &shiftOperator); |
| |
| // 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<std::string> |
| Symbol assignmentOperator = { |
| Rule({Token("=")}, YieldDefaultValue<base::Optional<std::string>>), |
| Rule({OneOf({"*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", |
| "^=", "|="})}, |
| ExtractAssignmentOperator)}; |
| |
| // Result: Expression* |
| Symbol assignmentExpression = { |
| Rule({&conditionalExpression}), |
| Rule({&conditionalExpression, &assignmentOperator, &assignmentExpression}, |
| MakeAssignmentExpression)}; |
| |
| // Result: Statement* |
| Symbol block = {Rule({CheckIf(Token("deferred")), Token("{"), |
| List<Statement*>(&statement), Token("}")}, |
| MakeBlockStatement)}; |
| |
| // Result: TryHandler* |
| Symbol tryHandler = { |
| Rule({Token("label"), &name, |
| TryOrDefault<ParameterList>(¶meterListNoVararg), &block}, |
| MakeLabelBlock), |
| Rule({Token("catch"), Token("("), &identifier, Token(")"), &block}, |
| MakeCatchBlock)}; |
| |
| // Result: ExpressionWithSource |
| Symbol expressionWithSource = {Rule({expression}, MakeExpressionWithSource)}; |
| |
| Symbol* optionalTypeSpecifier = |
| Optional<TypeExpression*>(Sequence({Token(":"), &type})); |
| |
| // Result: EnumEntry |
| Symbol enumEntry = {Rule({&name, optionalTypeSpecifier}, MakeEnumEntry)}; |
| |
| // Result: Statement* |
| Symbol varDeclaration = { |
| Rule({OneOf({"let", "const"}), &name, optionalTypeSpecifier}, |
| MakeVarDeclarationStatement)}; |
| |
| // Result: Statement* |
| Symbol varDeclarationWithInitialization = { |
| Rule({OneOf({"let", "const"}), &name, optionalTypeSpecifier, Token("="), |
| expression}, |
| MakeVarDeclarationStatement)}; |
| |
| // Result: Statement* |
| Symbol atomarStatement = { |
| Rule({expression}, MakeExpressionStatement), |
| Rule({Token("return"), Optional<Expression*>(expression)}, |
| MakeReturnStatement), |
| Rule({Token("tail"), &callExpression}, MakeTailCallStatement), |
| Rule({Token("break")}, MakeBreakStatement), |
| Rule({Token("continue")}, MakeContinueStatement), |
| Rule({Token("goto"), &name, |
| TryOrDefault<std::vector<Expression*>>(&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<Statement*>(Sequence({Token("else"), &statement}))}, |
| MakeIfStatement), |
| Rule( |
| { |
| Token("typeswitch"), |
| Token("("), |
| expression, |
| Token(")"), |
| Token("{"), |
| NonemptyList<TypeswitchCase>(&typeswitchCase), |
| Token("}"), |
| }, |
| MakeTypeswitchStatement), |
| Rule({Token("try"), &block, List<TryHandler*>(&tryHandler)}, |
| MakeTryLabelExpression), |
| Rule({OneOf({"assert", "check", "static_assert"}), Token("("), |
| &expressionWithSource, Token(")"), Token(";")}, |
| MakeAssertStatement), |
| Rule({Token("while"), Token("("), expression, Token(")"), &statement}, |
| MakeWhileStatement), |
| Rule({Token("for"), Token("("), |
| Optional<Statement*>(&varDeclarationWithInitialization), Token(";"), |
| Optional<Expression*>(expression), Token(";"), |
| Optional<Expression*>(expression), Token(")"), &statement}, |
| MakeForLoopStatement)}; |
| |
| // Result: TypeswitchCase |
| Symbol typeswitchCase = { |
| Rule({Token("case"), Token("("), |
| Optional<std::string>(Sequence({&identifier, Token(":")})), &type, |
| Token(")"), Token(":"), &block}, |
| MakeTypeswitchCase)}; |
| |
| // Result: base::Optional<Statement*> |
| Symbol optionalBody = { |
| Rule({&block}, CastParseResult<Statement*, base::Optional<Statement*>>), |
| Rule({Token(";")}, YieldDefaultValue<base::Optional<Statement*>>)}; |
| |
| // Result: Declaration* |
| Symbol method = {Rule( |
| {CheckIf(Token("transitioning")), |
| Optional<std::string>(Sequence({Token("operator"), &externalString})), |
| Token("macro"), &name, ¶meterListNoVararg, &optionalReturnType, |
| optionalLabelList, &block}, |
| MakeMethodDeclaration)}; |
| |
| // Result: base::Optional<ClassBody*> |
| Symbol optionalClassBody = { |
| Rule({Token("{"), List<Declaration*>(&method), |
| List<ClassFieldExpression>(&classField), Token("}")}, |
| MakeClassBody), |
| Rule({Token(";")}, YieldDefaultValue<base::Optional<ClassBody*>>)}; |
| |
| // Result: std::vector<Declaration*> |
| Symbol declaration = { |
| Rule({Token("const"), &name, Token(":"), &type, Token("="), expression, |
| Token(";")}, |
| AsSingletonVector<Declaration*, MakeConstDeclaration>()), |
| Rule({Token("const"), &name, Token(":"), &type, Token("generates"), |
| &externalString, Token(";")}, |
| AsSingletonVector<Declaration*, MakeExternConstDeclaration>()), |
| Rule({annotations, CheckIf(Token("extern")), CheckIf(Token("transient")), |
| OneOf({"class", "shape"}), &name, Token("extends"), &type, |
| Optional<std::string>( |
| Sequence({Token("generates"), &externalString})), |
| &optionalClassBody}, |
| MakeClassDeclaration), |
| Rule({annotations, Token("struct"), &name, |
| TryOrDefault<GenericParameters>(&genericParameters), Token("{"), |
| List<Declaration*>(&method), |
| List<StructFieldExpression>(&structField), Token("}")}, |
| AsSingletonVector<Declaration*, MakeStructDeclaration>()), |
| Rule({Token("bitfield"), Token("struct"), &name, Token("extends"), &type, |
| Token("{"), List<BitFieldDeclaration>(&bitFieldDeclaration), |
| Token("}")}, |
| AsSingletonVector<Declaration*, MakeBitFieldStructDeclaration>()), |
| Rule({annotations, CheckIf(Token("transient")), Token("type"), &name, |
| TryOrDefault<GenericParameters>(&genericParameters), |
| Optional<TypeExpression*>(Sequence({Token("extends"), &type})), |
| Optional<std::string>( |
| Sequence({Token("generates"), &externalString})), |
| Optional<std::string>( |
| Sequence({Token("constexpr"), &externalString})), |
| Token(";")}, |
| MakeAbstractTypeDeclaration), |
| Rule({Token("type"), &name, Token("="), &type, Token(";")}, |
| AsSingletonVector<Declaration*, MakeTypeAliasDeclaration>()), |
| Rule({Token("intrinsic"), &intrinsicName, |
| TryOrDefault<GenericParameters>(&genericParameters), |
| ¶meterListNoVararg, &optionalReturnType, &optionalBody}, |
| AsSingletonVector<Declaration*, MakeIntrinsicDeclaration>()), |
| Rule({Token("extern"), CheckIf(Token("transitioning")), |
| Optional<std::string>( |
| Sequence({Token("operator"), &externalString})), |
| Token("macro"), |
| Optional<std::string>(Sequence({&identifier, Token("::")})), &name, |
| TryOrDefault<GenericParameters>(&genericParameters), |
| &typeListMaybeVarArgs, &optionalReturnType, optionalLabelList, |
| Token(";")}, |
| AsSingletonVector<Declaration*, MakeExternalMacro>()), |
| Rule({Token("extern"), CheckIf(Token("transitioning")), |
| CheckIf(Token("javascript")), Token("builtin"), &name, |
| TryOrDefault<GenericParameters>(&genericParameters), |
| &typeListMaybeVarArgs, &optionalReturnType, Token(";")}, |
| AsSingletonVector<Declaration*, MakeExternalBuiltin>()), |
| Rule({Token("extern"), CheckIf(Token("transitioning")), Token("runtime"), |
| &name, &typeListMaybeVarArgs, &optionalReturnType, Token(";")}, |
| AsSingletonVector<Declaration*, MakeExternalRuntime>()), |
| Rule({annotations, CheckIf(Token("transitioning")), |
| Optional<std::string>( |
| Sequence({Token("operator"), &externalString})), |
| Token("macro"), &name, |
| TryOrDefault<GenericParameters>(&genericParameters), |
| ¶meterListNoVararg, &optionalReturnType, optionalLabelList, |
| &optionalBody}, |
| AsSingletonVector<Declaration*, MakeTorqueMacroDeclaration>()), |
| Rule({CheckIf(Token("transitioning")), CheckIf(Token("javascript")), |
| Token("builtin"), &name, |
| TryOrDefault<GenericParameters>(&genericParameters), |
| ¶meterListAllowVararg, &optionalReturnType, &optionalBody}, |
| AsSingletonVector<Declaration*, MakeTorqueBuiltinDeclaration>()), |
| Rule({CheckIf(Token("transitioning")), &name, |
| &genericSpecializationTypeList, ¶meterListAllowVararg, |
| &optionalReturnType, optionalLabelList, &block}, |
| AsSingletonVector<Declaration*, MakeSpecializationDeclaration>()), |
| Rule({Token("#include"), &externalString}, |
| AsSingletonVector<Declaration*, MakeCppIncludeDeclaration>()), |
| Rule({CheckIf(Token("extern")), Token("enum"), &name, |
| Optional<TypeExpression*>(Sequence({Token("extends"), &type})), |
| Optional<std::string>( |
| Sequence({Token("constexpr"), &externalString})), |
| Token("{"), NonemptyList<EnumEntry>(&enumEntry, Token(",")), |
| CheckIf(Sequence({Token(","), Token("...")})), Token("}")}, |
| MakeEnumDeclaration), |
| Rule({Token("namespace"), &identifier, Token("{"), &declarationList, |
| Token("}")}, |
| AsSingletonVector<Declaration*, MakeNamespaceDeclaration>())}; |
| |
| // Result: std::vector<Declaration*> |
| Symbol declarationList = { |
| Rule({List<std::vector<Declaration*>>(&declaration)}, ConcatList)}; |
| |
| Symbol file = {Rule({&file, Token("import"), &externalString}, |
| ProcessTorqueImportDeclaration), |
| Rule({&file, &declaration}, AddGlobalDeclarations), Rule({})}; |
| }; |
| |
| } // namespace |
| |
| void ParseTorque(const std::string& input) { |
| BuildFlags::Scope build_flags_scope; |
| TorqueGrammar().Parse(input); |
| } |
| |
| } // namespace torque |
| } // namespace internal |
| } // namespace v8 |