Add basic lexing and parsing support for SSA operands and definitions.  This
isn't actually constructing IR objects yet, it is eating the tokens and
discarding them.

PiperOrigin-RevId: 203616265
diff --git a/lib/Parser/Lexer.cpp b/lib/Parser/Lexer.cpp
index 3872565..8e94560 100644
--- a/lib/Parser/Lexer.cpp
+++ b/lib/Parser/Lexer.cpp
@@ -103,7 +103,10 @@
 
   case ';': return lexComment();
   case '@': return lexAtIdentifier(tokStart);
-  case '#': return lexAffineMapId(tokStart);
+  case '#':
+    LLVM_FALLTHROUGH;
+  case '%':
+    return lexPrefixedIdentifier(tokStart);
   case '"': return lexString(tokStart);
 
   case '0': case '1': case '2': case '3': case '4':
@@ -182,14 +185,28 @@
   return formToken(Token::at_identifier, tokStart);
 }
 
-/// Lex an '#foo' identifier.
+/// Lex an identifier that starts with a prefix followed by suffix-id.
 ///
 ///   affine-map-id ::= `#` suffix-id
+///   ssa-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) {
+Token Lexer::lexPrefixedIdentifier(const char *tokStart) {
+  Token::Kind kind;
+  StringRef errorKind;
+  switch (*tokStart) {
+  case '#':
+    kind = Token::hash_identifier;
+    errorKind = "invalid affine map name";
+    break;
+  case '%':
+    kind = Token::percent_identifier;
+    errorKind = "invalid SSA name";
+    break;
+  default:
+    llvm_unreachable("invalid caller");
+  }
+
   // Parse suffix-id.
   if (isdigit(*curPtr)) {
     // If suffix-id starts with a digit, the rest must be digits.
@@ -201,9 +218,10 @@
       ++curPtr;
     } while (isalpha(*curPtr) || isdigit(*curPtr) || isPunct(*curPtr));
   } else {
-    return emitError(curPtr-1, "invalid affine map id");
+    return emitError(curPtr - 1, errorKind);
   }
-  return formToken(Token::affine_map_identifier, tokStart);
+
+  return formToken(kind, tokStart);
 }
 
 /// Lex an integer literal.
diff --git a/lib/Parser/Lexer.h b/lib/Parser/Lexer.h
index 4bbd9b7..730bbc9 100644
--- a/lib/Parser/Lexer.h
+++ b/lib/Parser/Lexer.h
@@ -60,7 +60,7 @@
   Token lexComment();
   Token lexBareIdentifierOrKeyword(const char *tokStart);
   Token lexAtIdentifier(const char *tokStart);
-  Token lexAffineMapId(const char *tokStart);
+  Token lexPrefixedIdentifier(const char *tokStart);
   Token lexNumber(const char *tokStart);
   Token lexString(const char *tokStart);
 };
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index f9849a7..94d1468 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -188,17 +188,23 @@
                                         const AffineMapParserState &state,
                                         AffineExpr *&result);
 
+  // SSA
+  ParseResult parseSSAUse();
+  ParseResult parseOptionalSSAUseList(Token::Kind endToken);
+  ParseResult parseSSAUseAndType();
+  ParseResult parseOptionalSSAUseAndTypeList(Token::Kind endToken);
+
   // Functions.
   ParseResult parseFunctionSignature(StringRef &name, FunctionType *&type);
   ParseResult parseExtFunc();
   ParseResult parseCFGFunc();
-  ParseResult parseMLFunc();
   ParseResult parseBasicBlock(CFGFunctionParserState &functionState);
   Statement *parseStatement(ParentType parent);
 
   OperationInst *parseCFGOperation(CFGFunctionParserState &functionState);
   TerminatorInst *parseTerminator(CFGFunctionParserState &functionState);
 
+  ParseResult parseMLFunc();
   ForStmt *parseForStmt(ParentType parent);
   IfStmt *parseIfStmt(ParentType parent);
   ParseResult parseNestedStatements(NodeStmt *parent);
@@ -658,7 +664,7 @@
 ///  affine-map-def ::= affine-map-id `=` affine-map-inline
 ///
 ParseResult Parser::parseAffineMapDef() {
-  assert(curToken.is(Token::affine_map_identifier));
+  assert(curToken.is(Token::hash_identifier));
 
   StringRef affineMapId = curToken.getSpelling().drop_front();
 
@@ -667,7 +673,7 @@
   if (entry)
     return emitError("redefinition of affine map id '" + affineMapId + "'");
 
-  consumeToken(Token::affine_map_identifier);
+  consumeToken(Token::hash_identifier);
 
   // Parse the '='
   if (!consumeIf(Token::equal))
@@ -1092,9 +1098,67 @@
 }
 
 //===----------------------------------------------------------------------===//
-// Functions
+// SSA
 //===----------------------------------------------------------------------===//
 
