diff options
| -rw-r--r-- | source/core/core.vcxproj | 2 | ||||
| -rw-r--r-- | source/core/text-io.h | 22 | ||||
| -rw-r--r-- | source/core/token-reader.cpp | 868 | ||||
| -rw-r--r-- | source/core/token-reader.h | 258 | ||||
| -rw-r--r-- | source/slang/bytecode.h | 2 | ||||
| -rw-r--r-- | source/slang/check.cpp | 3 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 1 | ||||
| -rw-r--r-- | source/slang/glsl.meta.slang.h | 2 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 6 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 1 | ||||
| -rw-r--r-- | tools/render-test/main.cpp | 12 | ||||
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 10 | ||||
| -rw-r--r-- | tools/render-test/render-gl.cpp | 10 | ||||
| -rw-r--r-- | tools/render-test/render-test.vcxproj | 13 | ||||
| -rw-r--r-- | tools/render-test/render-test.vcxproj.filters | 6 | ||||
| -rw-r--r-- | tools/render-test/render.h | 7 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.cpp | 180 | ||||
| -rw-r--r-- | tools/render-test/shader-input-layout.h | 52 | ||||
| -rw-r--r-- | tools/slang-test/main.cpp | 4 |
19 files changed, 1423 insertions, 36 deletions
diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index ba9fe3d98..350482686 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -36,6 +36,7 @@ <ClInclude Include="smart-pointer.h" /> <ClInclude Include="stream.h" /> <ClInclude Include="text-io.h" /> + <ClInclude Include="token-reader.h" /> <ClInclude Include="type-traits.h" /> </ItemGroup> <ItemGroup> @@ -44,6 +45,7 @@ <ClCompile Include="slang-string.cpp" /> <ClCompile Include="stream.cpp" /> <ClCompile Include="text-io.cpp" /> + <ClCompile Include="token-reader.cpp" /> </ItemGroup> <ItemGroup> <Natvis Include="core.natvis" /> diff --git a/source/core/text-io.h b/source/core/text-io.h index e4bdc6e2d..c914e340a 100644 --- a/source/core/text-io.h +++ b/source/core/text-io.h @@ -311,28 +311,6 @@ namespace Slang stream = 0; } }; - - inline List<String> Split(String text, char c) - { - List<String> result; - StringBuilder sb; - for (int i = 0; i < text.Length(); i++) - { - if (text[i] == c) - { - auto str = sb.ToString(); - if (str.Length() != 0) - result.Add(str); - sb.Clear(); - } - else - sb << text[i]; - } - auto lastStr = sb.ToString(); - if (lastStr.Length()) - result.Add(lastStr); - return result; - } } #endif diff --git a/source/core/token-reader.cpp b/source/core/token-reader.cpp new file mode 100644 index 000000000..5f7115112 --- /dev/null +++ b/source/core/token-reader.cpp @@ -0,0 +1,868 @@ +#include "token-reader.h" + +namespace Slang +{ + enum class TokenizeErrorType + { + InvalidCharacter, InvalidEscapeSequence + }; + + enum class State + { + Start, Identifier, Operator, Int, Hex, Fixed, Double, Char, String, MultiComment, SingleComment + }; + + enum class LexDerivative + { + None, Line, File + }; + + inline bool IsLetter(char ch) + { + return ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || ch == '_'); + } + + inline bool IsDigit(char ch) + { + return ch >= '0' && ch <= '9'; + } + + inline bool IsPunctuation(char ch) + { + return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || + ch == '!' || ch == '^' || ch == '&' || ch == '(' || ch == ')' || + ch == '=' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || + ch == '|' || ch == ';' || ch == ',' || ch == '.' || ch == '<' || + ch == '>' || ch == '~' || ch == '@' || ch == ':' || ch == '?' || ch == '#'; + } + + inline bool IsWhiteSpace(char ch) + { + return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v'); + } + + void ParseOperators(const String & str, List<Token> & tokens, TokenFlags& tokenFlags, int line, int col, int startPos, String fileName) + { + int pos = 0; + while (pos < (int)str.Length()) + { + wchar_t curChar = str[pos]; + wchar_t nextChar = (pos < (int)str.Length() - 1) ? str[pos + 1] : '\0'; + wchar_t nextNextChar = (pos < (int)str.Length() - 2) ? str[pos + 2] : '\0'; + auto InsertToken = [&](TokenType type, const String & ct) + { + tokens.Add(Token(type, ct, line, col + pos, pos + startPos, fileName, tokenFlags)); + tokenFlags = 0; + }; + switch (curChar) + { + case '+': + if (nextChar == '+') + { + InsertToken(TokenType::OpInc, "++"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpAddAssign, "+="); + pos += 2; + } + else + { + InsertToken(TokenType::OpAdd, "+"); + pos++; + } + break; + case '-': + if (nextChar == '-') + { + InsertToken(TokenType::OpDec, "--"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpSubAssign, "-="); + pos += 2; + } + else if (nextChar == '>') + { + InsertToken(TokenType::RightArrow, "->"); + pos += 2; + } + else + { + InsertToken(TokenType::OpSub, "-"); + pos++; + } + break; + case '*': + if (nextChar == '=') + { + InsertToken(TokenType::OpMulAssign, "*="); + pos += 2; + } + else + { + InsertToken(TokenType::OpMul, "*"); + pos++; + } + break; + case '/': + if (nextChar == '=') + { + InsertToken(TokenType::OpDivAssign, "/="); + pos += 2; + } + else + { + InsertToken(TokenType::OpDiv, "/"); + pos++; + } + break; + case '%': + if (nextChar == '=') + { + InsertToken(TokenType::OpModAssign, "%="); + pos += 2; + } + else + { + InsertToken(TokenType::OpMod, "%"); + pos++; + } + break; + case '|': + if (nextChar == '|') + { + InsertToken(TokenType::OpOr, "||"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpOrAssign, "|="); + pos += 2; + } + else + { + InsertToken(TokenType::OpBitOr, "|"); + pos++; + } + break; + case '&': + if (nextChar == '&') + { + InsertToken(TokenType::OpAnd, "&&"); + pos += 2; + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpAndAssign, "&="); + pos += 2; + } + else + { + InsertToken(TokenType::OpBitAnd, "&"); + pos++; + } + break; + case '^': + if (nextChar == '=') + { + InsertToken(TokenType::OpXorAssign, "^="); + pos += 2; + } + else + { + InsertToken(TokenType::OpBitXor, "^"); + pos++; + } + break; + case '>': + if (nextChar == '>') + { + if (nextNextChar == '=') + { + InsertToken(TokenType::OpShrAssign, ">>="); + pos += 3; + } + else + { + InsertToken(TokenType::OpRsh, ">>"); + pos += 2; + } + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpGeq, ">="); + pos += 2; + } + else + { + InsertToken(TokenType::OpGreater, ">"); + pos++; + } + break; + case '<': + if (nextChar == '<') + { + if (nextNextChar == '=') + { + InsertToken(TokenType::OpShlAssign, "<<="); + pos += 3; + } + else + { + InsertToken(TokenType::OpLsh, "<<"); + pos += 2; + } + } + else if (nextChar == '=') + { + InsertToken(TokenType::OpLeq, "<="); + pos += 2; + } + else + { + InsertToken(TokenType::OpLess, "<"); + pos++; + } + break; + case '=': + if (nextChar == '=') + { + InsertToken(TokenType::OpEql, "=="); + pos += 2; + } + else + { + InsertToken(TokenType::OpAssign, "="); + pos++; + } + break; + case '!': + if (nextChar == '=') + { + InsertToken(TokenType::OpNeq, "!="); + pos += 2; + } + else + { + InsertToken(TokenType::OpNot, "!"); + pos++; + } + break; + case '?': + InsertToken(TokenType::QuestionMark, "?"); + pos++; + break; + case '@': + InsertToken(TokenType::At, "@"); + pos++; + break; + case '#': + if (nextChar == '#') + { + InsertToken(TokenType::PoundPound, "##"); + pos += 2; + } + else + { + InsertToken(TokenType::Pound, "#"); + pos++; + } + pos++; + break; + case ':': + InsertToken(TokenType::Colon, ":"); + pos++; + break; + case '~': + InsertToken(TokenType::OpBitNot, "~"); + pos++; + break; + case ';': + InsertToken(TokenType::Semicolon, ";"); + pos++; + break; + case ',': + InsertToken(TokenType::Comma, ","); + pos++; + break; + case '.': + InsertToken(TokenType::Dot, "."); + pos++; + break; + case '{': + InsertToken(TokenType::LBrace, "{"); + pos++; + break; + case '}': + InsertToken(TokenType::RBrace, "}"); + pos++; + break; + case '[': + InsertToken(TokenType::LBracket, "["); + pos++; + break; + case ']': + InsertToken(TokenType::RBracket, "]"); + pos++; + break; + case '(': + InsertToken(TokenType::LParent, "("); + pos++; + break; + case ')': + InsertToken(TokenType::RParent, ")"); + pos++; + break; + } + } + } + + List<Token> TokenizeText(const String & fileName, const String & text) + { + int lastPos = 0, pos = 0; + int line = 1, col = 0; + String file = fileName; + State state = State::Start; + StringBuilder tokenBuilder; + int tokenLine, tokenCol; + List<Token> tokenList; + LexDerivative derivative = LexDerivative::None; + TokenFlags tokenFlags = TokenFlag::AtStartOfLine; + auto InsertToken = [&](TokenType type) + { + derivative = LexDerivative::None; + tokenList.Add(Token(type, tokenBuilder.ToString(), tokenLine, tokenCol, pos, file, tokenFlags)); + tokenFlags = 0; + tokenBuilder.Clear(); + }; + auto ProcessTransferChar = [&](char nextChar) + { + switch (nextChar) + { + case '\\': + case '\"': + case '\'': + tokenBuilder.Append(nextChar); + break; + case 't': + tokenBuilder.Append('\t'); + break; + case 's': + tokenBuilder.Append(' '); + break; + case 'n': + tokenBuilder.Append('\n'); + break; + case 'r': + tokenBuilder.Append('\r'); + break; + case 'b': + tokenBuilder.Append('\b'); + break; + } + }; + while (pos <= (int)text.Length()) + { + char curChar = (pos < (int)text.Length() ? text[pos] : ' '); + char nextChar = (pos < (int)text.Length() - 1) ? text[pos + 1] : '\0'; + if (lastPos != pos) + { + if (curChar == '\n') + { + line++; + col = 0; + } + else + col++; + lastPos = pos; + } + + switch (state) + { + case State::Start: + if (IsLetter(curChar)) + { + state = State::Identifier; + tokenLine = line; + tokenCol = col; + } + else if (IsDigit(curChar)) + { + state = State::Int; + tokenLine = line; + tokenCol = col; + } + else if (curChar == '\'') + { + state = State::Char; + pos++; + tokenLine = line; + tokenCol = col; + } + else if (curChar == '"') + { + state = State::String; + pos++; + tokenLine = line; + tokenCol = col; + } + else if (curChar == '\r' || curChar == '\n') + { + tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; + pos++; + } + else if (curChar == ' ' || curChar == '\t' || curChar == -62 || curChar == -96) // -62/-96:non-break space + { + tokenFlags |= TokenFlag::AfterWhitespace; + pos++; + } + else if (curChar == '/' && nextChar == '/') + { + state = State::SingleComment; + pos += 2; + } + else if (curChar == '/' && nextChar == '*') + { + pos += 2; + state = State::MultiComment; + } + else if (curChar == '.' && IsDigit(nextChar)) + { + tokenBuilder.Append("0."); + state = State::Fixed; + pos++; + } + else if (IsPunctuation(curChar)) + { + state = State::Operator; + tokenLine = line; + tokenCol = col; + } + else + { + pos++; + } + break; + case State::Identifier: + if (IsLetter(curChar) || IsDigit(curChar)) + { + tokenBuilder.Append(curChar); + pos++; + } + else + { + auto tokenStr = tokenBuilder.ToString(); +#if 0 + if (tokenStr == "#line_reset#") + { + line = 0; + col = 0; + tokenBuilder.Clear(); + } + else if (tokenStr == "#line") + { + derivative = LexDerivative::Line; + tokenBuilder.Clear(); + } + else if (tokenStr == "#file") + { + derivative = LexDerivative::File; + tokenBuilder.Clear(); + line = 0; + col = 0; + } + else +#endif + InsertToken(TokenType::Identifier); + state = State::Start; + } + break; + case State::Operator: + if (IsPunctuation(curChar) && !((curChar == '/' && nextChar == '/') || (curChar == '/' && nextChar == '*'))) + { + tokenBuilder.Append(curChar); + pos++; + } + else + { + //do token analyze + ParseOperators(tokenBuilder.ToString(), tokenList, tokenFlags, tokenLine, tokenCol, pos - tokenBuilder.Length(), file); + tokenBuilder.Clear(); + state = State::Start; + } + break; + case State::Int: + if (IsDigit(curChar)) + { + tokenBuilder.Append(curChar); + pos++; + } + else if (curChar == '.') + { + state = State::Fixed; + tokenBuilder.Append(curChar); + pos++; + } + else if (curChar == 'e' || curChar == 'E') + { + state = State::Double; + tokenBuilder.Append(curChar); + if (nextChar == '-' || nextChar == '+') + { + tokenBuilder.Append(nextChar); + pos++; + } + pos++; + } + else if (curChar == 'x') + { + state = State::Hex; + tokenBuilder.Append(curChar); + pos++; + } + else if (curChar == 'u') + { + pos++; + tokenBuilder.Append(curChar); + InsertToken(TokenType::IntLiteral); + state = State::Start; + } + else + { + if (derivative == LexDerivative::Line) + { + derivative = LexDerivative::None; + line = StringToInt(tokenBuilder.ToString()) - 1; + col = 0; + tokenBuilder.Clear(); + } + else + { + InsertToken(TokenType::IntLiteral); + } + state = State::Start; + } + break; + case State::Hex: + if (IsDigit(curChar) || (curChar >= 'a' && curChar <= 'f') || (curChar >= 'A' && curChar <= 'F')) + { + tokenBuilder.Append(curChar); + pos++; + } + else + { + InsertToken(TokenType::IntLiteral); + state = State::Start; + } + break; + case State::Fixed: + if (IsDigit(curChar)) + { + tokenBuilder.Append(curChar); + pos++; + } + else if (curChar == 'e' || curChar == 'E') + { + state = State::Double; + tokenBuilder.Append(curChar); + if (nextChar == '-' || nextChar == '+') + { + tokenBuilder.Append(nextChar); + pos++; + } + pos++; + } + else + { + if (curChar == 'f') + pos++; + InsertToken(TokenType::DoubleLiteral); + state = State::Start; + } + break; + case State::Double: + if (IsDigit(curChar)) + { + tokenBuilder.Append(curChar); + pos++; + } + else + { + if (curChar == 'f') + pos++; + InsertToken(TokenType::DoubleLiteral); + state = State::Start; + } + break; + case State::String: + if (curChar != '"') + { + if (curChar == '\\') + { + ProcessTransferChar(nextChar); + pos++; + } + else + tokenBuilder.Append(curChar); + } + else + { + if (derivative == LexDerivative::File) + { + derivative = LexDerivative::None; + file = tokenBuilder.ToString(); + tokenBuilder.Clear(); + } + else + { + InsertToken(TokenType::StringLiteral); + } + state = State::Start; + } + pos++; + break; + case State::Char: + if (curChar != '\'') + { + if (curChar == '\\') + { + ProcessTransferChar(nextChar); + pos++; + } + else + tokenBuilder.Append(curChar); + } + else + { + InsertToken(TokenType::CharLiteral); + state = State::Start; + } + pos++; + break; + case State::SingleComment: + if (curChar == '\n') + { + state = State::Start; + tokenFlags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; + } + pos++; + break; + case State::MultiComment: + if (curChar == '*' && nextChar == '/') + { + state = State::Start; + tokenFlags |= TokenFlag::AfterWhitespace; + pos += 2; + } + else + pos++; + break; + } + } + return tokenList; + } + List<Token> TokenizeText(const String & text) + { + return TokenizeText("", text); + } + + String EscapeStringLiteral(String str) + { + StringBuilder sb; + sb << "\""; + for (int i = 0; i < (int)str.Length(); i++) + { + switch (str[i]) + { + case ' ': + sb << "\\s"; + break; + case '\n': + sb << "\\n"; + break; + case '\r': + sb << "\\r"; + break; + case '\t': + sb << "\\t"; + break; + case '\v': + sb << "\\v"; + break; + case '\'': + sb << "\\\'"; + break; + case '\"': + sb << "\\\""; + break; + case '\\': + sb << "\\\\"; + break; + default: + sb << str[i]; + break; + } + } + sb << "\""; + return sb.ProduceString(); + } + + String UnescapeStringLiteral(String str) + { + StringBuilder sb; + for (int i = 0; i < (int)str.Length(); i++) + { + if (str[i] == '\\' && i < (int)str.Length() - 1) + { + switch (str[i + 1]) + { + case 's': + sb << " "; + break; + case 't': + sb << '\t'; + break; + case 'n': + sb << '\n'; + break; + case 'r': + sb << '\r'; + break; + case 'v': + sb << '\v'; + break; + case '\'': + sb << '\''; + break; + case '\"': + sb << "\""; + break; + case '\\': + sb << "\\"; + break; + default: + i = i - 1; + sb << str[i]; + } + i++; + } + else + sb << str[i]; + } + return sb.ProduceString(); + } + + + String TokenTypeToString(TokenType type) + { + switch (type) + { + case TokenType::EndOfFile: + return "end of file"; + case TokenType::Unknown: + return "UnknownToken"; + case TokenType::Identifier: + return "identifier"; + case TokenType::IntLiteral: + return "integer literal"; + case TokenType::DoubleLiteral: + return "floating-point literal"; + case TokenType::StringLiteral: + return "string literal"; + case TokenType::CharLiteral: + return "character literal"; + case TokenType::QuestionMark: + return "'?'"; + case TokenType::Colon: + return "':'"; + case TokenType::Semicolon: + return "';'"; + case TokenType::Comma: + return "','"; + case TokenType::LBrace: + return "'{'"; + case TokenType::RBrace: + return "'}'"; + case TokenType::LBracket: + return "'['"; + case TokenType::RBracket: + return "']'"; + case TokenType::LParent: + return "'('"; + case TokenType::RParent: + return "')'"; + case TokenType::At: + return "'@'"; + case TokenType::OpAssign: + return "'='"; + case TokenType::OpAdd: + return "'+'"; + case TokenType::OpSub: + return "'-'"; + case TokenType::OpMul: + return "'*'"; + case TokenType::OpDiv: + return "'/'"; + case TokenType::OpMod: + return "'%'"; + case TokenType::OpNot: + return "'!'"; + case TokenType::OpLsh: + return "'<<'"; + case TokenType::OpRsh: + return "'>>'"; + case TokenType::OpAddAssign: + return "'+='"; + case TokenType::OpSubAssign: + return "'-='"; + case TokenType::OpMulAssign: + return "'*='"; + case TokenType::OpDivAssign: + return "'/='"; + case TokenType::OpModAssign: + return "'%='"; + case TokenType::OpEql: + return "'=='"; + case TokenType::OpNeq: + return "'!='"; + case TokenType::OpGreater: + return "'>'"; + case TokenType::OpLess: + return "'<'"; + case TokenType::OpGeq: + return "'>='"; + case TokenType::OpLeq: + return "'<='"; + case TokenType::OpAnd: + return "'&&'"; + case TokenType::OpOr: + return "'||'"; + case TokenType::OpBitXor: + return "'^'"; + case TokenType::OpBitAnd: + return "'&'"; + case TokenType::OpBitOr: + return "'|'"; + case TokenType::OpInc: + return "'++'"; + case TokenType::OpDec: + return "'--'"; + case TokenType::Pound: + return "'#'"; + case TokenType::PoundPound: + return "'##'"; + default: + return ""; + } + } + + TokenReader::TokenReader(String text) + { + this->tokens = TokenizeText("", text); + tokenPtr = 0; + } +} diff --git a/source/core/token-reader.h b/source/core/token-reader.h new file mode 100644 index 000000000..aaebad756 --- /dev/null +++ b/source/core/token-reader.h @@ -0,0 +1,258 @@ +#ifndef CORE_TOKEN_READER_H +#define CORE_TOKEN_READER_H + +#include "basic.h" + +namespace Slang +{ + enum class TokenType + { + EndOfFile = -1, + // illegal + Unknown, + // identifier + Identifier, + // constant + IntLiteral, DoubleLiteral, StringLiteral, CharLiteral, + // operators + Semicolon, Comma, Dot, LBrace, RBrace, LBracket, RBracket, LParent, RParent, + OpAssign, OpAdd, OpSub, OpMul, OpDiv, OpMod, OpNot, OpBitNot, OpLsh, OpRsh, + OpEql, OpNeq, OpGreater, OpLess, OpGeq, OpLeq, + OpAnd, OpOr, OpBitXor, OpBitAnd, OpBitOr, + OpInc, OpDec, OpAddAssign, OpSubAssign, OpMulAssign, OpDivAssign, OpModAssign, + OpShlAssign, OpShrAssign, OpOrAssign, OpAndAssign, OpXorAssign, + + QuestionMark, Colon, RightArrow, At, Pound, PoundPound, + }; + + class CodePosition + { + public: + int Line = -1, Col = -1, Pos = -1; + String FileName; + String ToString() + { + StringBuilder sb(100); + sb << FileName; + if (Line != -1) + sb << "(" << Line << ")"; + return sb.ProduceString(); + } + CodePosition() = default; + CodePosition(int line, int col, int pos, String fileName) + { + Line = line; + Col = col; + Pos = pos; + this->FileName = fileName; + } + bool operator < (const CodePosition & pos) const + { + return FileName < pos.FileName || (FileName == pos.FileName && Line < pos.Line) || + (FileName == pos.FileName && Line == pos.Line && Col < pos.Col); + } + bool operator == (const CodePosition & pos) const + { + return FileName == pos.FileName && Line == pos.Line && Col == pos.Col; + } + }; + + enum TokenFlag : unsigned int + { + AtStartOfLine = 1 << 0, + AfterWhitespace = 1 << 1, + }; + typedef unsigned int TokenFlags; + + class Token + { + public: + TokenType Type = TokenType::Unknown; + String Content; + CodePosition Position; + TokenFlags flags; + Token() = default; + Token(TokenType type, const String & content, int line, int col, int pos, String fileName, TokenFlags flags = 0) + : flags(flags) + { + Type = type; + Content = content; + Position = CodePosition(line, col, pos, fileName); + } + }; + + class TextFormatException : public Exception + { + public: + TextFormatException(String message) + : Exception(message) + {} + }; + + class TokenReader + { + private: + bool legal; + List<Token> tokens; + int tokenPtr; + public: + TokenReader(String text); + int ReadInt() + { + auto token = ReadToken(); + bool neg = false; + if (token.Content == '-') + { + neg = true; + token = ReadToken(); + } + if (token.Type == TokenType::IntLiteral) + { + if (neg) + return -StringToInt(token.Content); + else + return StringToInt(token.Content); + } + throw TextFormatException("Text parsing error: int expected."); + } + unsigned int ReadUInt() + { + auto token = ReadToken(); + if (token.Type == TokenType::IntLiteral) + { + return StringToUInt(token.Content); + } + throw TextFormatException("Text parsing error: int expected."); + } + double ReadDouble() + { + auto token = ReadToken(); + bool neg = false; + if (token.Content == '-') + { + neg = true; + token = ReadToken(); + } + if (token.Type == TokenType::DoubleLiteral || token.Type == TokenType::IntLiteral) + { + if (neg) + return -StringToDouble(token.Content); + else + return StringToDouble(token.Content); + } + throw TextFormatException("Text parsing error: floating point value expected."); + } + float ReadFloat() + { + return (float)ReadDouble(); + } + String ReadWord() + { + auto token = ReadToken(); + if (token.Type == TokenType::Identifier) + { + return token.Content; + } + throw TextFormatException("Text parsing error: identifier expected."); + } + String Read(const char * expectedStr) + { + auto token = ReadToken(); + if (token.Content == expectedStr) + { + return token.Content; + } + throw TextFormatException("Text parsing error: \'" + String(expectedStr) + "\' expected."); + } + String Read(String expectedStr) + { + auto token = ReadToken(); + if (token.Content == expectedStr) + { + return token.Content; + } + throw TextFormatException("Text parsing error: \'" + expectedStr + "\' expected."); + } + + String ReadStringLiteral() + { + auto token = ReadToken(); + if (token.Type == TokenType::StringLiteral) + { + return token.Content; + } + throw TextFormatException("Text parsing error: string literal expected."); + } + void Back(int count) + { + tokenPtr -= count; + } + Token ReadToken() + { + if (tokenPtr < (int)tokens.Count()) + { + auto &rs = tokens[tokenPtr]; + tokenPtr++; + return rs; + } + throw TextFormatException("Unexpected ending."); + } + Token NextToken(int offset = 0) + { + if (tokenPtr + offset < (int)tokens.Count()) + return tokens[tokenPtr + offset]; + else + { + Token rs; + rs.Type = TokenType::Unknown; + return rs; + } + } + bool LookAhead(String token) + { + if (tokenPtr < (int)tokens.Count()) + { + auto next = NextToken(); + return next.Content == token; + } + else + { + return false; + } + } + bool IsEnd() + { + return tokenPtr == (int)tokens.Count(); + } + public: + bool IsLegalText() + { + return legal; + } + }; + + inline List<String> Split(String text, char c) + { + List<String> result; + StringBuilder sb; + for (int i = 0; i < (int)text.Length(); i++) + { + if (text[i] == c) + { + auto str = sb.ToString(); + if (str.Length() != 0) + result.Add(str); + sb.Clear(); + } + else + sb << text[i]; + } + auto lastStr = sb.ToString(); + if (lastStr.Length()) + result.Add(lastStr); + return result; + } +} + + +#endif
\ No newline at end of file diff --git a/source/slang/bytecode.h b/source/slang/bytecode.h index f38007ba9..75b9f15cd 100644 --- a/source/slang/bytecode.h +++ b/source/slang/bytecode.h @@ -243,7 +243,7 @@ struct BCHeader // entry points for each target. }; -struct CompileRequest; +class CompileRequest; void generateBytecodeForCompileRequest( CompileRequest* compileReq); diff --git a/source/slang/check.cpp b/source/slang/check.cpp index f12e7e55d..5ebb22999 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -4,6 +4,7 @@ #include "compiler.h" #include "visitor.h" +#include "../core/secure-crt.h" #include <assert.h> namespace Slang @@ -4887,7 +4888,7 @@ namespace Slang if (auto decl = dynamic_cast<CallableDecl*>(candidate.item.declRef.decl)) { char buffer[1024]; - sprintf(buffer, "[this:%p, primary:%p, next:%p]", + sprintf_s(buffer, sizeof(buffer), "[this:%p, primary:%p, next:%p]", decl, decl->primaryDecl, decl->nextDecl); diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 971f0345b..da9489a75 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -4517,6 +4517,7 @@ emitDeclImpl(decl, nullptr); switch(inst->op) { + case 0: // nothing yet default: emit(getIRName(inst)); break; diff --git a/source/slang/glsl.meta.slang.h b/source/slang/glsl.meta.slang.h index e43a51ea9..a4aade3c2 100644 --- a/source/slang/glsl.meta.slang.h +++ b/source/slang/glsl.meta.slang.h @@ -173,7 +173,7 @@ sb << "syntax patch : GLSLPatchModifier;\n"; // [GLSL 4.5] Interpolation Qualifiers sb << "syntax smooth : SimpleModifier;\n"; sb << "syntax flat : SimpleModifier;\n"; -sb << "syntax noperspectie : SimpleModifier;\n"; +sb << "syntax noperspective : SimpleModifier;\n"; // [GLSL 4.3.2] Constant Qualifier diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 5ace50397..4bf9de5d3 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -1614,9 +1614,9 @@ namespace Slang // There are several ops we want to special-case here, // so that they will be more pleasant to look at. // +#if 0 switch (op) { -#if 0 case kIROp_Module: dumpIndent(context); dump(context, "module\n"); @@ -1688,11 +1688,11 @@ namespace Slang dumpChildrenRaw(context, block); } return; -#endif default: break; } +#endif #if 0 // We also want to special-case based on the *type* @@ -2918,7 +2918,7 @@ namespace Slang // TODO: are there any instruction types that need to be handled // specially here? That would be anything that has more state // than is visible in its operand list... - + case 0: // nothing yet default: { // The common case is that we just need to construct a cloned diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index a3d67b670..327902e4a 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -338,6 +338,7 @@ LoweredValInfo emitCallToVal( auto builder = context->irBuilder; switch (funcVal.flavor) { + case LoweredValInfo::Flavor::None: default: return LoweredValInfo::simple( builder->emitCallInst(type, getSimpleVal(context, funcVal), argCount, args)); diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp index 6907ba40f..02b1963ff 100644 --- a/tools/render-test/main.cpp +++ b/tools/render-test/main.cpp @@ -5,7 +5,7 @@ #include "render-d3d11.h" #include "render-gl.h" #include "slang-support.h" - +#include "shader-input-layout.h" #include <stdio.h> #include <stdlib.h> @@ -55,7 +55,9 @@ Buffer* gConstantBuffer; InputLayout* gInputLayout; Buffer* gVertexBuffer; Buffer* gComputeResultBuffer; -ShaderProgram* gShaderProgram; +ShaderProgram* gShaderProgram; +BindingState* gBindingState; +ShaderInputLayout gShaderInputLayout; // Entry point name to use for vertex/fragment shader static char const* vertexEntryPointName = "vertexMain"; @@ -92,6 +94,8 @@ Error initializeShaders( fclose(sourceFile); sourceText[sourceSize] = 0; + gShaderInputLayout.Parse(sourceText); + ShaderCompileRequest::SourceInfo sourceInfo; sourceInfo.path = sourcePath; sourceInfo.text = sourceText; @@ -144,6 +148,7 @@ Error initializeInner( err = initializeShaders(shaderCompiler); if(err != Error::None) return err; + gBindingState = renderer->createBindingState(gShaderInputLayout); // Do other initialization that doesn't depend on the source language. @@ -222,7 +227,7 @@ void renderFrameInner( renderer->setShaderProgram(gShaderProgram); renderer->setConstantBuffer(0, gConstantBuffer); - + renderer->setBindingState(gBindingState); // renderer->draw(3); @@ -232,6 +237,7 @@ void runCompute(Renderer * renderer) { renderer->setShaderProgram(gShaderProgram); renderer->setStorageBuffer(0, gComputeResultBuffer); + renderer->setBindingState(gBindingState); renderer->dispatchCompute(1, 1, 1); } diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index 6e9e04a78..8915952e0 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -751,6 +751,16 @@ public: auto dxContext = dxImmediateContext; dxContext->Dispatch(x, y, z); } + + virtual BindingState * createBindingState(const ShaderInputLayout & layout) + { + return nullptr; + } + + virtual void setBindingState(BindingState * state) + { + + } }; diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp index 55647fb25..79dd09ad9 100644 --- a/tools/render-test/render-gl.cpp +++ b/tools/render-test/render-gl.cpp @@ -613,6 +613,16 @@ public: { glDispatchCompute(x, y, z); } + + virtual BindingState * createBindingState(const ShaderInputLayout & layout) + { + return nullptr; + } + + virtual void setBindingState(BindingState * state) + { + + } }; diff --git a/tools/render-test/render-test.vcxproj b/tools/render-test/render-test.vcxproj index 94af429e8..0b0f6b05e 100644 --- a/tools/render-test/render-test.vcxproj +++ b/tools/render-test/render-test.vcxproj @@ -96,6 +96,8 @@ <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../../source/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -109,6 +111,8 @@ <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../../source/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -124,6 +128,8 @@ <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../../source/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -141,6 +147,8 @@ <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>../../source/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -154,6 +162,7 @@ <ClCompile Include="options.cpp" /> <ClCompile Include="render-d3d11.cpp" /> <ClCompile Include="render-gl.cpp" /> + <ClCompile Include="shader-input-layout.cpp" /> <ClCompile Include="slang-support.cpp" /> </ItemGroup> <ItemGroup> @@ -161,10 +170,14 @@ <ClInclude Include="render-d3d11.h" /> <ClInclude Include="render-gl.h" /> <ClInclude Include="render.h" /> + <ClInclude Include="shader-input-layout.h" /> <ClInclude Include="slang-support.h" /> <ClInclude Include="window.h" /> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\..\source\core\core.vcxproj"> + <Project>{f9be7957-8399-899e-0c49-e714fddd4b65}</Project> + </ProjectReference> <ProjectReference Include="..\..\source\slang\slang.vcxproj"> <Project>{db00da62-0533-4afd-b59f-a67d5b3a0808}</Project> </ProjectReference> diff --git a/tools/render-test/render-test.vcxproj.filters b/tools/render-test/render-test.vcxproj.filters index 6e0ff295a..985e24b8b 100644 --- a/tools/render-test/render-test.vcxproj.filters +++ b/tools/render-test/render-test.vcxproj.filters @@ -30,6 +30,9 @@ <ClCompile Include="slang-support.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="shader-input-layout.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="options.h"> @@ -50,5 +53,8 @@ <ClInclude Include="slang-support.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="shader-input-layout.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project>
\ No newline at end of file diff --git a/tools/render-test/render.h b/tools/render-test/render.h index 7f8f2fffa..426b0738a 100644 --- a/tools/render-test/render.h +++ b/tools/render-test/render.h @@ -3,13 +3,14 @@ #include "options.h" #include "window.h" +#include "shader-input-layout.h" namespace renderer_test { typedef struct Buffer Buffer; typedef struct InputLayout InputLayout; typedef struct ShaderProgram ShaderProgram; - +typedef struct BindingState BindingState; struct ShaderCompileRequest { struct SourceInfo @@ -93,7 +94,7 @@ public: virtual Buffer* createBuffer(BufferDesc const& desc) = 0; virtual InputLayout* createInputLayout(InputElementDesc const* inputElements, UInt inputElementCount) = 0; - + virtual BindingState* createBindingState(const ShaderInputLayout & shaderInput) = 0; virtual ShaderCompiler* getShaderCompiler() = 0; virtual void* map(Buffer* buffer, MapFlavor flavor) = 0; @@ -101,7 +102,7 @@ public: virtual void setInputLayout(InputLayout* inputLayout) = 0; virtual void setPrimitiveTopology(PrimitiveTopology topology) = 0; - + virtual void setBindingState(BindingState * state) = 0; virtual void setVertexBuffers(UInt startSlot, UInt slotCount, Buffer* const* buffers, UInt const* strides, UInt const* offsets) = 0; inline void setVertexBuffer(UInt slot, Buffer* buffer, UInt stride, UInt offset = 0) diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp new file mode 100644 index 000000000..c97028441 --- /dev/null +++ b/tools/render-test/shader-input-layout.cpp @@ -0,0 +1,180 @@ +#include "shader-input-layout.h" +#include "core/token-reader.h" + +namespace renderer_test +{ + using namespace Slang; + void ShaderInputLayout::Parse(const char * source) + { + entries.Clear(); + auto lines = Split(source, '\n'); + for (auto & line : lines) + { + if (line.StartsWith("//TEST_INPUT:")) + { + auto lineContent = line.SubString(13, line.Length() - 13); + TokenReader parser(lineContent); + try + { + ShaderInputLayoutEntry entry; + + if (parser.LookAhead("cbuffer")) + { + entry.type = ShaderInputType::Buffer; + entry.bufferDesc.type = InputBufferType::ConstantBuffer; + } + else if (parser.LookAhead("ubuffer")) + { + entry.type = ShaderInputType::Buffer; + entry.bufferDesc.type = InputBufferType::StorageBuffer; + } + else if (parser.LookAhead("Texture1D")) + { + entry.type = ShaderInputType::Texture; + entry.textureDesc.dimension = 1; + } + else if (parser.LookAhead("Texture2D")) + { + entry.type = ShaderInputType::Texture; + entry.textureDesc.dimension = 2; + } + else if (parser.LookAhead("Texture3D")) + { + entry.type = ShaderInputType::Texture; + entry.textureDesc.dimension = 3; + } + else if (parser.LookAhead("TextureCube")) + { + entry.type = ShaderInputType::Texture; + entry.textureDesc.dimension = 2; + entry.textureDesc.isCube = true; + } + else if (parser.LookAhead("Sampler")) + { + entry.type = ShaderInputType::Sampler; + } + else if (parser.LookAhead("Sampler1D")) + { + entry.type = ShaderInputType::CombinedTextureSampler; + entry.textureDesc.dimension = 1; + } + else if (parser.LookAhead("Sampler2D")) + { + entry.type = ShaderInputType::CombinedTextureSampler; + entry.textureDesc.dimension = 2; + } + else if (parser.LookAhead("Sampler3D")) + { + entry.type = ShaderInputType::CombinedTextureSampler; + entry.textureDesc.dimension = 3; + } + else if (parser.LookAhead("SamplerCube")) + { + entry.type = ShaderInputType::CombinedTextureSampler; + entry.textureDesc.dimension = 2; + entry.textureDesc.isCube = true; + } + parser.ReadToken(); + // parse options + if (parser.LookAhead("(")) + { + parser.Read("("); + while (!parser.IsEnd() && !parser.LookAhead(")")) + { + auto word = parser.ReadWord(); + if (word == "depth") + { + entry.textureDesc.isDepthTexture = true; + } + else if (word == "depthCompare") + { + entry.samplerDesc.isCompareSampler = true; + } + else if (word == "arrayLength") + { + parser.Read("="); + entry.textureDesc.arrayLength = parser.ReadInt(); + } + else if (word == "stride") + { + parser.Read("="); + entry.bufferDesc.stride = parser.ReadInt(); + } + else if (word == "data") + { + parser.Read("="); + parser.Read("["); + while (!parser.IsEnd() && !parser.LookAhead("]")) + { + if (parser.NextToken().Type == TokenType::IntLiteral) + { + entry.bufferData.Add(parser.ReadUInt()); + } + else + { + auto floatNum = parser.ReadFloat(); + entry.bufferData.Add(*(unsigned int*)&floatNum); + } + } + parser.Read("]"); + } + if (parser.LookAhead(",")) + parser.Read(","); + else + break; + } + parser.Read(")"); + // parse bindings + if (parser.LookAhead(":")) + { + parser.Read(":"); + while (!parser.IsEnd()) + { + if (parser.LookAhead("register")) + { + parser.ReadToken(); + parser.Read("("); + auto reg = parser.ReadWord(); + entry.hlslRegister = parser.ReadInt(); + parser.Read(")"); + } + else if (parser.LookAhead("layout")) + { + parser.ReadToken(); + parser.Read("("); + while (!parser.IsEnd() && !parser.LookAhead(")")) + { + auto word = parser.ReadWord(); + if (word == "binding") + { + parser.Read("="); + entry.glslBinding = parser.ReadInt(); + } + else if (word == "location") + { + parser.Read("="); + entry.glslLocation = parser.ReadInt(); + } + if (parser.LookAhead(",")) + parser.Read(","); + else + break; + } + parser.Read(")"); + } + if (parser.LookAhead(",")) + parser.Read(","); + } + } + } + } + catch (TextFormatException) + { + throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line); + } + } + } + + + } +}
\ No newline at end of file diff --git a/tools/render-test/shader-input-layout.h b/tools/render-test/shader-input-layout.h new file mode 100644 index 000000000..788a72224 --- /dev/null +++ b/tools/render-test/shader-input-layout.h @@ -0,0 +1,52 @@ +#ifndef SLANG_TEST_SHADER_INPUT_LAYOUT_H +#define SLANG_TEST_SHADER_INPUT_LAYOUT_H + +#include "core/basic.h" + +namespace renderer_test +{ + enum class ShaderInputType + { + Buffer, Texture, Sampler, CombinedTextureSampler + }; + struct InputTextureDesc + { + int dimension = 2; + int arrayLength = 0; + bool isCube = false; + bool isDepthTexture = false; + }; + enum class InputBufferType + { + ConstantBuffer, StorageBuffer + }; + struct InputBufferDesc + { + InputBufferType type = InputBufferType::ConstantBuffer; + int stride = 0; // stride == 0 indicates an unstructured buffer. + }; + struct InputSamplerDesc + { + bool isCompareSampler = false; + }; + class ShaderInputLayoutEntry + { + public: + ShaderInputType type; + Slang::List<unsigned int> bufferData; + InputTextureDesc textureDesc; + InputBufferDesc bufferDesc; + InputSamplerDesc samplerDesc; + int hlslRegister = -1; + int glslBinding = -1; + int glslLocation = -1; + }; + class ShaderInputLayout + { + public: + Slang::List<ShaderInputLayoutEntry> entries; + void Parse(const char * source); + }; +} + +#endif
\ No newline at end of file diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp index fb10d46f6..181c34b00 100644 --- a/tools/slang-test/main.cpp +++ b/tools/slang-test/main.cpp @@ -1,6 +1,7 @@ // main.cpp #include "../../source/core/slang-io.h" +#include "../../source/core/token-reader.h" using namespace Slang; @@ -20,7 +21,6 @@ using namespace Slang; #include <stdio.h> #include <stdlib.h> #include <stdarg.h> - enum OutputMode { // Default mode is to write test results to the console @@ -1145,7 +1145,7 @@ TestResult doComputeComparisonTestRunImpl(TestInput& input, const char * langOpt auto referenceProgramOutput = Split(File::ReadAllText(referenceOutput), '\n'); if (actualProgramOutput.Count() < referenceProgramOutput.Count()) return kTestResult_Fail; - for (int i = 0; i < referenceProgramOutput.Count(); i++) + for (int i = 0; i < (int)referenceProgramOutput.Count(); i++) { auto reference = StringToFloat(referenceProgramOutput[i]); auto actual = StringToFloat(actualProgramOutput[i]); |
