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 }