+/// Parse a SSA operand for an instruction or statement.
+///
+///   ssa-use ::= ssa-id | ssa-constant
+///
+ParseResult Parser::parseSSAUse() {
+  if (curToken.is(Token::percent_identifier)) {
+    StringRef name = curToken.getSpelling().drop_front();
+    consumeToken(Token::percent_identifier);
+    // TODO: Return this use.
+    (void)name;
+    return ParseSuccess;
+  }
+
+  // TODO: Parse SSA constants.
+
+  return emitError("expected SSA operand");
+}
+
+/// Parse a (possibly empty) list of SSA operands.
+///
+///   ssa-use-list ::= ssa-use (`,` ssa-use)*
+///   ssa-use-list-opt ::= ssa-use-list?
+///
+ParseResult Parser::parseOptionalSSAUseList(Token::Kind endToken) {
+  // TODO: Build and return this.
+  return parseCommaSeparatedList(
+      endToken, [&]() -> ParseResult { return parseSSAUse(); });
+}
+
+/// Parse an SSA use with an associated type.
+///
+///   ssa-use-and-type ::= ssa-use `:` type
+ParseResult Parser::parseSSAUseAndType() {
+  if (parseSSAUse())
+    return ParseFailure;
+
+  if (!consumeIf(Token::colon))
+    return emitError("expected ':' and type for SSA operand");
+
+  if (!parseType())
+    return ParseFailure;
+
+  return ParseSuccess;
+}
+
+/// Parse a (possibly empty) list of SSA operands with types.
+///
+///   ssa-use-and-type-list ::= ssa-use-and-type (`,` ssa-use-and-type)*
+///
+ParseResult Parser::parseOptionalSSAUseAndTypeList(Token::Kind endToken) {
+  // TODO: Build and return this.
+  return parseCommaSeparatedList(
+      endToken, [&]() -> ParseResult { return parseSSAUseAndType(); });
+}
+
+//===----------------------------------------------------------------------===//
+// Functions
+//===----------------------------------------------------------------------===//
 
 /// Parse a function signature, starting with a name and including the parameter
 /// list.
@@ -1237,7 +1301,13 @@
   // Add the block to the function.
   functionState.function->push_back(block);
 
-  // TODO: parse bb argument list.
+  // If an argument list is present, parse it.
+  if (consumeIf(Token::l_paren)) {
+    if (parseOptionalSSAUseAndTypeList(Token::r_paren))
+      return ParseFailure;
+
+    // TODO: attach it.
+  }
 
   if (!consumeIf(Token::colon))
     return emitError("expected ':' after basic block name");
@@ -1280,7 +1350,13 @@
 OperationInst *Parser::
 parseCFGOperation(CFGFunctionParserState &functionState) {
 
-  // TODO: parse ssa-id.
+  StringRef resultID;
+  if (curToken.is(Token::percent_identifier)) {
+    resultID = curToken.getSpelling().drop_front();
+    consumeToken();
+    if (!consumeIf(Token::equal))
+      return (emitError("expected '=' after SSA name"), nullptr);
+  }
 
   if (curToken.isNot(Token::string))
     return (emitError("expected operation name in quotes"), nullptr);
@@ -1294,9 +1370,8 @@
   if (!consumeIf(Token::l_paren))
     return (emitError("expected '(' to start operand list"), nullptr);
 
-  // TODO: Parse operands.
-  if (!consumeIf(Token::r_paren))
-    return (emitError("expected ')' in operand list"), nullptr);
+  // Parse the operand list.
+  parseOptionalSSAUseList(Token::r_paren);
 
   SmallVector<NamedAttribute, 4> attributes;
   if (curToken.is(Token::l_brace)) {
@@ -1304,6 +1379,7 @@
       return nullptr;
   }
 
+  // TODO: Don't drop result name and operand names on the floor.
   auto nameId = Identifier::get(name, context);
   return new OperationInst(nameId, attributes, context);
 }
@@ -1334,6 +1410,7 @@
       return (emitError("expected basic block name"), nullptr);
     return new BranchInst(destBB);
   }
+    // TODO: cond_br.
   }
 }
 
@@ -1501,7 +1578,7 @@
       if (parseCFGFunc()) return nullptr;
       break;
 
-    case Token::affine_map_identifier:
+    case Token::hash_identifier:
       if (parseAffineMapDef()) return nullptr;
       break;
 
diff --git a/lib/Parser/TokenKinds.def b/lib/Parser/TokenKinds.def
index 158852a..1637a95 100644
--- a/lib/Parser/TokenKinds.def
+++ b/lib/Parser/TokenKinds.def
@@ -50,9 +50,10 @@
 TOK_MARKER(error)
 
 // Identifiers.
-TOK_IDENTIFIER(bare_identifier)         // foo
-TOK_IDENTIFIER(at_identifier)           // @foo
-TOK_IDENTIFIER(affine_map_identifier)   // #foo
+TOK_IDENTIFIER(bare_identifier)    // foo
+TOK_IDENTIFIER(at_identifier)      // @foo
+TOK_IDENTIFIER(hash_identifier)    // #foo
+TOK_IDENTIFIER(percent_identifier) // %foo
 // TODO: @@foo, etc.
 
 // Literals