Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lib/Dialect/FIRRTL/Import/FIRLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,19 @@ FIRToken FIRLexer::lexIdentifierOrKeyword(const char *tokStart) {
}
}

// Check to see if this is a keyword followed by '<' character.
if (*curPtr == '<') {
FIRToken::Kind kind = llvm::StringSwitch<FIRToken::Kind>(spelling)
#define TOK_LESSKEYWORD(SPELLING) .Case(#SPELLING, FIRToken::langle_##SPELLING)
#include "FIRTokenKinds.def"
.Default(FIRToken::identifier);
#undef TOK_LESSKEYWORD
if (kind != FIRToken::identifier) {
++curPtr;
return formToken(kind, tokStart);
}
}

// See if the identifier is a keyword. By default, it is an identifier.
FIRToken::Kind kind = llvm::StringSwitch<FIRToken::Kind>(spelling)
#define TOK_KEYWORD(SPELLING) .Case(#SPELLING, FIRToken::kw_##SPELLING)
Expand Down
1 change: 1 addition & 0 deletions lib/Dialect/FIRRTL/Import/FIRLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class FIRToken {
#define TOK_PUNCTUATION(NAME, SPELLING) NAME,
#define TOK_KEYWORD(SPELLING) kw_##SPELLING,
#define TOK_LPKEYWORD(SPELLING) lp_##SPELLING,
#define TOK_LESSKEYWORD(SPELLING) langle_##SPELLING,
#include "FIRTokenKinds.def"
};

