00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #include "TypeCheck.h"
00010 #include "comma/ast/AttribDecl.h"
00011 #include "comma/ast/AttribExpr.h"
00012 #include "comma/ast/RangeAttrib.h"
00013 #include "comma/ast/TypeRef.h"
00014 
00015 using namespace comma;
00016 using llvm::dyn_cast_or_null;
00017 using llvm::dyn_cast;
00018 using llvm::cast;
00019 using llvm::isa;
00020 
00021 namespace {
00022 
00024 class AttributeChecker {
00025 
00026 public:
00027     AttributeChecker(TypeCheck &TC, attrib::AttributeID ID)
00028         : TC(TC),
00029           resource(TC.getAstResource()),
00030           diagnostic(TC.getDiagnostic()),
00031           ID(ID) { }
00032 
00033     Ast *checkAttribute(Ast *prefix, Location loc);
00034 
00035 private:
00036     TypeCheck &TC;
00037     AstResource &resource;
00038     Diagnostic &diagnostic;
00039     attrib::AttributeID ID;
00040 
00042     const char *attributeName() {
00043         return attrib::getAttributeString(ID);
00044     }
00045 
00056     AttribExpr *checkBound(Ast *prefix, Location loc);
00057 
00059     ScalarBoundAE *checkScalarBound(TypeRef *prefix, Location loc);
00060 
00062     ArrayBoundAE *checkArrayBound(Expr *prefix, Location loc);
00063 
00065     RangeAttrib *checkRange(Ast *prefix, Location loc);
00066 
00070     SubroutineRef *checkPosVal(Ast *prefix, Location loc);
00071 
00072     SourceLocation getSourceLoc(Location loc) const {
00073         return resource.getTextProvider().getSourceLocation(loc);
00074     }
00075 
00076     DiagnosticStream &report(Location loc, diag::Kind kind) {
00077         return diagnostic.report(getSourceLoc(loc), kind);
00078     }
00079 };
00080 
00081 Ast *AttributeChecker::checkAttribute(Ast *prefix, Location loc)
00082 {
00083     Ast *result = 0;
00084 
00085     switch (ID) {
00086     default:
00087         assert(false && "Unknown attribute!");
00088         break;
00089 
00090     case attrib::First:
00091     case attrib::Last:
00092         result = checkBound(prefix, loc);
00093         break;
00094 
00095     case attrib::Pos:
00096     case attrib::Val:
00097         result = checkPosVal(prefix, loc);
00098         break;
00099 
00100     case attrib::Range:
00101         result = checkRange(prefix, loc);
00102         break;
00103     };
00104     return result;
00105 }
00106 
00107 AttribExpr *AttributeChecker::checkBound(Ast *prefix, Location loc)
00108 {
00109     AttribExpr *result = 0;
00110 
00111     if (TypeRef *ref = dyn_cast<TypeRef>(prefix))
00112         result = checkScalarBound(ref, loc);
00113     else if (Expr *expr = dyn_cast<Expr>(prefix))
00114         result = checkArrayBound(expr, loc);
00115     else {
00116         
00117         
00118         report(loc, diag::INVALID_ATTRIB_PREFIX) << attributeName();
00119     }
00120     return result;
00121 }
00122 
00123 ScalarBoundAE *AttributeChecker::checkScalarBound(TypeRef *prefix, Location loc)
00124 {
00125     
00126     
00127 
00128     
00129     TypeDecl *decl = prefix->getTypeDecl();
00130     DiscreteType *prefixTy = dyn_cast<DiscreteType>(decl->getType());
00131 
00132     if (!decl) {
00133         report(loc, diag::ATTRIB_OF_NON_SCALAR) << attributeName();
00134         return 0;
00135     }
00136 
00137     if (ID == attrib::First)
00138         return new FirstAE(prefixTy, loc);
00139     else
00140         return new LastAE(prefixTy, loc);
00141 }
00142 
00143 ArrayBoundAE *AttributeChecker::checkArrayBound(Expr *prefix, Location loc)
00144 {
00145     ArrayType *arrTy = dyn_cast<ArrayType>(prefix->getType());
00146 
00147     if (!arrTy) {
00148         report(loc, diag::ATTRIB_OF_NON_ARRAY) << attributeName();
00149         return 0;
00150     }
00151 
00152     if (ID == attrib::First)
00153         return new FirstArrayAE(prefix, loc);
00154     else
00155         return new LastArrayAE(prefix, loc);
00156 }
00157 
00158 RangeAttrib *AttributeChecker::checkRange(Ast *prefix, Location loc)
00159 {
00160     
00161     
00162     if (Expr *expr = dyn_cast<Expr>(prefix)) {
00163         if (!(expr->hasResolvedType() ||
00164               TC.checkExprInContext(expr, Type::CLASS_Array)))
00165             return 0;
00166 
00167         if (!isa<ArrayType>(expr->getType())) {
00168             Type *type = expr->getType();
00169             if ((type = TC.getCoveringDereference(type, Type::CLASS_Array)))
00170                 expr = TC.implicitlyDereference(expr, type);
00171             else {
00172                 report(loc, diag::ATTRIB_OF_NON_ARRAY) << attributeName();
00173                 return 0;
00174             }
00175         }
00176         return new ArrayRangeAttrib(expr, loc);
00177     }
00178 
00179     
00180     TypeRef *ref = dyn_cast<TypeRef>(prefix);
00181 
00182     if (!ref || !ref->referencesTypeDecl()) {
00183         report(loc, diag::INVALID_ATTRIB_PREFIX) << attributeName();
00184         return 0;
00185     }
00186 
00187     TypeDecl *tyDecl = ref->getTypeDecl();
00188     DiscreteType *prefixTy = dyn_cast<DiscreteType>(tyDecl->getType());
00189 
00190     if (!prefixTy) {
00191         report(loc, diag::INVALID_ATTRIB_PREFIX) << attributeName();
00192         return 0;
00193     }
00194 
00195     return new ScalarRangeAttrib(prefixTy, loc);
00196 }
00197 
00198 SubroutineRef *AttributeChecker::checkPosVal(Ast *prefix, Location loc)
00199 {
00200     assert((ID == attrib::Pos || ID == attrib::Val) &&
00201            "Unexpected attribute ID!");
00202 
00203     TypeRef *ref = dyn_cast<TypeRef>(prefix);
00204 
00205     if (!(ref && ref->referencesTypeDecl())) {
00206         report(prefix->getLocation(), diag::EXPECTED_DISCRETE_SUBTYPE);
00207         return 0;
00208     }
00209 
00210     TypeDecl *tyDecl = ref->getTypeDecl();
00211     FunctionAttribDecl *attrib;
00212 
00213     if (IntegerDecl *intDecl = dyn_cast<IntegerDecl>(tyDecl))
00214         attrib = intDecl->getAttribute(ID);
00215     else if (EnumerationDecl *enumDecl = dyn_cast<EnumerationDecl>(tyDecl))
00216         attrib = enumDecl->getAttribute(ID);
00217 
00218     if (!attrib) {
00219         report(prefix->getLocation(), diag::EXPECTED_DISCRETE_SUBTYPE);
00220         return 0;
00221     }
00222 
00223     return new SubroutineRef(loc, attrib);
00224 }
00225 
00226 } 
00227 
00228 
00229 Ast *TypeCheck::checkAttribute(attrib::AttributeID ID,
00230                                Ast *prefix, Location loc)
00231 {
00232     AttributeChecker AC(*this, ID);
00233     return AC.checkAttribute(prefix, loc);
00234 }