blob: bbde9fe4f8bc4b1e2c35b05909c511fe47b22c1b [file] [log] [blame]
/*
* Copyright (C) 2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if ENABLE(WEBGPU)
#include <wtf/Optional.h>
#include <wtf/Vector.h>
#include <wtf/text/StringConcatenate.h>
#include <wtf/text/StringConcatenateNumbers.h>
#include <wtf/text/StringView.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
namespace WHLSL {
class Lexer {
public:
Lexer() = default;
Lexer(StringView stringView)
: m_stringView(stringView)
{
skipWhitespaceAndComments();
m_ringBuffer[0] = consumeTokenFromStream();
m_ringBuffer[1] = consumeTokenFromStream();
}
Lexer(const Lexer&) = delete;
Lexer(Lexer&&) = default;
Lexer& operator=(const Lexer&) = delete;
Lexer& operator=(Lexer&&) = default;
struct Token {
Token() = delete;
Token(const Token&) = default;
Token(Token&&) = default;
Token& operator=(const Token&) = default;
Token& operator=(Token&&) = default;
StringView stringView;
unsigned lineNumber;
enum class Type {
IntLiteral,
UintLiteral,
FloatLiteral,
Struct,
Typedef,
Enum,
Operator,
If,
Else,
Continue,
Break,
Switch,
Case,
Default,
Fallthrough,
For,
While,
Do,
Return,
Trap,
Null,
True,
False,
Constant,
Device,
Threadgroup,
Thread,
Space,
Vertex,
Fragment,
Compute,
NumThreads,
SVInstanceID,
SVVertexID,
PSize,
SVPosition,
SVIsFrontFace,
SVSampleIndex,
SVInnerCoverage,
SVTarget,
SVDepth,
SVCoverage,
SVDispatchThreadID,
SVGroupID,
SVGroupIndex,
SVGroupThreadID,
Attribute,
Register,
Specialized,
Native,
Restricted,
Underscore,
Auto,
Protocol,
Const,
Static,
Qualifier,
Identifier,
OperatorName,
EqualsSign,
Semicolon,
LeftCurlyBracket,
RightCurlyBracket,
Colon,
Comma,
LeftParenthesis,
RightParenthesis,
SquareBracketPair,
LeftSquareBracket,
RightSquareBracket,
Star,
LessThanSign,
GreaterThanSign,
FullStop,
PlusEquals,
MinusEquals,
TimesEquals,
DivideEquals,
ModEquals,
XorEquals,
AndEquals,
OrEquals,
RightShiftEquals,
LeftShiftEquals,
PlusPlus,
MinusMinus,
Arrow,
QuestionMark,
OrOr,
AndAnd,
Or,
Xor,
And,
LessThanOrEqualTo,
GreaterThanOrEqualTo,
EqualComparison,
NotEqual,
RightShift,
LeftShift,
Plus,
Minus,
Divide,
Mod,
Tilde,
ExclamationPoint,
At,
} type;
static const char* typeName(Type);
};
Optional<Token> consumeToken()
{
auto result = m_ringBuffer[m_ringBufferIndex];
m_ringBuffer[m_ringBufferIndex] = consumeTokenFromStream();
m_ringBufferIndex = (m_ringBufferIndex + 1) % 2;
return result;
}
Optional<Token> peek()
{
return m_ringBuffer[m_ringBufferIndex];
}
Optional<Token> peekFurther()
{
return m_ringBuffer[(m_ringBufferIndex + 1) % 2];
}
// FIXME: We should not need this
// https://bugs.webkit.org/show_bug.cgi?id=198357
struct State {
Optional<Token> ringBuffer[2];
unsigned ringBufferIndex;
unsigned offset;
unsigned lineNumber;
};
State state() const
{
State state;
state.ringBuffer[0] = m_ringBuffer[0];
state.ringBuffer[1] = m_ringBuffer[1];
state.ringBufferIndex = m_ringBufferIndex;
state.offset = m_offset;
state.lineNumber = m_lineNumber;
return state;
}
void setState(const State& state)
{
m_ringBuffer[0] = state.ringBuffer[0];
m_ringBuffer[1] = state.ringBuffer[1];
m_ringBufferIndex = state.ringBufferIndex;
m_offset = state.offset;
m_lineNumber = state.lineNumber;
}
void setState(State&& state)
{
m_ringBuffer[0] = WTFMove(state.ringBuffer[0]);
m_ringBuffer[1] = WTFMove(state.ringBuffer[1]);
m_ringBufferIndex = WTFMove(state.ringBufferIndex);
m_offset = WTFMove(state.offset);
m_lineNumber = WTFMove(state.lineNumber);
}
bool isFullyConsumed() const
{
return m_offset == m_stringView.length();
}
String errorString(const Token& token, const String& message)
{
return makeString("Parse error at line ", token.lineNumber, ": ", message);
}
private:
Optional<Token> consumeTokenFromStream();
void skipWhitespaceAndComments();
void skipWhitespace();
void skipLineComment();
void skipLongComment();
Optional<Token::Type> recognizeKeyword(unsigned end);
Optional<unsigned> coreDecimalIntLiteral(unsigned) const;
Optional<unsigned> decimalIntLiteral(unsigned) const;
Optional<unsigned> decimalUintLiteral(unsigned) const;
Optional<unsigned> coreHexadecimalIntLiteral(unsigned) const;
Optional<unsigned> hexadecimalIntLiteral(unsigned) const;
Optional<unsigned> hexadecimalUintLiteral(unsigned) const;
Optional<unsigned> intLiteral(unsigned) const;
Optional<unsigned> uintLiteral(unsigned) const;
Optional<unsigned> digit(unsigned) const;
unsigned digitStar(unsigned) const;
Optional<unsigned> character(char, unsigned) const;
template<unsigned length> Optional<unsigned> anyCharacter(const char (&string)[length], unsigned) const;
Optional<unsigned> coreFloatLiteralType1(unsigned) const;
Optional<unsigned> coreFloatLiteral(unsigned) const;
Optional<unsigned> floatLiteral(unsigned) const;
template<unsigned length> Optional<unsigned> string(const char (&string)[length], unsigned) const;
Optional<unsigned> validIdentifier(unsigned) const;
Optional<unsigned> identifier(unsigned) const;
Optional<unsigned> operatorName(unsigned) const;
StringView m_stringView;
Optional<Token> m_ringBuffer[2];
unsigned m_ringBufferIndex { 0 };
unsigned m_offset { 0 };
unsigned m_lineNumber { 0 };
};
template<unsigned length> Optional<unsigned> Lexer::string(const char (&string)[length], unsigned offset) const
{
for (unsigned i = 0; i < length - 1; ++i) {
if (offset + i >= m_stringView.length() || m_stringView[offset + i] != string[i])
return WTF::nullopt;
}
return offset + length - 1;
}
template<unsigned length> Optional<unsigned> Lexer::anyCharacter(const char (&string)[length], unsigned offset) const
{
if (offset >= m_stringView.length())
return WTF::nullopt;
for (unsigned i = 0; i < length - 1; ++i) {
if (m_stringView[offset] == string[i])
return offset + 1;
}
return WTF::nullopt;
}
} // namespace WHLSL
} // namespace WebCore
#endif // ENABLE(WEBGPU)