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 }