Add some scaffolding for parsing affine maps:
- parsing affine map identifiers
- place-holder classes for AffineMap
- module contains a list of affine maps (defined at the top level).

PiperOrigin-RevId: 202336919
diff --git a/lib/Parser/Lexer.cpp b/lib/Parser/Lexer.cpp
index 7f53886..209f988 100644
--- a/lib/Parser/Lexer.cpp
+++ b/lib/Parser/Lexer.cpp
@@ -25,6 +25,12 @@
 using llvm::SMLoc;
 using llvm::SourceMgr;
 
+// Returns true if 'c' is an allowable puncuation character: [$._-]
+// Returns false otherwise.
+static bool isPunct(char c) {
+  return c == '$' || c == '.' || c == '_' || c == '-';
+}
+
 Lexer::Lexer(llvm::SourceMgr &sourceMgr,
              const SMDiagnosticHandlerTy &errorReporter)
     : sourceMgr(sourceMgr), errorReporter(errorReporter) {
@@ -92,6 +98,7 @@
 
   case ';': return lexComment();
   case '@': return lexAtIdentifier(tokStart);
+  case '#': return lexAffineMapId(tokStart);
 
   case '0': case '1': case '2': case '3': case '4':
   case '5': case '6': case '7': case '8': case '9':
@@ -174,6 +181,30 @@
   return formToken(Token::at_identifier, tokStart);
 }
 
+/// Lex an '#foo' identifier.
+///
+///   affine-map-id ::= `#` suffix-id
+///   suffix-id ::= digit+ | (letter|id-punct) (letter|id-punct|digit)*
+///
+// TODO(andydavis) Consider moving suffix-id parsing to a shared function
+// so it can be re-used to parse %suffix-id.
+Token Lexer::lexAffineMapId(const char *tokStart) {
+  // Parse suffix-id.
+  if (isdigit(*curPtr)) {
+    // If suffix-id starts with a digit, the rest must be digits.
+    while (isdigit(*curPtr)) {
+      ++curPtr;
+    }
+  } else if (isalpha(*curPtr) || isPunct(*curPtr)) {
+    do  {
+      ++curPtr;
+    } while (isalpha(*curPtr) || isdigit(*curPtr) || isPunct(*curPtr));
+  } else {
+    return emitError(curPtr-1, "invalid affine map id");
+  }
+  return formToken(Token::affine_map_id, tokStart);
+}
+
 /// Lex an integer literal.
 ///
 ///   integer-literal ::= digit+ | `0x` hex_digit+
diff --git a/lib/Parser/Lexer.h b/lib/Parser/Lexer.h
index 139dfa6..0301a35 100644
--- a/lib/Parser/Lexer.h
+++ b/lib/Parser/Lexer.h
@@ -60,6 +60,7 @@
   Token lexComment();
   Token lexBareIdentifierOrKeyword(const char *tokStart);
   Token lexAtIdentifier(const char *tokStart);
+  Token lexAffineMapId(const char *tokStart);
   Token lexNumber(const char *tokStart);
 };
 
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index 5a79f1e..0d24972 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -21,6 +21,7 @@
 
 #include "mlir/Parser.h"
 #include "Lexer.h"
+#include "mlir/IR/AffineMap.h"
 #include "mlir/IR/Module.h"
 #include "mlir/IR/CFGFunction.h"
 #include "mlir/IR/Types.h"
@@ -68,6 +69,11 @@
   // This is the result module we are parsing into.
   std::unique_ptr<Module> module;
 
+  // A map from affine map identifier to AffineMap.
+  // TODO(andydavis) Remove use of unique_ptr when AffineMaps are bump pointer
+  // allocated.
+  llvm::StringMap<std::unique_ptr<AffineMap>> affineMaps;
+
 private:
   // Helper methods.
 
@@ -121,6 +127,9 @@
   Type *parseType();
   ParseResult parseTypeList(SmallVectorImpl<Type*> &elements);
 
+  // Polyhedral structures
+  ParseResult parseAffineMapDef();
+
   // Functions.
   ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
   ParseResult parseExtFunc();
@@ -461,6 +470,33 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Polyhedral structures.
+//===----------------------------------------------------------------------===//
+
+/// Affine map declaration.
+///
+///  affine-map-def ::= affine-map-id `=` affine-map-inline
+///  affine-map-inline ::= dim-and-symbol-id-lists `->` multi-dim-affine-expr
+///                        ( `size` `(` dim-size (`,` dim-size)* `)` )?
+///  dim-size ::= affine-expr | `min` `(` affine-expr ( `,` affine-expr)+ `)`
+///
+ParseResult Parser::parseAffineMapDef() {
+  assert(curToken.is(Token::affine_map_id));
+
+  StringRef affineMapId = curToken.getSpelling().drop_front();
+  // Check that 'affineMapId' is unique.
+  // TODO(andydavis) Add a unit test for this case.
+  if (affineMaps.count(affineMapId) > 0)
+    return emitError("encountered non-unique affine map id");
+
+  consumeToken(Token::affine_map_id);
+
+  // TODO(andydavis,bondhugula) Parse affine map definition.
+  affineMaps[affineMapId].reset(new AffineMap(1, 0));
+  return ParseSuccess;
+}
+
+//===----------------------------------------------------------------------===//
 // Functions
 //===----------------------------------------------------------------------===//
 
@@ -701,6 +737,9 @@
     case Token::kw_cfgfunc:
       if (parseCFGFunc()) return nullptr;
       break;
+    case Token::affine_map_id:
+      if (parseAffineMapDef()) return nullptr;
+      break;
 
     // TODO: mlfunc, affine entity declarations, etc.
     }
diff --git a/lib/Parser/Token.h b/lib/Parser/Token.h
index dde0722..8a654a1 100644
--- a/lib/Parser/Token.h
+++ b/lib/Parser/Token.h
@@ -34,6 +34,7 @@
     // Identifiers.
     bare_identifier,    // foo
     at_identifier,      // @foo
+    affine_map_id,      // #foo
     // TODO: @@foo, etc.
 
     integer,            // 42