| // Copyright 2017 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/declaration-visitor.h" | |
| namespace v8 { | |
| namespace internal { | |
| namespace torque { | |
| void DeclarationVisitor::Visit(Expression* expr) { | |
| CurrentSourcePosition::Scope scope(expr->pos); | |
| switch (expr->kind) { | |
| #define ENUM_ITEM(name) \ | |
| case AstNode::Kind::k##name: \ | |
| return Visit(name::cast(expr)); | |
| AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM) | |
| #undef ENUM_ITEM | |
| default: | |
| UNIMPLEMENTED(); | |
| } | |
| } | |
| void DeclarationVisitor::Visit(Statement* stmt) { | |
| CurrentSourcePosition::Scope scope(stmt->pos); | |
| switch (stmt->kind) { | |
| #define ENUM_ITEM(name) \ | |
| case AstNode::Kind::k##name: \ | |
| return Visit(name::cast(stmt)); | |
| AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM) | |
| #undef ENUM_ITEM | |
| default: | |
| UNIMPLEMENTED(); | |
| } | |
| } | |
| void DeclarationVisitor::Visit(Declaration* decl) { | |
| CurrentSourcePosition::Scope scope(decl->pos); | |
| switch (decl->kind) { | |
| #define ENUM_ITEM(name) \ | |
| case AstNode::Kind::k##name: \ | |
| return Visit(name::cast(decl)); | |
| AST_DECLARATION_NODE_KIND_LIST(ENUM_ITEM) | |
| #undef ENUM_ITEM | |
| default: | |
| UNIMPLEMENTED(); | |
| } | |
| } | |
| void DeclarationVisitor::Visit(CallableNode* decl, const Signature& signature, | |
| Statement* body) { | |
| switch (decl->kind) { | |
| #define ENUM_ITEM(name) \ | |
| case AstNode::Kind::k##name: \ | |
| return Visit(name::cast(decl), signature, body); | |
| AST_CALLABLE_NODE_KIND_LIST(ENUM_ITEM) | |
| #undef ENUM_ITEM | |
| default: | |
| UNIMPLEMENTED(); | |
| } | |
| } | |
| Builtin* DeclarationVisitor::BuiltinDeclarationCommon( | |
| BuiltinDeclaration* decl, bool external, const Signature& signature) { | |
| const bool javascript = decl->javascript_linkage; | |
| const bool varargs = decl->signature->parameters.has_varargs; | |
| Builtin::Kind kind = !javascript ? Builtin::kStub | |
| : varargs ? Builtin::kVarArgsJavaScript | |
| : Builtin::kFixedArgsJavaScript; | |
| if (signature.types().size() == 0 || | |
| !(signature.types()[0] == | |
| declarations()->LookupGlobalType(CONTEXT_TYPE_STRING))) { | |
| std::stringstream stream; | |
| stream << "first parameter to builtin " << decl->name | |
| << " is not a context but should be"; | |
| ReportError(stream.str()); | |
| } | |
| if (varargs && !javascript) { | |
| std::stringstream stream; | |
| stream << "builtin " << decl->name | |
| << " with rest parameters must be a JavaScript builtin"; | |
| ReportError(stream.str()); | |
| } | |
| if (javascript) { | |
| if (signature.types().size() < 2 || | |
| !(signature.types()[1] == | |
| declarations()->LookupGlobalType(OBJECT_TYPE_STRING))) { | |
| std::stringstream stream; | |
| stream << "second parameter to javascript builtin " << decl->name | |
| << " is " << *signature.types()[1] << " but should be Object"; | |
| ReportError(stream.str()); | |
| } | |
| } | |
| if (const StructType* struct_type = | |
| StructType::DynamicCast(signature.return_type)) { | |
| std::stringstream stream; | |
| stream << "builtins (in this case" << decl->name | |
| << ") cannot return structs (in this case " << struct_type->name() | |
| << ")"; | |
| ReportError(stream.str()); | |
| } | |
| std::string generated_name = GetGeneratedCallableName( | |
| decl->name, declarations()->GetCurrentSpecializationTypeNamesVector()); | |
| return declarations()->DeclareBuiltin(generated_name, kind, external, | |
| signature); | |
| } | |
| void DeclarationVisitor::Visit(ExternalRuntimeDeclaration* decl, | |
| const Signature& signature, Statement* body) { | |
| if (global_context_.verbose()) { | |
| std::cout << "found declaration of external runtime " << decl->name | |
| << " with signature "; | |
| } | |
| if (signature.parameter_types.types.size() == 0 || | |
| !(signature.parameter_types.types[0] == | |
| declarations()->LookupGlobalType(CONTEXT_TYPE_STRING))) { | |
| std::stringstream stream; | |
| stream << "first parameter to runtime " << decl->name | |
| << " is not a context but should be"; | |
| ReportError(stream.str()); | |
| } | |
| if (signature.return_type->IsStructType()) { | |
| std::stringstream stream; | |
| stream << "runtime functions (in this case" << decl->name | |
| << ") cannot return structs (in this case " | |
| << static_cast<const StructType*>(signature.return_type)->name() | |
| << ")"; | |
| ReportError(stream.str()); | |
| } | |
| declarations()->DeclareRuntimeFunction(decl->name, signature); | |
| } | |
| void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl, | |
| const Signature& signature, Statement* body) { | |
| if (global_context_.verbose()) { | |
| std::cout << "found declaration of external macro " << decl->name | |
| << " with signature "; | |
| } | |
| std::string generated_name = GetGeneratedCallableName( | |
| decl->name, declarations()->GetCurrentSpecializationTypeNamesVector()); | |
| declarations()->DeclareMacro(generated_name, signature, decl->op); | |
| } | |
| void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl, | |
| const Signature& signature, Statement* body) { | |
| Builtin* builtin = BuiltinDeclarationCommon(decl, false, signature); | |
| CurrentCallableActivator activator(global_context_, builtin, decl); | |
| DeclareSignature(signature); | |
| if (signature.parameter_types.var_args) { | |
| declarations()->DeclareExternConstant( | |
| decl->signature->parameters.arguments_variable, | |
| TypeOracle::GetArgumentsType(), "arguments"); | |
| } | |
| torque_builtins_.push_back(builtin); | |
| Visit(body); | |
| } | |
| void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl, | |
| const Signature& signature, Statement* body) { | |
| std::string generated_name = GetGeneratedCallableName( | |
| decl->name, declarations()->GetCurrentSpecializationTypeNamesVector()); | |
| Macro* macro = | |
| declarations()->DeclareMacro(generated_name, signature, decl->op); | |
| CurrentCallableActivator activator(global_context_, macro, decl); | |
| DeclareSignature(signature); | |
| Variable* return_variable = nullptr; | |
| if (!signature.return_type->IsVoidOrNever()) { | |
| return_variable = | |
| DeclareVariable(kReturnValueVariable, signature.return_type, | |
| signature.return_type->IsConstexpr()); | |
| } | |
| PushControlSplit(); | |
| if (body != nullptr) { | |
| Visit(body); | |
| } | |
| auto changed_vars = PopControlSplit(); | |
| if (return_variable) changed_vars.insert(return_variable); | |
| global_context_.AddControlSplitChangedVariables( | |
| decl, declarations()->GetCurrentSpecializationTypeNamesVector(), | |
| changed_vars); | |
| } | |
| void DeclarationVisitor::Visit(ConstDeclaration* decl) { | |
| declarations()->DeclareModuleConstant(decl->name, | |
| declarations()->GetType(decl->type)); | |
| Visit(decl->expression); | |
| } | |
| void DeclarationVisitor::Visit(StandardDeclaration* decl) { | |
| Signature signature = MakeSignature(decl->callable->signature.get()); | |
| Visit(decl->callable, signature, decl->body); | |
| } | |
| void DeclarationVisitor::Visit(GenericDeclaration* decl) { | |
| declarations()->DeclareGeneric(decl->callable->name, CurrentModule(), decl); | |
| } | |
| void DeclarationVisitor::Visit(SpecializationDeclaration* decl) { | |
| if ((decl->body != nullptr) == decl->external) { | |
| std::stringstream stream; | |
| stream << "specialization of " << decl->name | |
| << " must either be marked 'extern' or have a body"; | |
| ReportError(stream.str()); | |
| } | |
| GenericList* generic_list = declarations()->LookupGeneric(decl->name); | |
| // Find the matching generic specialization based on the concrete parameter | |
| // list. | |
| CallableNode* matching_callable = nullptr; | |
| SpecializationKey matching_key; | |
| Signature signature_with_types = MakeSignature(decl->signature.get()); | |
| for (Generic* generic : generic_list->list()) { | |
| SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)}; | |
| CallableNode* callable_candidate = generic->declaration()->callable; | |
| // Abuse the Specialization nodes' scope to temporarily declare the | |
| // specialization aliases for the generic types to compare signatures. This | |
| // scope is never used for anything else, so it's OK to pollute it. | |
| Declarations::CleanNodeScopeActivator specialization_activator( | |
| declarations(), decl); | |
| DeclareSpecializedTypes(key); | |
| Signature generic_signature_with_types = | |
| MakeSignature(generic->declaration()->callable->signature.get()); | |
| if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) { | |
| if (matching_callable != nullptr) { | |
| std::stringstream stream; | |
| stream << "specialization of " << callable_candidate->name | |
| << " is ambigous, it matches more than one generic declaration (" | |
| << *matching_key.first << " and " << *key.first << ")"; | |
| ReportError(stream.str()); | |
| } | |
| matching_callable = callable_candidate; | |
| matching_key = key; | |
| } | |
| } | |
| if (matching_callable == nullptr) { | |
| std::stringstream stream; | |
| stream << "specialization of " << decl->name | |
| << " doesn't match any generic declaration"; | |
| ReportError(stream.str()); | |
| } | |
| // Make sure the declarations of the parameter types for the specialization | |
| // are the ones from the matching generic. | |
| { | |
| Declarations::CleanNodeScopeActivator specialization_activator( | |
| declarations(), decl); | |
| DeclareSpecializedTypes(matching_key); | |
| } | |
| SpecializeGeneric({matching_key, matching_callable, decl->signature.get(), | |
| decl->body, decl->pos}); | |
| } | |
| void DeclarationVisitor::Visit(ReturnStatement* stmt) { | |
| if (stmt->value) { | |
| Visit(*stmt->value); | |
| } | |
| } | |
| Variable* DeclarationVisitor::DeclareVariable(const std::string& name, | |
| const Type* type, bool is_const) { | |
| Variable* result = declarations()->DeclareVariable(name, type, is_const); | |
| if (type->IsStructType()) { | |
| const StructType* struct_type = StructType::cast(type); | |
| for (auto& field : struct_type->fields()) { | |
| std::string field_var_name = name + "." + field.name; | |
| DeclareVariable(field_var_name, field.type, is_const); | |
| } | |
| } | |
| return result; | |
| } | |
| Parameter* DeclarationVisitor::DeclareParameter(const std::string& name, | |
| const Type* type) { | |
| Parameter* result = declarations()->DeclareParameter( | |
| name, GetParameterVariableFromName(name), type); | |
| if (type->IsStructType()) { | |
| const StructType* struct_type = StructType::cast(type); | |
| for (auto& field : struct_type->fields()) { | |
| std::string field_var_name = name + "." + field.name; | |
| DeclareParameter(field_var_name, field.type); | |
| } | |
| } | |
| return result; | |
| } | |
| void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) { | |
| std::string variable_name = stmt->name; | |
| if (!stmt->const_qualified) { | |
| if (!stmt->type) { | |
| ReportError( | |
| "variable declaration is missing type. Only 'const' bindings can " | |
| "infer the type."); | |
| } | |
| const Type* type = declarations()->GetType(*stmt->type); | |
| if (type->IsConstexpr()) { | |
| ReportError( | |
| "cannot declare variable with constexpr type. Use 'const' instead."); | |
| } | |
| DeclareVariable(variable_name, type, stmt->const_qualified); | |
| if (global_context_.verbose()) { | |
| std::cout << "declared variable " << variable_name << " with type " | |
| << *type << "\n"; | |
| } | |
| } | |
| // const qualified variables are required to be initialized properly. | |
| if (stmt->const_qualified && !stmt->initializer) { | |
| std::stringstream stream; | |
| stream << "local constant \"" << variable_name << "\" is not initialized."; | |
| ReportError(stream.str()); | |
| } | |
| if (stmt->initializer) { | |
| Visit(*stmt->initializer); | |
| if (global_context_.verbose()) { | |
| std::cout << "variable has initialization expression at " | |
| << CurrentPositionAsString() << "\n"; | |
| } | |
| } | |
| } | |
| void DeclarationVisitor::Visit(ExternConstDeclaration* decl) { | |
| const Type* type = declarations()->GetType(decl->type); | |
| if (!type->IsConstexpr()) { | |
| std::stringstream stream; | |
| stream << "extern constants must have constexpr type, but found: \"" | |
| << *type << "\"\n"; | |
| ReportError(stream.str()); | |
| } | |
| declarations()->DeclareExternConstant(decl->name, type, decl->literal); | |
| } | |
| void DeclarationVisitor::Visit(StructDeclaration* decl) { | |
| std::vector<NameAndType> fields; | |
| for (auto& field : decl->fields) { | |
| const Type* field_type = declarations()->GetType(field.type); | |
| fields.push_back({field.name, field_type}); | |
| } | |
| declarations()->DeclareStruct(CurrentModule(), decl->name, fields); | |
| } | |
| void DeclarationVisitor::Visit(LogicalOrExpression* expr) { | |
| { | |
| Declarations::NodeScopeActivator scope(declarations(), expr->left); | |
| declarations()->DeclareLabel(kFalseLabelName); | |
| Visit(expr->left); | |
| } | |
| Visit(expr->right); | |
| } | |
| void DeclarationVisitor::Visit(LogicalAndExpression* expr) { | |
| { | |
| Declarations::NodeScopeActivator scope(declarations(), expr->left); | |
| declarations()->DeclareLabel(kTrueLabelName); | |
| Visit(expr->left); | |
| } | |
| Visit(expr->right); | |
| } | |
| void DeclarationVisitor::DeclareExpressionForBranch(Expression* node) { | |
| Declarations::NodeScopeActivator scope(declarations(), node); | |
| // Conditional expressions can either explicitly return a bit | |
| // type, or they can be backed by macros that don't return but | |
| // take a true and false label. By declaring the labels before | |
| // visiting the conditional expression, those label-based | |
| // macro conditionals will be able to find them through normal | |
| // label lookups. | |
| declarations()->DeclareLabel(kTrueLabelName); | |
| declarations()->DeclareLabel(kFalseLabelName); | |
| Visit(node); | |
| } | |
| void DeclarationVisitor::Visit(ConditionalExpression* expr) { | |
| DeclareExpressionForBranch(expr->condition); | |
| PushControlSplit(); | |
| Visit(expr->if_true); | |
| Visit(expr->if_false); | |
| auto changed_vars = PopControlSplit(); | |
| global_context_.AddControlSplitChangedVariables( | |
| expr, declarations()->GetCurrentSpecializationTypeNamesVector(), | |
| changed_vars); | |
| } | |
| void DeclarationVisitor::Visit(IfStatement* stmt) { | |
| if (!stmt->is_constexpr) { | |
| PushControlSplit(); | |
| } | |
| DeclareExpressionForBranch(stmt->condition); | |
| Visit(stmt->if_true); | |
| if (stmt->if_false) Visit(*stmt->if_false); | |
| if (!stmt->is_constexpr) { | |
| auto changed_vars = PopControlSplit(); | |
| global_context_.AddControlSplitChangedVariables( | |
| stmt, declarations()->GetCurrentSpecializationTypeNamesVector(), | |
| changed_vars); | |
| } | |
| } | |
| void DeclarationVisitor::Visit(WhileStatement* stmt) { | |
| Declarations::NodeScopeActivator scope(declarations(), stmt); | |
| DeclareExpressionForBranch(stmt->condition); | |
| PushControlSplit(); | |
| Visit(stmt->body); | |
| auto changed_vars = PopControlSplit(); | |
| global_context_.AddControlSplitChangedVariables( | |
| stmt, declarations()->GetCurrentSpecializationTypeNamesVector(), | |
| changed_vars); | |
| } | |
| void DeclarationVisitor::Visit(ForOfLoopStatement* stmt) { | |
| // Scope for for iteration variable | |
| Declarations::NodeScopeActivator scope(declarations(), stmt); | |
| Visit(stmt->var_declaration); | |
| Visit(stmt->iterable); | |
| if (stmt->begin) Visit(*stmt->begin); | |
| if (stmt->end) Visit(*stmt->end); | |
| PushControlSplit(); | |
| Visit(stmt->body); | |
| auto changed_vars = PopControlSplit(); | |
| global_context_.AddControlSplitChangedVariables( | |
| stmt, declarations()->GetCurrentSpecializationTypeNamesVector(), | |
| changed_vars); | |
| } | |
| void DeclarationVisitor::Visit(ForLoopStatement* stmt) { | |
| Declarations::NodeScopeActivator scope(declarations(), stmt); | |
| if (stmt->var_declaration) Visit(*stmt->var_declaration); | |
| PushControlSplit(); | |
| // Same as DeclareExpressionForBranch, but without the extra scope. | |
| // If no test expression is present we can not use it for the scope. | |
| declarations()->DeclareLabel(kTrueLabelName); | |
| declarations()->DeclareLabel(kFalseLabelName); | |
| if (stmt->test) Visit(*stmt->test); | |
| Visit(stmt->body); | |
| if (stmt->action) Visit(*stmt->action); | |
| auto changed_vars = PopControlSplit(); | |
| global_context_.AddControlSplitChangedVariables( | |
| stmt, declarations()->GetCurrentSpecializationTypeNamesVector(), | |
| changed_vars); | |
| } | |
| void DeclarationVisitor::Visit(TryLabelStatement* stmt) { | |
| // Activate a new scope to declare handler labels, they should not be | |
| // visible outside the label block. | |
| { | |
| Declarations::NodeScopeActivator scope(declarations(), stmt); | |
| // Declare labels | |
| for (LabelBlock* block : stmt->label_blocks) { | |
| CurrentSourcePosition::Scope scope(block->pos); | |
| Label* shared_label = declarations()->DeclareLabel(block->label); | |
| { | |
| Declarations::NodeScopeActivator scope(declarations(), block->body); | |
| if (block->parameters.has_varargs) { | |
| std::stringstream stream; | |
| stream << "cannot use ... for label parameters"; | |
| ReportError(stream.str()); | |
| } | |
| size_t i = 0; | |
| for (auto p : block->parameters.names) { | |
| const Type* type = | |
| declarations()->GetType(block->parameters.types[i]); | |
| if (type->IsConstexpr()) { | |
| ReportError("no constexpr type allowed for label arguments"); | |
| } | |
| shared_label->AddVariable(DeclareVariable(p, type, false)); | |
| ++i; | |
| } | |
| } | |
| if (global_context_.verbose()) { | |
| std::cout << " declaring label " << block->label << "\n"; | |
| } | |
| } | |
| Visit(stmt->try_block); | |
| } | |
| for (LabelBlock* block : stmt->label_blocks) { | |
| Visit(block->body); | |
| } | |
| } | |
| void DeclarationVisitor::GenerateHeader(std::string& file_name) { | |
| std::stringstream new_contents_stream; | |
| new_contents_stream | |
| << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n" | |
| "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n" | |
| "\n" | |
| "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) " | |
| "\\\n"; | |
| for (auto builtin : torque_builtins_) { | |
| int firstParameterIndex = 1; | |
| bool declareParameters = true; | |
| if (builtin->IsStub()) { | |
| new_contents_stream << "TFS(" << builtin->name(); | |
| } else { | |
| new_contents_stream << "TFJ(" << builtin->name(); | |
| if (builtin->IsVarArgsJavaScript()) { | |
| new_contents_stream | |
| << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel"; | |
| declareParameters = false; | |
| } else { | |
| assert(builtin->IsFixedArgsJavaScript()); | |
| // FixedArg javascript builtins need to offer the parameter | |
| // count. | |
| assert(builtin->parameter_names().size() >= 2); | |
| new_contents_stream << ", " << (builtin->parameter_names().size() - 2); | |
| // And the receiver is explicitly declared. | |
| new_contents_stream << ", kReceiver"; | |
| firstParameterIndex = 2; | |
| } | |
| } | |
| if (declareParameters) { | |
| int index = 0; | |
| for (auto parameter : builtin->parameter_names()) { | |
| if (index >= firstParameterIndex) { | |
| new_contents_stream << ", k" << CamelifyString(parameter); | |
| } | |
| index++; | |
| } | |
| } | |
| new_contents_stream << ") \\\n"; | |
| } | |
| new_contents_stream | |
| << "\n" | |
| "#endif // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"; | |
| std::string new_contents(new_contents_stream.str()); | |
| ReplaceFileContentsIfDifferent(file_name, new_contents); | |
| } | |
| void DeclarationVisitor::Visit(IdentifierExpression* expr) { | |
| if (expr->generic_arguments.size() != 0) { | |
| TypeVector specialization_types; | |
| for (auto t : expr->generic_arguments) { | |
| specialization_types.push_back(declarations()->GetType(t)); | |
| } | |
| // Specialize all versions of the generic, since the exact parameter type | |
| // list cannot be resolved until the call's parameter expressions are | |
| // evaluated. This is an overly conservative but simple way to make sure | |
| // that the correct specialization exists. | |
| for (auto generic : declarations()->LookupGeneric(expr->name)->list()) { | |
| CallableNode* callable = generic->declaration()->callable; | |
| if (generic->declaration()->body) { | |
| QueueGenericSpecialization({generic, specialization_types}, callable, | |
| callable->signature.get(), | |
| generic->declaration()->body); | |
| } | |
| } | |
| } | |
| } | |
| void DeclarationVisitor::Visit(CallExpression* expr) { | |
| Visit(&expr->callee); | |
| for (Expression* arg : expr->arguments) Visit(arg); | |
| } | |
| void DeclarationVisitor::Visit(TypeDeclaration* decl) { | |
| std::string generates = decl->generates ? *decl->generates : std::string(""); | |
| const AbstractType* type = declarations()->DeclareAbstractType( | |
| decl->name, generates, {}, decl->extends); | |
| if (decl->constexpr_generates) { | |
| std::string constexpr_name = CONSTEXPR_TYPE_PREFIX + decl->name; | |
| base::Optional<std::string> constexpr_extends; | |
| if (decl->extends) | |
| constexpr_extends = CONSTEXPR_TYPE_PREFIX + *decl->extends; | |
| declarations()->DeclareAbstractType( | |
| constexpr_name, *decl->constexpr_generates, type, constexpr_extends); | |
| } | |
| } | |
| void DeclarationVisitor::MarkLocationModified(Expression* location) { | |
| if (IdentifierExpression* id = IdentifierExpression::cast(location)) { | |
| const Value* value = declarations()->LookupValue(id->name); | |
| if (value->IsVariable()) { | |
| const Variable* variable = Variable::cast(value); | |
| bool was_live = MarkVariableModified(variable); | |
| if (was_live && global_context_.verbose()) { | |
| std::cout << *variable << " was modified in control split at " | |
| << PositionAsString(id->pos) << "\n"; | |
| } | |
| } | |
| } | |
| } | |
| bool DeclarationVisitor::MarkVariableModified(const Variable* variable) { | |
| auto e = live_and_changed_variables_.rend(); | |
| auto c = live_and_changed_variables_.rbegin(); | |
| bool was_live_in_preceeding_split = false; | |
| while (c != e) { | |
| if (c->live.find(variable) != c->live.end()) { | |
| c->changed.insert(variable); | |
| was_live_in_preceeding_split = true; | |
| } | |
| c++; | |
| } | |
| return was_live_in_preceeding_split; | |
| } | |
| void DeclarationVisitor::DeclareSignature(const Signature& signature) { | |
| auto type_iterator = signature.parameter_types.types.begin(); | |
| for (auto name : signature.parameter_names) { | |
| const Type* t(*type_iterator++); | |
| if (name.size() != 0) { | |
| DeclareParameter(name, t); | |
| } | |
| } | |
| for (auto& label : signature.labels) { | |
| auto label_params = label.types; | |
| Label* new_label = declarations()->DeclareLabel(label.name); | |
| size_t i = 0; | |
| for (auto var_type : label_params) { | |
| if (var_type->IsConstexpr()) { | |
| ReportError("no constexpr type allowed for label arguments"); | |
| } | |
| std::string var_name = label.name + std::to_string(i++); | |
| new_label->AddVariable(DeclareVariable(var_name, var_type, false)); | |
| } | |
| } | |
| } | |
| void DeclarationVisitor::DeclareSpecializedTypes(const SpecializationKey& key) { | |
| size_t i = 0; | |
| Generic* generic = key.first; | |
| const std::size_t generic_parameter_count = | |
| generic->declaration()->generic_parameters.size(); | |
| if (generic_parameter_count != key.second.size()) { | |
| std::stringstream stream; | |
| stream << "Wrong generic argument count for specialization of \"" | |
| << generic->name() << "\", expected: " << generic_parameter_count | |
| << ", actual: " << key.second.size(); | |
| ReportError(stream.str()); | |
| } | |
| for (auto type : key.second) { | |
| std::string generic_type_name = | |
| generic->declaration()->generic_parameters[i++]; | |
| declarations()->DeclareType(generic_type_name, type); | |
| } | |
| } | |
| void DeclarationVisitor::Specialize(const SpecializationKey& key, | |
| CallableNode* callable, | |
| const CallableNodeSignature* signature, | |
| Statement* body) { | |
| Generic* generic = key.first; | |
| // TODO(tebbi): The error should point to the source position where the | |
| // instantiation was requested. | |
| CurrentSourcePosition::Scope pos_scope(generic->declaration()->pos); | |
| size_t generic_parameter_count = | |
| generic->declaration()->generic_parameters.size(); | |
| if (generic_parameter_count != key.second.size()) { | |
| std::stringstream stream; | |
| stream << "number of template parameters (" | |
| << std::to_string(key.second.size()) | |
| << ") to intantiation of generic " << callable->name | |
| << " doesnt match the generic's declaration (" | |
| << std::to_string(generic_parameter_count) << ")"; | |
| ReportError(stream.str()); | |
| } | |
| Signature type_signature; | |
| { | |
| // Manually activate the specialized generic's scope when declaring the | |
| // generic parameter specializations. | |
| Declarations::GenericScopeActivator namespace_scope(declarations(), key); | |
| DeclareSpecializedTypes(key); | |
| type_signature = MakeSignature(signature); | |
| } | |
| Visit(callable, type_signature, body); | |
| } | |
| } // namespace torque | |
| } // namespace internal | |
| } // namespace v8 |