From 4b3936e2983dcecd36a3437bd6c7eef8d5fbbffa Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Wed, 28 Jun 2017 08:49:04 -0700 Subject: Rename literal tokens. These had a typo (`Literial`), so they needed a fix eventually. I also went ahead and made things a bit more verbose (`IntegerLiteral`, `FloatingPointLiteral`) because these names don't get used often enough for the brevity to pay off. --- source/slang/emit.cpp | 2 +- source/slang/lexer.cpp | 20 ++++++++++---------- source/slang/parser.cpp | 36 ++++++++++++++++++------------------ source/slang/preprocessor.cpp | 18 +++++++++--------- source/slang/token-defs.h | 8 ++++---- 5 files changed, 42 insertions(+), 42 deletions(-) (limited to 'source') diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 77b0c2fe9..5272204f6 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -487,7 +487,7 @@ static String getStringOrIdentifierTokenValue( case TokenType::Identifier: return token.Content; - case TokenType::StringLiterial: + case TokenType::StringLiteral: return getStringLiteralTokenValue(token); break; } diff --git a/source/slang/lexer.cpp b/source/slang/lexer.cpp index f81ead87c..73fbb9605 100644 --- a/source/slang/lexer.cpp +++ b/source/slang/lexer.cpp @@ -370,7 +370,7 @@ namespace Slang { case 'f': case 'F': advance(lexer); - return TokenType::DoubleLiterial; + return TokenType::FloatingPointLiteral; default: break; @@ -453,21 +453,21 @@ namespace Slang lexDigits(lexer, base); maybeLexNumberExponent(lexer, base); - return maybeLexNumberSuffix(lexer, TokenType::DoubleLiterial); + return maybeLexNumberSuffix(lexer, TokenType::FloatingPointLiteral); } static TokenType lexNumber(Lexer* lexer, int base) { // TODO(tfoley): Need to consider whehter to allow any kind of digit separator character. - TokenType tokenType = TokenType::IntLiterial; + TokenType tokenType = TokenType::IntegerLiteral; // At the start of things, we just concern ourselves with digits lexDigits(lexer, base); if( peek(lexer) == '.' ) { - tokenType = TokenType::DoubleLiterial; + tokenType = TokenType::FloatingPointLiteral; advance(lexer); lexDigits(lexer, base); @@ -475,7 +475,7 @@ namespace Slang if( maybeLexNumberExponent(lexer, base)) { - tokenType = TokenType::DoubleLiterial; + tokenType = TokenType::FloatingPointLiteral; } maybeLexNumberSuffix(lexer, tokenType); @@ -575,8 +575,8 @@ namespace Slang String getStringLiteralTokenValue(Token const& token) { - assert(token.Type == TokenType::StringLiterial - || token.Type == TokenType::CharLiterial); + assert(token.Type == TokenType::StringLiteral + || token.Type == TokenType::CharLiteral); char const* cursor = token.Content.begin(); char const* end = token.Content.end(); @@ -758,7 +758,7 @@ namespace Slang switch(peek(lexer)) { default: - return TokenType::IntLiterial; + return TokenType::IntegerLiteral; case '.': advance(lexer); @@ -798,12 +798,12 @@ namespace Slang case '\"': advance(lexer); lexStringLiteralBody(lexer, '\"'); - return TokenType::StringLiterial; + return TokenType::StringLiteral; case '\'': advance(lexer); lexStringLiteralBody(lexer, '\''); - return TokenType::CharLiterial; + return TokenType::CharLiteral; case '+': advance(lexer); diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 3ffbc1263..5e93d63cb 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -630,7 +630,7 @@ namespace Slang modifier->Position = loc; parser->ReadToken(TokenType::LParent); - if (parser->LookAheadToken(TokenType::IntLiterial)) + if (parser->LookAheadToken(TokenType::IntegerLiteral)) { modifier->op = (IntrinsicOp)StringToInt(parser->ReadToken().Content); } @@ -662,7 +662,7 @@ namespace Slang if( AdvanceIf(parser, TokenType::Comma) ) { - if( parser->LookAheadToken(TokenType::StringLiterial) ) + if( parser->LookAheadToken(TokenType::StringLiteral) ) { modifier->definitionToken = parser->ReadToken(); } @@ -708,7 +708,7 @@ namespace Slang if(AdvanceIf(parser, TokenType::OpAssign)) { - modifier->valToken = parser->ReadToken(TokenType::IntLiterial); + modifier->valToken = parser->ReadToken(TokenType::IntegerLiteral); } AddModifier(&modifierLink, modifier); @@ -726,7 +726,7 @@ namespace Slang { RefPtr modifier = new BuiltinTypeModifier(); parser->ReadToken(TokenType::LParent); - modifier->tag = BaseType(StringToInt(parser->ReadToken(TokenType::IntLiterial).Content)); + modifier->tag = BaseType(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content)); parser->ReadToken(TokenType::RParent); AddModifier(&modifierLink, modifier); @@ -738,7 +738,7 @@ namespace Slang modifier->name = parser->ReadToken(TokenType::Identifier).Content; if (AdvanceIf(parser, TokenType::Comma)) { - modifier->tag = uint32_t(StringToInt(parser->ReadToken(TokenType::IntLiterial).Content)); + modifier->tag = uint32_t(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content)); } parser->ReadToken(TokenType::RParent); @@ -807,9 +807,9 @@ namespace Slang auto decl = new ImportDecl(); decl->scope = parser->currentScope; - if (peekTokenType(parser) == TokenType::StringLiterial) + if (peekTokenType(parser) == TokenType::StringLiteral) { - auto nameToken = parser->ReadToken(TokenType::StringLiterial); + auto nameToken = parser->ReadToken(TokenType::StringLiteral); nameToken.Content = getStringLiteralTokenValue(nameToken); decl->nameToken = nameToken; } @@ -3213,18 +3213,18 @@ namespace Slang return initExpr; } - case TokenType::IntLiterial: - case TokenType::DoubleLiterial: + case TokenType::IntegerLiteral: + case TokenType::FloatingPointLiteral: { RefPtr constExpr = new ConstantExpressionSyntaxNode(); auto token = parser->tokenReader.AdvanceToken(); parser->FillPosition(constExpr.Ptr()); - if (token.Type == TokenType::IntLiterial) + if (token.Type == TokenType::IntegerLiteral) { constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; constExpr->IntValue = StringToInt(token.Content); } - else if (token.Type == TokenType::DoubleLiterial) + else if (token.Type == TokenType::FloatingPointLiteral) { constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float; constExpr->FloatValue = (FloatingPointLiteralValue) StringToDouble(token.Content); @@ -3233,14 +3233,14 @@ namespace Slang return constExpr; } - case TokenType::StringLiterial: + case TokenType::StringLiteral: { RefPtr constExpr = new ConstantExpressionSyntaxNode(); auto token = parser->tokenReader.AdvanceToken(); parser->FillPosition(constExpr.Ptr()); constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::String; - if (!parser->LookAheadToken(TokenType::StringLiterial)) + if (!parser->LookAheadToken(TokenType::StringLiteral)) { // Easy/common case: a single string constExpr->stringValue = getStringLiteralTokenValue(token); @@ -3249,7 +3249,7 @@ namespace Slang { StringBuilder sb; sb << getStringLiteralTokenValue(token); - while (parser->LookAheadToken(TokenType::StringLiterial)) + while (parser->LookAheadToken(TokenType::StringLiteral)) { token = parser->tokenReader.AdvanceToken(); sb << getStringLiteralTokenValue(token); @@ -3467,18 +3467,18 @@ namespace Slang rs = initExpr; } - else if (LookAheadToken(TokenType::IntLiterial) || - LookAheadToken(TokenType::DoubleLiterial)) + else if (LookAheadToken(TokenType::IntegerLiteral) || + LookAheadToken(TokenType::FloatingPointLiteral)) { RefPtr constExpr = new ConstantExpressionSyntaxNode(); auto token = tokenReader.AdvanceToken(); FillPosition(constExpr.Ptr()); - if (token.Type == TokenType::IntLiterial) + if (token.Type == TokenType::IntegerLiteral) { constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; constExpr->IntValue = StringToInt(token.Content); } - else if (token.Type == TokenType::DoubleLiterial) + else if (token.Type == TokenType::FloatingPointLiteral) { constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float; constExpr->FloatValue = (FloatingPointLiteralValue) StringToDouble(token.Content); diff --git a/source/slang/preprocessor.cpp b/source/slang/preprocessor.cpp index 084f518fb..f84355018 100644 --- a/source/slang/preprocessor.cpp +++ b/source/slang/preprocessor.cpp @@ -1083,7 +1083,7 @@ static PreprocessorExpressionValue ParseAndEvaluateUnaryExpression(PreprocessorD return value; } - case TokenType::IntLiterial: + case TokenType::IntegerLiteral: return StringToInt(AdvanceToken(context).Content); case TokenType::Identifier: @@ -1488,7 +1488,7 @@ static void HandleImportDirective(PreprocessorDirectiveContext* context); static void HandleIncludeDirective(PreprocessorDirectiveContext* context) { Token pathToken; - if(!Expect(context, TokenType::StringLiterial, Diagnostics::expectedTokenInPreprocessorDirective, &pathToken)) + if(!Expect(context, TokenType::StringLiteral, Diagnostics::expectedTokenInPreprocessorDirective, &pathToken)) return; String path = getFileNameTokenValue(pathToken); @@ -1656,7 +1656,7 @@ static void HandleErrorDirective(PreprocessorDirectiveContext* context) static void HandleLineDirective(PreprocessorDirectiveContext* context) { int line = 0; - if (PeekTokenType(context) == TokenType::IntLiterial) + if (PeekTokenType(context) == TokenType::IntegerLiteral) { line = StringToInt(AdvanceToken(context).Content); } @@ -1672,7 +1672,7 @@ static void HandleLineDirective(PreprocessorDirectiveContext* context) else { GetSink(context)->diagnose(PeekLoc(context), Diagnostics::expected2TokensInPreprocessorDirective, - TokenType::IntLiterial, + TokenType::IntegerLiteral, "default", GetDirectiveName(context)); context->parseError = true; @@ -1686,11 +1686,11 @@ static void HandleLineDirective(PreprocessorDirectiveContext* context) { file = directiveLoc.FileName; } - else if (PeekTokenType(context) == TokenType::StringLiterial) + else if (PeekTokenType(context) == TokenType::StringLiteral) { file = AdvanceToken(context).Content; } - else if (PeekTokenType(context) == TokenType::IntLiterial) + else if (PeekTokenType(context) == TokenType::IntegerLiteral) { // Note(tfoley): GLSL allows the "source string" to be indicated by an integer // TODO(tfoley): Figure out a better way to handle this, if it matters @@ -1698,7 +1698,7 @@ static void HandleLineDirective(PreprocessorDirectiveContext* context) } else { - Expect(context, TokenType::StringLiterial, Diagnostics::expectedTokenInPreprocessorDirective); + Expect(context, TokenType::StringLiteral, Diagnostics::expectedTokenInPreprocessorDirective); return; } @@ -1723,7 +1723,7 @@ static void handleGLSLVersionDirective(PreprocessorDirectiveContext* context) Token versionNumberToken; if(!ExpectRaw( context, - TokenType::IntLiterial, + TokenType::IntegerLiteral, Diagnostics::expectedTokenInPreprocessorDirective, &versionNumberToken)) { @@ -2090,7 +2090,7 @@ TokenList preprocessSource( static void HandleImportDirective(PreprocessorDirectiveContext* context) { Token pathToken; - if(!Expect(context, TokenType::StringLiterial, Diagnostics::expectedTokenInPreprocessorDirective, &pathToken)) + if(!Expect(context, TokenType::StringLiteral, Diagnostics::expectedTokenInPreprocessorDirective, &pathToken)) return; String path = getFileNameTokenValue(pathToken); diff --git a/source/slang/token-defs.h b/source/slang/token-defs.h index 0fe833e36..08f67f996 100644 --- a/source/slang/token-defs.h +++ b/source/slang/token-defs.h @@ -21,10 +21,10 @@ TOKEN(EndOfFile, "end of file") TOKEN(EndOfDirective, "end of line") TOKEN(Invalid, "invalid character") TOKEN(Identifier, "identifier") -TOKEN(IntLiterial, "integer literal") -TOKEN(DoubleLiterial, "floating-point literal") -TOKEN(StringLiterial, "string literal") -TOKEN(CharLiterial, "character literal") +TOKEN(IntegerLiteral, "integer literal") +TOKEN(FloatingPointLiteral, "floating-point literal") +TOKEN(StringLiteral, "string literal") +TOKEN(CharLiteral, "character literal") TOKEN(WhiteSpace, "whitespace") TOKEN(NewLine, "newline") TOKEN(LineComment, "line comment") -- cgit v1.2.3 From d601921b71ed44835e8d4fa6f13ff7aefcf7649d Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Wed, 28 Jun 2017 10:20:16 -0700 Subject: Actually respect suffixes on numeric literals. - Add logic to extract the value and suffix from a numeric literal - This duplicates some of the lexing logic, but this is hard to avoid without redundant runtime work - Note that I'm not using and stdlib string-to-number code. This should be more robust once it is working, but it is obviously error prone in the near term. The main up-sides to this are: - We can handle binary integer literals - We can handle hexadecimal floating-point literals without stdlib support - We can hypothetically support digit separators, if we ever wanted - The parser looks at the suffix characters sliced off by the lexer, and tries to pick a type to use for a literal - It uses `NULL` if there is no suffix, to avoid some nasty order dependencies where the stdlib might need to parse a number before it has seen the definition of `int` - Right now I only handle a few cases, so there may be bugs lurking here - The emit logic needs to handle the fact that a literal node in the AST might have a non-default type attached. - Right now I just quickly check for the most likely types, and emit the literal with a matching suffix. This doesn't seem robust if any source language supports a suffix for a type where a target has no corresponding suffix. In the long term some amount of casting is probably required. --- source/slang/check.cpp | 4 + source/slang/diagnostic-defs.h | 3 + source/slang/emit.cpp | 41 +++++++ source/slang/lexer.cpp | 210 +++++++++++++++++++++++++++++++++- source/slang/lexer.h | 6 + source/slang/parser.cpp | 136 ++++++++++++++++++++-- source/slang/syntax.cpp | 5 + source/slang/syntax.h | 4 + tests/hlsl/simple/literal-typing.hlsl | 25 ++++ 9 files changed, 421 insertions(+), 13 deletions(-) create mode 100644 tests/hlsl/simple/literal-typing.hlsl (limited to 'source') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 11efb2f7d..dfa726150 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -1887,6 +1887,10 @@ namespace Slang } virtual RefPtr VisitConstantExpression(ConstantExpressionSyntaxNode *expr) override { + // The expression might already have a type, determined by its suffix + if(expr->Type.type) + return expr; + switch (expr->ConstType) { case ConstantExpressionSyntaxNode::ConstantType::Int: diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index f92f43ddb..c85270e08 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -284,6 +284,9 @@ DIAGNOSTIC(39999, Error, expectedPostfixOperator, "function called as postfix op DIAGNOSTIC(39999, Error, notEnoughArguments, "not enough arguments to call (got $0, expected $1)") DIAGNOSTIC(39999, Error, tooManyArguments, "too many arguments to call (got $0, expected $1)") +DIAGNOSTIC(39999, Error, invalidIntegerLiteralSuffix, "invalid suffix '$0' on integer literal") +DIAGNOSTIC(39999, Error, invalidFloatingPOintLiteralSuffix, "invalid suffix '$0' on floating-point literal") + // // 4xxxx - IL code generation. // diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 5272204f6..9a1d44641 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -219,6 +219,8 @@ static void Emit(EmitContext* context, double value) Emit(context, buffer); } +static void emitTokenWithLocation(EmitContext* context, Token const& token); + // Expressions // Determine if an expression should not be emitted when it is the base of @@ -900,14 +902,53 @@ static void EmitExprWithPrecedence(EmitContext* context, RefPtrType.type; switch (litExpr->ConstType) { case ConstantExpressionSyntaxNode::ConstantType::Int: + if(!type) + { + // Special case for "rewrite" mode + emitTokenWithLocation(context, litExpr->token); + break; + } + if(type->Equals(ExpressionType::GetInt())) + {} + else if(type->Equals(ExpressionType::GetUInt())) + { + suffix = "u"; + } + else + { + assert(!"unimplemented"); + } Emit(context, litExpr->IntValue); + Emit(context, suffix); break; + + case ConstantExpressionSyntaxNode::ConstantType::Float: + if(!type) + { + // Special case for "rewrite" mode + emitTokenWithLocation(context, litExpr->token); + break; + } + if(type->Equals(ExpressionType::GetFloat())) + {} + else if(type->Equals(ExpressionType::getDoubleType())) + { + suffix = "l"; + } + else + { + assert(!"unimplemented"); + } Emit(context, litExpr->FloatValue); + Emit(context, suffix); break; + case ConstantExpressionSyntaxNode::ConstantType::Bool: Emit(context, litExpr->IntValue ? "true" : "false"); break; diff --git a/source/slang/lexer.cpp b/source/slang/lexer.cpp index 73fbb9605..786376baf 100644 --- a/source/slang/lexer.cpp +++ b/source/slang/lexer.cpp @@ -415,25 +415,34 @@ namespace Slang return tokenType; } - static bool maybeLexNumberExponent(Lexer* lexer, int base) + static bool isNumberExponent(char c, int base) { - switch( peek(lexer) ) + switch( c ) { default: return false; case 'e': case 'E': if(base != 10) return false; - advance(lexer); break; case 'p': case 'P': if(base != 16) return false; - advance(lexer); break; } - // we saw an exponent marker, so we must + return true; + } + + static bool maybeLexNumberExponent(Lexer* lexer, int base) + { + if(!isNumberExponent(peek(lexer), base)) + return false; + + // we saw an exponent marker + advance(lexer); + + // Now start to read the exponent switch( peek(lexer) ) { case '+': case '-': @@ -482,6 +491,197 @@ namespace Slang return tokenType; } + static int maybeReadDigit(char const** ioCursor, int base) + { + auto& cursor = *ioCursor; + + for(;;) + { + int digitVal = 0; + int c = *cursor; + switch(c) + { + default: + return -1; + + // TODO: need to decide on digit separator characters + case '_': + cursor++; + continue; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + cursor++; + return c - '0'; + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + if(base > 10) + { + cursor++; + return c - 'a'; + } + return -1; + + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + if(base > 10) + { + cursor++; + return c - 'A'; + } + return -1; + } + } + } + + static int readOptionalBase(char const** ioCursor) + { + auto& cursor = *ioCursor; + if( *cursor == '0' ) + { + cursor++; + switch(*cursor) + { + case 'x': case 'X': + cursor++; + return 16; + + case 'b': case 'B': + cursor++; + return 2; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return 8; + + default: + return 10; + } + } + + return 10; + } + + + + IntegerLiteralValue getIntegerLiteralValue(Token const& token, String* outSuffix) + { + IntegerLiteralValue value = 0; + + char const* cursor = token.Content.begin(); + char const* end = token.Content.end(); + + int base = readOptionalBase(&cursor); + + for( ;;) + { + int digit = maybeReadDigit(&cursor, base); + if(digit < 0) + break; + + value = value*base + digit; + } + + if(outSuffix) + { + *outSuffix = String(cursor, end); + } + + return value; + } + + FloatingPointLiteralValue getFloatingPointLiteralValue(Token const& token, String* outSuffix) + { + FloatingPointLiteralValue value = 0; + + char const* cursor = token.Content.begin(); + char const* end = token.Content.end(); + + int radix = readOptionalBase(&cursor); + + bool seenDot = false; + FloatingPointLiteralValue divisor = 1; + for( ;;) + { + if(*cursor == '.') + { + cursor++; + seenDot = true; + continue; + } + + int digit = maybeReadDigit(&cursor, radix); + if(digit < 0) + break; + + value = value*radix + digit; + + if(seenDot) + { + divisor *= radix; + } + } + + // Now read optional exponent + if(isNumberExponent(*cursor, radix)) + { + cursor++; + + bool exponentIsNegative = false; + switch(*cursor) + { + default: + break; + + case '-': + exponentIsNegative = true; + cursor++; + break; + + case '+': + cursor++; + break; + } + + int exponentRadix = 10; + int exponent = 0; + + for(;;) + { + int digit = maybeReadDigit(&cursor, exponentRadix); + if(digit < 0) + break; + + exponent = exponent*exponentRadix + digit; + } + + FloatingPointLiteralValue exponentBase = 10; + if(radix == 16) + { + exponentBase = 2; + } + + FloatingPointLiteralValue exponentValue = pow(exponentBase, exponent); + + if( exponentIsNegative ) + { + divisor *= exponentValue; + } + else + { + value *= exponentValue; + } + } + + value /= divisor; + + if(outSuffix) + { + *outSuffix = String(cursor, end); + } + + return value; + } + static void lexStringLiteralBody(Lexer* lexer, char quote) { for(;;) diff --git a/source/slang/lexer.h b/source/slang/lexer.h index 5bcfc0f4a..53bfc0999 100644 --- a/source/slang/lexer.h +++ b/source/slang/lexer.h @@ -91,6 +91,12 @@ namespace Slang // Helper routines for extracting values from tokens String getStringLiteralTokenValue(Token const& token); String getFileNameTokenValue(Token const& token); + + typedef unsigned long long IntegerLiteralValue; + typedef double FloatingPointLiteralValue; + + IntegerLiteralValue getIntegerLiteralValue(Token const& token, String* outSuffix = 0); + FloatingPointLiteralValue getFloatingPointLiteralValue(Token const& token, String* outSuffix = 0); } #endif \ No newline at end of file diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 5e93d63cb..6437deca2 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -3214,22 +3214,140 @@ namespace Slang } case TokenType::IntegerLiteral: - case TokenType::FloatingPointLiteral: { RefPtr constExpr = new ConstantExpressionSyntaxNode(); - auto token = parser->tokenReader.AdvanceToken(); parser->FillPosition(constExpr.Ptr()); - if (token.Type == TokenType::IntegerLiteral) + + auto token = parser->tokenReader.AdvanceToken(); + constExpr->token = token; + + String suffix; + IntegerLiteralValue value = getIntegerLiteralValue(token, &suffix); + + // Look at any suffix on the value + char const* suffixCursor = suffix.begin(); + + RefPtr suffixType = nullptr; + if( suffixCursor && *suffixCursor ) { - constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; - constExpr->IntValue = StringToInt(token.Content); + int lCount = 0; + int uCount = 0; + int unknownCount = 0; + while(*suffixCursor) + { + switch( *suffixCursor++ ) + { + case 'l': case 'L': + lCount++; + break; + + case 'u': case 'U': + uCount++; + break; + + default: + unknownCount++; + break; + } + } + + if(unknownCount) + { + parser->sink->diagnose(token, Diagnostics::invalidIntegerLiteralSuffix, suffix); + suffixType = ExpressionType::GetError(); + } + // `u` or `ul` suffix -> `uint` + else if(uCount == 1 && (lCount <= 1)) + { + suffixType = ExpressionType::GetUInt(); + } + // `l` suffix on integer -> `int` (== `long`) + else if(lCount == 1 && !uCount) + { + suffixType = ExpressionType::GetInt(); + } + // TODO: probably need `ll` and `ull` + // TODO: are there other suffixes we need to handle? + else + { + parser->sink->diagnose(token, Diagnostics::invalidIntegerLiteralSuffix, suffix); + suffixType = ExpressionType::GetError(); + } } - else if (token.Type == TokenType::FloatingPointLiteral) + + constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; + constExpr->IntValue = value; + constExpr->Type = suffixType; + + return constExpr; + } + + + case TokenType::FloatingPointLiteral: + { + RefPtr constExpr = new ConstantExpressionSyntaxNode(); + parser->FillPosition(constExpr.Ptr()); + + auto token = parser->tokenReader.AdvanceToken(); + constExpr->token = token; + + String suffix; + FloatingPointLiteralValue value = getFloatingPointLiteralValue(token, &suffix); + + // Look at any suffix on the value + char const* suffixCursor = suffix.begin(); + + RefPtr suffixType = nullptr; + if( suffixCursor && *suffixCursor ) { - constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float; - constExpr->FloatValue = (FloatingPointLiteralValue) StringToDouble(token.Content); + int fCount = 0; + int lCount = 0; + int unknownCount = 0; + while(*suffixCursor) + { + switch( *suffixCursor++ ) + { + case 'f': case 'F': + fCount++; + break; + + case 'l': case 'L': + lCount++; + break; + + default: + unknownCount++; + break; + } + } + + if(unknownCount) + { + parser->sink->diagnose(token, Diagnostics::invalidFloatingPOintLiteralSuffix, suffix); + suffixType = ExpressionType::GetError(); + } + // `f` suffix -> `float` + if(fCount == 1 && !lCount) + { + suffixType = ExpressionType::GetFloat(); + } + // `l` or `lf` suffix on float -> `double` + else if(lCount == 1 && (fCount <= 1)) + { + suffixType = ExpressionType::getDoubleType(); + } + // TODO: are there other suffixes we need to handle? + else + { + parser->sink->diagnose(token, Diagnostics::invalidFloatingPOintLiteralSuffix, suffix); + suffixType = ExpressionType::GetError(); + } } + constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float; + constExpr->FloatValue = value; + constExpr->Type = suffixType; + return constExpr; } @@ -3237,6 +3355,7 @@ namespace Slang { RefPtr constExpr = new ConstantExpressionSyntaxNode(); auto token = parser->tokenReader.AdvanceToken(); + constExpr->token = token; parser->FillPosition(constExpr.Ptr()); constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::String; @@ -3269,6 +3388,7 @@ namespace Slang { RefPtr constExpr = new ConstantExpressionSyntaxNode(); auto token = parser->tokenReader.AdvanceToken(); + constExpr->token = token; parser->FillPosition(constExpr.Ptr()); constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Bool; constExpr->IntValue = token.Content == "true" ? 1 : 0; diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index f78d3c8ec..6b9a74f7d 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -1397,6 +1397,11 @@ namespace Slang return sBuiltinTypes[(int)BaseType::Float].GetValue().Ptr(); } + ExpressionType* ExpressionType::getDoubleType() + { + return sBuiltinTypes[(int)BaseType::Double].GetValue().Ptr(); + } + ExpressionType* ExpressionType::GetInt() { return sBuiltinTypes[(int)BaseType::Int].GetValue().Ptr(); diff --git a/source/slang/syntax.h b/source/slang/syntax.h index 7289719f4..81d6f8e01 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -375,6 +375,7 @@ namespace Slang UInt, UInt64, Float, + Double, #if 0 Texture2D = 48, TextureCube = 49, @@ -485,6 +486,7 @@ namespace Slang static ExpressionType* GetBool(); static ExpressionType* GetFloat(); + static ExpressionType* getDoubleType(); static ExpressionType* GetInt(); static ExpressionType* GetUInt(); static ExpressionType* GetVoid(); @@ -1916,6 +1918,8 @@ namespace Slang class ConstantExpressionSyntaxNode : public ExpressionSyntaxNode { public: + Token token; + enum class ConstantType { Int, diff --git a/tests/hlsl/simple/literal-typing.hlsl b/tests/hlsl/simple/literal-typing.hlsl new file mode 100644 index 000000000..71acb0d92 --- /dev/null +++ b/tests/hlsl/simple/literal-typing.hlsl @@ -0,0 +1,25 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_5_0 -entry main + +// Confirm that we get the typing of literal suffixes correct + +// A type created to cause type-checking failures downstream +struct Bad { int bad; }; + +// We define two overloads for `foo()`. The "right" one takes +// an unsigned integer, and returns it. The "wrong" one takes +// a signed integer and returns a `Bad`. + +uint foo(uint x) { return x; } +Bad foo(int x) { Bad b; b.bad = x; return b; } + +// The shader entry point will call `foo()` on a literal +// with a suffix that should make it unsigned, so that +// we either respect the suffix and call the right overload, +// or ignore it and call the wrong one. + +RWStructuredBuffer b; +[numthreads(32,1,1)] +void main(uint3 tid : SV_DispatchThreadID) +{ + b[tid.x] = foo(99u); +} \ No newline at end of file -- cgit v1.2.3