This machine mirrors various open-source projects.
20 Gbit/s uplink.
If there are any issues or you want another project mirrored, please contact
mirror-service -=AT=- netcologne DOT de !
00001 //===-- CheckSubroutine.cpp ----------------------------------- -*- C++ -*-===// 00002 // 00003 // This file is distributed under the MIT license. See LICENSE.txt for details. 00004 // 00005 // Copyright (C) 2008-2009, Stephen Wilson 00006 // 00007 //===----------------------------------------------------------------------===// 00008 00009 //===----------------------------------------------------------------------===// 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "Scope.h" 00016 #include "Stencil.h" 00017 #include "TypeCheck.h" 00018 #include "comma/ast/AstRewriter.h" 00019 #include "comma/ast/Expr.h" 00020 #include "comma/ast/Decl.h" 00021 #include "comma/ast/Stmt.h" 00022 #include "comma/ast/TypeRef.h" 00023 #include "comma/basic/PrimitiveOps.h" 00024 00025 using namespace comma; 00026 using llvm::dyn_cast; 00027 using llvm::dyn_cast_or_null; 00028 using llvm::cast; 00029 using llvm::isa; 00030 00031 void TypeCheck::beginFunctionDeclaration(IdentifierInfo *name, Location loc) 00032 { 00033 routineStencil.init(name, loc, SRDeclStencil::FUNCTION_Stencil); 00034 } 00035 00036 void TypeCheck::beginProcedureDeclaration(IdentifierInfo *name, Location loc) 00037 { 00038 routineStencil.init(name, loc, SRDeclStencil::PROCEDURE_Stencil); 00039 } 00040 00041 void TypeCheck::acceptSubroutineParameter(IdentifierInfo *formal, Location loc, 00042 Node declNode, PM::ParameterMode mode) 00043 { 00044 TypeDecl *tyDecl = ensureCompleteTypeDecl(declNode); 00045 00046 if (!tyDecl) { 00047 routineStencil.markInvalid(); 00048 return; 00049 } 00050 00051 // If we are building a function declaration, ensure that the parameter is 00052 // of mode "in". 00053 if (routineStencil.denotesFunction() && 00054 (mode != PM::MODE_IN) && (mode != PM::MODE_DEFAULT)) { 00055 report(loc, diag::OUT_MODE_IN_FUNCTION); 00056 routineStencil.markInvalid(); 00057 return; 00058 } 00059 00060 // Check that this parameters name does not conflict with any previous 00061 // parameters. 00062 typedef SRDeclStencil::param_iterator iterator; 00063 for (iterator I = routineStencil.begin_params(); 00064 I != routineStencil.end_params(); ++I) { 00065 ParamValueDecl *previousParam = *I; 00066 if (previousParam->getIdInfo() == formal) { 00067 report(loc, diag::DUPLICATE_FORMAL_PARAM) << formal; 00068 routineStencil.markInvalid(); 00069 return; 00070 } 00071 } 00072 00073 // Check that the parameter name does not conflict with the subroutine 00074 // declaration itself. 00075 if (formal == routineStencil.getIdInfo()) { 00076 report(loc, diag::CONFLICTING_DECLARATION) 00077 << formal << getSourceLoc(routineStencil.getLocation()); 00078 routineStencil.markInvalid(); 00079 return; 00080 } 00081 00082 Type *paramTy = tyDecl->getType(); 00083 ParamValueDecl *paramDecl = new ParamValueDecl(formal, paramTy, mode, loc); 00084 routineStencil.addParameter(paramDecl); 00085 } 00086 00087 void TypeCheck::acceptFunctionReturnType(Node typeNode) 00088 { 00089 assert(routineStencil.denotesFunction() && 00090 "Inconsitent state for function returns!"); 00091 00092 if (typeNode.isNull()) { 00093 routineStencil.markInvalid(); 00094 return; 00095 } 00096 00097 TypeDecl *returnDecl = ensureCompleteTypeDecl(typeNode); 00098 if (!returnDecl) { 00099 routineStencil.markInvalid(); 00100 return; 00101 } 00102 00103 routineStencil.setReturnType(returnDecl); 00104 } 00105 00106 Node TypeCheck::endSubroutineDeclaration(bool definitionFollows) 00107 { 00108 IdentifierInfo *name = routineStencil.getIdInfo(); 00109 Location location = routineStencil.getLocation(); 00110 SRDeclStencil::ParamVec ¶ms = routineStencil.getParams(); 00111 00112 // Ensure the stencil is reset once this method returns. 00113 ASTStencilReseter reseter(routineStencil); 00114 00115 // If the subroutine stencil has not checked out thus far, do not construct 00116 // a subroutine declaration for it. 00117 if (routineStencil.isInvalid()) 00118 return getInvalidNode(); 00119 00120 // Ensure that if this function names a binary or unary operator it has the 00121 // required arity. 00122 if (routineStencil.denotesFunction()) { 00123 bool namesUnary = PO::denotesUnaryOp(name); 00124 bool namesBinary = PO::denotesBinaryOp(name); 00125 00126 if (namesUnary || namesBinary) { 00127 bool allOK = true; 00128 unsigned numParams = params.size(); 00129 00130 if (namesUnary && namesBinary) 00131 allOK = numParams == 1 || numParams == 2; 00132 else if (namesUnary) 00133 allOK = numParams == 1; 00134 else if (namesBinary) 00135 allOK = numParams == 2; 00136 00137 if (!allOK) { 00138 report(location, diag::OPERATOR_ARITY_MISMATCH) << name; 00139 return getInvalidNode(); 00140 } 00141 } 00142 } 00143 00144 SubroutineDecl *routineDecl = 0; 00145 DeclRegion *region = currentDeclarativeRegion(); 00146 if (routineStencil.denotesFunction()) { 00147 Type *returnType = routineStencil.getReturnType()->getType(); 00148 routineDecl = new FunctionDecl(resource, name, location, 00149 params.data(), params.size(), 00150 returnType, region); 00151 } 00152 else 00153 routineDecl = new ProcedureDecl(resource, name, location, 00154 params.data(), params.size(), 00155 region); 00156 00157 // Ensure this new declaration does not conflict with any other currently in 00158 // scope. 00159 if (Decl *conflict = scope.addDirectDecl(routineDecl)) { 00160 // If the conflict is a subroutine, check if the current declaration can 00161 // serve as a completion. 00162 SubroutineDecl *fwdDecl = dyn_cast<SubroutineDecl>(conflict); 00163 if (fwdDecl && definitionFollows && 00164 compatibleSubroutineDecls(fwdDecl, routineDecl)) { 00165 00166 // If the conflict does not already have a completion link in this 00167 // routine. 00168 if (fwdDecl->hasDefiningDeclaration()) { 00169 report(location, diag::SUBROUTINE_REDECLARATION) 00170 << fwdDecl->getIdInfo() 00171 << getSourceLoc(fwdDecl->getLocation()); 00172 return getInvalidNode(); 00173 } 00174 00175 fwdDecl->setDefiningDeclaration(routineDecl); 00176 00177 // If the forward declaration is present in the current region we do 00178 // not add this node to the region. This ensures that only one 00179 // subroutine declaration with a given profile is listed. 00180 if (!fwdDecl->isDeclaredIn(region)) 00181 region->addDecl(routineDecl); 00182 } 00183 else { 00184 report(location, diag::CONFLICTING_DECLARATION) 00185 << name << getSourceLoc(conflict->getLocation()); 00186 return getInvalidNode(); 00187 } 00188 } 00189 else { 00190 // The subroutine does not conflict or serve as a completion. Add it to 00191 // the current declarative region. 00192 region->addDecl(routineDecl); 00193 } 00194 00195 // Since the declaration has been added permanently to the environment, 00196 // ensure the returned Node does not reclaim the decl. 00197 Node routine = getNode(routineDecl); 00198 routine.release(); 00199 return routine; 00200 } 00201 00202 Node TypeCheck::beginSubroutineDefinition(Node declarationNode) 00203 { 00204 declarationNode.release(); 00205 SubroutineDecl *srDecl = cast_node<SubroutineDecl>(declarationNode); 00206 00207 // Enter a scope for the subroutine definition. Add the subroutine itself 00208 // as an element of the new scope and add the formal parameters. This 00209 // should never result in conflicts. 00210 scope.push(SUBROUTINE_SCOPE); 00211 scope.addDirectDeclNoConflicts(srDecl); 00212 typedef SubroutineDecl::param_iterator param_iterator; 00213 for (param_iterator I = srDecl->begin_params(), E = srDecl->end_params(); 00214 I != E; ++I) 00215 scope.addDirectDeclNoConflicts(*I); 00216 00217 // Allocate a BlockStmt for the subroutines body and make this block the 00218 // current declarative region. 00219 assert(!srDecl->hasBody() && "Current subroutine already has a body!"); 00220 00221 BlockStmt *block = new BlockStmt(0, srDecl, srDecl->getIdInfo()); 00222 srDecl->setBody(block); 00223 pushDeclarativeRegion(block); 00224 Node blockNode = getNode(block); 00225 blockNode.release(); 00226 return blockNode; 00227 } 00228 00229 void TypeCheck::endSubroutineBody(Node contextNode) 00230 { 00231 // The parser is finished with the subroutine body. Pop the scope and set 00232 // the current declarative region to the containing subroutine declaration. 00233 popDeclarativeRegion(); 00234 scope.pop(); 00235 00236 // FIXME: This burns cycles in the common case when a subroutine does not 00237 // have handlers. Push a new scope and add the subroutine and formal 00238 // parameters so that they are visible to any handlers. 00239 // 00240 // What does this code solve? Consider: 00241 // 00242 // procedure P (X : T) is 00243 // X : T; 00244 // begin 00245 // null; 00246 // exception 00247 // when others => Foo(X); 00248 // end P; 00249 // 00250 // We cannot push two scopes for the subroutine (one for the subroutine and 00251 // the parameters, another for the body and its local declarations) since 00252 // then the local declaration of X will be interpreted as shadowing the 00253 // formal parameter X instead of conflicting. However, the the handler must 00254 // see the formal parameter (and subroutine declaration) but not any 00255 // bindings local to the body proper. 00256 // 00257 // The solution to this inefficiency would be to teach beginHandlerStmt to 00258 // inspect the current context and push/populate a new scope if needed, or 00259 // add a new pair of ParseClient callbacks to delimit all handlers and do 00260 // the work there. 00261 SubroutineDecl *srDecl = cast<SubroutineDecl>(currentDeclarativeRegion()); 00262 scope.push(SUBROUTINE_SCOPE); 00263 scope.addDirectDeclNoConflicts(srDecl); 00264 typedef SubroutineDecl::param_iterator param_iterator; 00265 for (param_iterator I = srDecl->begin_params(), E = srDecl->end_params(); 00266 I != E; ++I) 00267 scope.addDirectDeclNoConflicts(*I); 00268 } 00269 00270 void TypeCheck::endSubroutineDefinition() 00271 { 00272 assert(scope.getKind() == SUBROUTINE_SCOPE); 00273 00274 // Pop the declarative region and scope corresponding to the current subroutine. 00275 popDeclarativeRegion(); 00276 scope.pop(); 00277 } 00278 00282 bool TypeCheck::checkFunctionParameter(ParamValueDecl *param) 00283 { 00284 PM::ParameterMode mode = param->getParameterMode(); 00285 if (mode == PM::MODE_IN) 00286 return true; 00287 report(param->getLocation(), diag::OUT_MODE_IN_FUNCTION); 00288 return false; 00289 } 00290 00291 bool 00292 TypeCheck::compatibleSubroutineDecls(SubroutineDecl *X, SubroutineDecl *Y) 00293 { 00294 if (X->getIdInfo() != Y->getIdInfo()) 00295 return false; 00296 00297 if (X->getType() != Y->getType()) 00298 return false; 00299 00300 if (!X->paramModesMatch(Y)) 00301 return false; 00302 00303 if (!X->keywordsMatch(Y)) 00304 return false; 00305 00306 return true; 00307 }