Type * NameResolver::resolveBase(TypeSpecifier &spec) { switch (spec.resolver()) { // These are the most common cases - either a primitive type or a signature // containing primitive types. In some cases we could have already resolved // the type even earlier, for example, the parser does this for certain = // builtin tags. case TOK_VOID: return cc_.types()->getVoid(); case TOK_IMPLICIT_INT: return cc_.types()->getImplicitInt(); case TOK_INT: return cc_.types()->getPrimitive(PrimitiveType::Int32); case TOK_BOOL: return cc_.types()->getPrimitive(PrimitiveType::Bool); case TOK_CHAR: return cc_.types()->getPrimitive(PrimitiveType::Char); case TOK_FLOAT: return cc_.types()->getPrimitive(PrimitiveType::Float); case TOK_DEFINED: return spec.getResolvedBase(); case TOK_FUNCTION: { FunctionSignature *sig = spec.signature(); if (!sig->isResolved()) return nullptr; return FunctionType::New(sig); } case TOK_LABEL: case TOK_NAME: { NameProxy *proxy = spec.proxy(); Symbol *sym = proxy->sym(); if (!sym) { // This can happen if we use a type before it's been defined. We wait // until type resolution to try again. return nullptr; } TypeSymbol *ts = sym->asType(); if (!ts) { cc_.report(proxy->loc(), rmsg::not_a_type) << sym->name(); return nullptr; } // If we resolved a TypeSymbol, we must have allocated a Type object // (even if it's incomplete). assert(ts->type()); return ts->type(); } default: return nullptr; } }
bool NameResolver::canDefineMethodmap(MethodmapDecl *methodmap) { // Methodmaps are only allowed in the global scope. They have very odd // semantics (by design, as part of the transitional syntax): they // create an enum, or they extend an existing enum, in any declaration // order. // // If the symbol already exists, it must be a direct enum type. We do // not accept typedefs. assert(getOrCreateScope() == globals_); Symbol *prev = globals_->lookup(methodmap->name()); if (!prev) return true; TypeSymbol *sym = prev->asType(); if (!sym) { cc_.report(methodmap->loc(), rmsg::methodmap_on_non_type) << sym->name(); return false; } // Builtin types do not have AST nodes. if (!sym->node()) { cc_.report(methodmap->loc(), rmsg::methodmap_on_non_enum) << sym->name(); return false; } EnumStatement *stmt = sym->node()->asEnumStatement(); if (!stmt) { if (sym->node()->asMethodmapDecl()) { // We had something like: // methodmap X {} // methodmap X {} // // We can give a slightly more specific error for this case. cc_.report(methodmap->loc(), rmsg::methodmap_already_defined) << methodmap->name(); } else { cc_.report(methodmap->loc(), rmsg::methodmap_on_non_enum) << sym->name(); } return false; } // Mark that our enum statement has a methodmap. stmt->setMethodmap(methodmap); // Point the layout at the enum type. methodmap->setSymbol(sym); // Return false - symbol is already defined. return false; }
void SemanticAnalysis::visitNameProxy(NameProxy *proxy) { Symbol *binding = proxy->sym(); switch (binding->kind()) { case Symbol::kType: cc_.report(proxy->loc(), rmsg::cannot_use_type_as_value) << binding->asType()->type(); break; case Symbol::kConstant: { ConstantSymbol *sym = binding->toConstant(); proxy->setOutput(sym->type(), VK::rvalue); break; } case Symbol::kFunction: { FunctionSymbol *sym = binding->toFunction(); FunctionStatement *decl = sym->impl(); if (!decl) { cc_.report(proxy->loc(), rmsg::function_has_no_impl) << sym->name(); break; } if (!decl->type()) decl->setType(FunctionType::New(decl->signature())); // Function symbols are clvalues, since they are named. // :TODO: proxy->setOutput(decl->type(), VK::lvalue); break; } default: assert(false); } }