Expand Down
184 changes: 129 additions & 55 deletions lib/Dialect/FIRRTL/Import/FIRParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,8 @@ struct FIRParser {
// Parse 'verLit' into specified value
ParseResult parseVersionLit(const Twine &message);

// Parse ('<' intLit '>')? setting result to -1 if not present.
template <typename T>
ParseResult parseOptionalWidth(T &result);
// Parse 'intLit' '>' assuming '<' was already consumed.
ParseResult parseWidth(int32_t &result);

// Parse the 'id' grammar, which is an identifier or an allowed keyword.
ParseResult parseId(StringRef &result, const Twine &message);
Expand Down Expand Up @@ -682,23 +681,15 @@ ParseResult FIRParser::parseVersionLit(const Twine &message) {
return success();
}

// optional-width ::= ('<' intLit '>')?
//
// This returns with result equal to -1 if not present.
template <typename T>
ParseResult FIRParser::parseOptionalWidth(T &result) {
if (!consumeIf(FIRToken::less))
return result = -1, success();

// Parse a width specifier if present.
/// Parse a width specifier: intLit '>'
/// This is used when the '<' has already been consumed.
ParseResult FIRParser::parseWidth(int32_t &result) {
auto widthLoc = getToken().getLoc();
if (parseIntLit(result, "expected width") ||
parseToken(FIRToken::greater, "expected >"))
parseToken(FIRToken::greater, "expected '>'"))
return failure();

if (result < 0)
return emitError(widthLoc, "invalid width specifier"), failure();

return success();
}

Expand Down Expand Up @@ -1016,22 +1007,41 @@ ParseResult FIRParser::parseType(FIRRTLType &result, const Twine &message) {
break;

case FIRToken::kw_UInt:
consumeToken(FIRToken::kw_UInt);
// Width is not present since langle_UInt would have been lexed instead.
result = UIntType::get(getContext(), -1);
break;

case FIRToken::kw_SInt:
case FIRToken::kw_Analog: {
consumeToken(FIRToken::kw_SInt);
// Width is not present since langle_SInt would have been lexed instead.
result = SIntType::get(getContext(), -1);
break;

case FIRToken::kw_Analog:
consumeToken(FIRToken::kw_Analog);
// Width is not present since langle_Analog would have been lexed instead.
result = AnalogType::get(getContext(), -1);
break;

case FIRToken::langle_UInt:
case FIRToken::langle_SInt:
case FIRToken::langle_Analog: {
// The '<' has already been consumed by the lexer, so we need to parse
// the mandatory width and the trailing '>'.
auto kind = getToken().getKind();
consumeToken();

// Parse a width specifier if present.
int32_t width;
if (parseOptionalWidth(width))
if (parseWidth(width))
return failure();

if (kind == FIRToken::kw_SInt)
if (kind == FIRToken::langle_SInt)
result = SIntType::get(getContext(), width);
else if (kind == FIRToken::kw_UInt)
else if (kind == FIRToken::langle_UInt)
result = UIntType::get(getContext(), width);
else {
assert(kind == FIRToken::kw_Analog);
assert(kind == FIRToken::langle_Analog);
result = AnalogType::get(getContext(), width);
}
break;
Expand Down Expand Up @@ -1219,6 +1229,22 @@ ParseResult FIRParser::parseType(FIRRTLType &result, const Twine &message) {
if (requireFeature({4, 0, 0}, "Lists") || parseListType(result))
return failure();
break;

case FIRToken::langle_List: {
// The '<' has already been consumed by the lexer, so we need to parse
// the element type and the trailing '>'.
if (requireFeature({4, 0, 0}, "Lists"))
return failure();
consumeToken();

PropertyType elementType;
if (parsePropertyType(elementType, "expected List element type") ||
parseToken(FIRToken::greater, "expected '>' in List type"))
return failure();

result = ListType::get(getContext(), elementType);
break;
}
}

// Handle postfix vector sizes.
Expand Down Expand Up @@ -1959,7 +1985,9 @@ struct FIRStmtParser : public FIRParser {
ParseResult parsePostFixFieldId(Value &result);
ParseResult parsePostFixIntSubscript(Value &result);
ParseResult parsePostFixDynamicSubscript(Value &result);
ParseResult parseIntegerLiteralExp(Value &result);
ParseResult
parseIntegerLiteralExp(Value &result, bool isSigned,
std::optional<int32_t> allocatedWidth = {});
ParseResult parseListExp(Value &result);
ParseResult parseListConcatExp(Value &result);
ParseResult parseCatExp(Value &result);
Expand Down Expand Up @@ -2227,19 +2255,37 @@ ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
return failure();
break;

case FIRToken::kw_UInt:
case FIRToken::kw_SInt:
if (parseIntegerLiteralExp(result))
case FIRToken::langle_UInt:
case FIRToken::langle_SInt: {
// The '<' has already been consumed by the lexer, so we need to parse
// the mandatory width and '>'.
bool isSigned = getToken().is(FIRToken::langle_SInt);
consumeToken();
int32_t width;
if (parseWidth(width))
return failure();

// Now parse the '(' intLit ')' part.
if (parseIntegerLiteralExp(result, isSigned, width))
return failure();
break;
}

case FIRToken::lp_UInt:
if (parseIntegerLiteralExp(result, /*isSigned=*/false))
return failure();
break;
case FIRToken::kw_String: {
case FIRToken::lp_SInt:
if (parseIntegerLiteralExp(result, /*isSigned=*/true))
return failure();
break;
case FIRToken::lp_String: {
if (requireFeature({3, 1, 0}, "Strings"))
return failure();
locationProcessor.setLoc(getToken().getLoc());
consumeToken(FIRToken::kw_String);
consumeToken(FIRToken::lp_String);
StringRef spelling;
if (parseToken(FIRToken::l_paren, "expected '(' in String expression") ||
parseGetSpelling(spelling) ||
if (parseGetSpelling(spelling) ||
parseToken(FIRToken::string,
"expected string literal in String expression") ||
parseToken(FIRToken::r_paren, "expected ')' in String expression"))
Expand All @@ -2249,14 +2295,13 @@ ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
builder, attr, builder.getType<StringType>(), attr);
break;
}
case FIRToken::kw_Integer: {
case FIRToken::lp_Integer: {
if (requireFeature({3, 1, 0}, "Integers"))
return failure();
locationProcessor.setLoc(getToken().getLoc());
consumeToken(FIRToken::kw_Integer);
consumeToken(FIRToken::lp_Integer);
APInt value;
if (parseToken(FIRToken::l_paren, "expected '(' in Integer expression") ||
parseIntLit(value, "expected integer literal in Integer expression") ||
if (parseIntLit(value, "expected integer literal in Integer expression") ||
parseToken(FIRToken::r_paren, "expected ')' in Integer expression"))
return failure();
APSInt apint(value, /*isUnsigned=*/false);
Expand All @@ -2265,13 +2310,11 @@ ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
builder.getType<FIntegerType>(), apint);
break;
}
case FIRToken::kw_Bool: {
case FIRToken::lp_Bool: {
if (requireFeature(missingSpecFIRVersion, "Bools"))
return failure();
locationProcessor.setLoc(getToken().getLoc());
consumeToken(FIRToken::kw_Bool);
if (parseToken(FIRToken::l_paren, "expected '(' in Bool expression"))
return failure();
consumeToken(FIRToken::lp_Bool);
bool value;
if (consumeIf(FIRToken::kw_true))
value = true;
Expand All @@ -2286,13 +2329,11 @@ ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
builder, attr, builder.getType<BoolType>(), value);
break;
}
case FIRToken::kw_Double: {
case FIRToken::lp_Double: {
if (requireFeature(missingSpecFIRVersion, "Doubles"))
return failure();
locationProcessor.setLoc(getToken().getLoc());
consumeToken(FIRToken::kw_Double);
if (parseToken(FIRToken::l_paren, "expected '(' in Double expression"))
return failure();
consumeToken(FIRToken::lp_Double);
auto spelling = getTokenSpelling();
if (parseToken(FIRToken::floatingpoint,
"expected floating point in Double expression") ||
Expand All @@ -2308,7 +2349,8 @@ ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
builder, attr, builder.getType<DoubleType>(), attr);
break;
}
case FIRToken::kw_List: {
case FIRToken::lp_List:
case FIRToken::langle_List: {
if (requireFeature({4, 0, 0}, "Lists"))
return failure();
if (isLeadingStmt)
Expand Down Expand Up @@ -2359,6 +2401,13 @@ ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
// try them.
case FIRToken::identifier: // exp ::= id
case FIRToken::literal_identifier:
case FIRToken::kw_UInt:
case FIRToken::kw_SInt:
case FIRToken::kw_String:
case FIRToken::kw_Integer:
case FIRToken::kw_Bool:
case FIRToken::kw_Double:
case FIRToken::kw_List:
Comment on lines +2404 to +2410
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could be removed, however, they can also be viewed as documentation of what is going on in some relatively complex code.

default: {
StringRef name;
auto loc = getToken().getLoc();
Expand Down Expand Up @@ -2596,17 +2645,31 @@ ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {

/// integer-literal-exp ::= 'UInt' optional-width '(' intLit ')'
/// ::= 'SInt' optional-width '(' intLit ')'
ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
bool isSigned = getToken().is(FIRToken::kw_SInt);
///
/// If allocatedWidth is provided, it means the width was already parsed
/// (e.g., from a langle_UInt token) and should be used instead of parsing
/// it from the token stream.
ParseResult
FIRStmtParser::parseIntegerLiteralExp(Value &result, bool isSigned,
std::optional<int32_t> allocatedWidth) {
auto loc = getToken().getLoc();
consumeToken();

// Parse a width specifier if present.
int32_t width;
// Determine if '(' was already consumed by the lexer.
bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
if (hasLParen)
consumeToken();

// Parse a width specifier if not already provided.
int32_t width = allocatedWidth.value_or(-1);
APInt value;
if (parseOptionalWidth(width) ||
parseToken(FIRToken::l_paren, "expected '(' in integer expression") ||
parseIntLit(value, "expected integer value") ||

// If we consumed an lp_ token, the '(' was already consumed by the lexer.
// Otherwise, we need to parse it.
if (!hasLParen &&
parseToken(FIRToken::l_paren, "expected '(' in integer expression"))
return failure();

if (parseIntLit(value, "expected integer value") ||
parseToken(FIRToken::r_paren, "expected ')' in integer expression"))
return failure();

Expand Down Expand Up @@ -2640,13 +2703,24 @@ ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
/// list-exp ::= list-type '(' exp* ')'
ParseResult FIRStmtParser::parseListExp(Value &result) {
auto loc = getToken().getLoc();
FIRRTLType type;
if (parseListType(type))
bool hasLAngle = getToken().is(FIRToken::langle_List);
bool hasLParen = getToken().is(FIRToken::lp_List);
consumeToken();

PropertyType elementType;
// If we consumed a langle_ token, the '<' was already consumed by the lexer.
if (!hasLAngle && parseToken(FIRToken::less, "expected '<' in List type"))
return failure();
auto listType = type_cast<ListType>(type);
auto elementType = listType.getElementType();

if (parseToken(FIRToken::l_paren, "expected '(' in List expression"))
if (parsePropertyType(elementType, "expected List element type") ||
parseToken(FIRToken::greater, "expected '>' in List type"))
return failure();

auto listType = ListType::get(getContext(), elementType);

// If we consumed an lp_ token, the '(' was already consumed by the lexer.
if (!hasLParen &&
parseToken(FIRToken::l_paren, "expected '(' in List expression"))
return failure();

SmallVector<Value, 3> operands;
Expand Down
21 changes: 20 additions & 1 deletion lib/Dialect/FIRRTL/Import/FIRTokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#if !defined(TOK_MARKER) && !defined(TOK_IDENTIFIER) && \
!defined(TOK_LITERAL) && !defined(TOK_PUNCTUATION) && \
!defined(TOK_KEYWORD) && !defined(TOK_LPKEYWORD) && \
!defined(TOK_LPKEYWORD_PRIM)
!defined(TOK_LESSKEYWORD) && !defined(TOK_LPKEYWORD_PRIM)
#error Must define one of the TOK_ macros.
#endif

Expand All @@ -41,6 +41,9 @@
VERSION, FEATURE) \
TOK_LPKEYWORD(SPELLING)
#endif
#ifndef TOK_LESSKEYWORD
#define TOK_LESSKEYWORD(SPELLING)
#endif

// Markers
TOK_MARKER(eof)
Expand Down Expand Up @@ -199,6 +202,21 @@ TOK_LPKEYWORD(intrinsic)
TOK_LPKEYWORD(cat)
TOK_LPKEYWORD(unsafe_domain_cast)

TOK_LPKEYWORD(UInt)
TOK_LPKEYWORD(SInt)
TOK_LPKEYWORD(String)
TOK_LPKEYWORD(Integer)
TOK_LPKEYWORD(Bool)
TOK_LPKEYWORD(Double)
TOK_LPKEYWORD(List)

// Keywords when followed by a '<'. These turn "foo" into
// FIRToken::langle_foo enums.
TOK_LESSKEYWORD(UInt)
TOK_LESSKEYWORD(SInt)
TOK_LESSKEYWORD(Analog)
TOK_LESSKEYWORD(List)

// These are for LPKEYWORD cases that correspond to a primitive operation.
TOK_LPKEYWORD_PRIM(add, AddPrimOp, 2, 0, FIRVersion(0, 0, 0), "Base")
TOK_LPKEYWORD_PRIM(and, AndPrimOp, 2, 0, FIRVersion(0, 0, 0), "Base")
Expand Down Expand Up @@ -253,4 +271,5 @@ TOK_LPKEYWORD_PRIM(integer_shl, IntegerShlOp, 2, 0, FIRVersion(3, 1, 0),
#undef TOK_PUNCTUATION
#undef TOK_KEYWORD
#undef TOK_LPKEYWORD
#undef TOK_LESSKEYWORD
#undef TOK_LPKEYWORD_PRIM
Loading