00001 
00002 
00003 
00004 
00005 
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     
00052     
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     
00061     
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     
00074     
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     
00113     ASTStencilReseter reseter(routineStencil);
00114 
00115     
00116     
00117     if (routineStencil.isInvalid())
00118         return getInvalidNode();
00119 
00120     
00121     
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     
00158     
00159     if (Decl *conflict = scope.addDirectDecl(routineDecl)) {
00160         
00161         
00162         SubroutineDecl *fwdDecl = dyn_cast<SubroutineDecl>(conflict);
00163         if (fwdDecl && definitionFollows &&
00164             compatibleSubroutineDecls(fwdDecl, routineDecl)) {
00165 
00166             
00167             
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             
00178             
00179             
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         
00191         
00192         region->addDecl(routineDecl);
00193     }
00194 
00195     
00196     
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     
00208     
00209     
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     
00218     
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     
00232     
00233     popDeclarativeRegion();
00234     scope.pop();
00235 
00236     
00237     
00238     
00239     
00240     
00241     
00242     
00243     
00244     
00245     
00246     
00247     
00248     
00249     
00250     
00251     
00252     
00253     
00254     
00255     
00256     
00257     
00258     
00259     
00260     
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     
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 }