blob: 4b8810430723de521c718e4b15d9f69fb807f33c [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SKSL_PARSER
#define SKSL_PARSER
#include <vector>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include "include/private/SkSLLayout.h"
#include "src/sksl/SkSLASTFile.h"
#include "src/sksl/SkSLASTNode.h"
#include "src/sksl/SkSLErrorReporter.h"
#include "src/sksl/SkSLLexer.h"
namespace SkSL {
struct Modifiers;
class SymbolTable;
/**
* Consumes .sksl text and produces an abstract syntax tree describing the contents.
*/
class Parser {
public:
enum class LayoutToken {
LOCATION,
OFFSET,
BINDING,
INDEX,
SET,
BUILTIN,
INPUT_ATTACHMENT_INDEX,
ORIGIN_UPPER_LEFT,
BLEND_SUPPORT_ALL_EQUATIONS,
PUSH_CONSTANT,
POINTS,
LINES,
LINE_STRIP,
LINES_ADJACENCY,
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLES_ADJACENCY,
MAX_VERTICES,
INVOCATIONS,
SRGB_UNPREMUL,
};
Parser(skstd::string_view text, SymbolTable& symbols, ErrorReporter& errors);
/**
* Consumes a complete .sksl file and returns the parse tree. Errors are reported via the
* ErrorReporter; the return value may contain some declarations even when errors have occurred.
*/
std::unique_ptr<ASTFile> compilationUnit();
skstd::string_view text(Token token);
Position position(Token token);
private:
static void InitLayoutMap();
/**
* Return the next token, including whitespace tokens, from the parse stream.
*/
Token nextRawToken();
/**
* Return the next non-whitespace token from the parse stream.
*/
Token nextToken();
/**
* Push a token back onto the parse stream, so that it is the next one read. Only a single level
* of pushback is supported (that is, it is an error to call pushback() twice in a row without
* an intervening nextToken()).
*/
void pushback(Token t);
/**
* Returns the next non-whitespace token without consuming it from the stream.
*/
Token peek();
/**
* Checks to see if the next token is of the specified type. If so, stores it in result (if
* result is non-null) and returns true. Otherwise, pushes it back and returns false.
*/
bool checkNext(Token::Kind kind, Token* result = nullptr);
/**
* Reads the next non-whitespace token and generates an error if it is not the expected type.
* The 'expected' string is part of the error message, which reads:
*
* "expected <expected>, but found '<actual text>'"
*
* If 'result' is non-null, it is set to point to the token that was read.
* Returns true if the read token was as expected, false otherwise.
*/
bool expect(Token::Kind kind, const char* expected, Token* result = nullptr);
bool expect(Token::Kind kind, String expected, Token* result = nullptr);
/**
* Behaves like expect(TK_IDENTIFIER), but also verifies that identifier is not a type.
* If the token was actually a type, generates an error message of the form:
*
* "expected an identifier, but found type 'float2'"
*/
bool expectIdentifier(Token* result);
void error(Token token, String msg);
void error(int offset, String msg);
/**
* Returns true if the 'name' identifier refers to a type name. For instance, isType("int") will
* always return true.
*/
bool isType(skstd::string_view name);
/**
* Returns true if the passed-in ASTNode is an array type, or false if it is a non-arrayed type.
*/
bool isArrayType(ASTNode::ID type);
// The pointer to the node may be invalidated by modifying the fNodes vector
ASTNode& getNode(ASTNode::ID id) {
SkASSERT(id.fValue >= 0 && id.fValue < (int) fFile->fNodes.size());
return fFile->fNodes[id.fValue];
}
// these functions parse individual grammar rules from the current parse position; you probably
// don't need to call any of these outside of the parser. The function declarations in the .cpp
// file have comments describing the grammar rules.
ASTNode::ID precision();
ASTNode::ID directive();
ASTNode::ID declaration();
ASTNode::ID functionDeclarationEnd(Modifiers modifiers, ASTNode::ID type, const Token& name);
struct VarDeclarationsPrefix {
Modifiers modifiers;
ASTNode::ID type;
Token name;
};
bool varDeclarationsPrefix(VarDeclarationsPrefix* prefixData);
ASTNode::ID varDeclarationsOrExpressionStatement();
ASTNode::ID varDeclarations();
ASTNode::ID structDeclaration();
ASTNode::ID structVarDeclaration(Modifiers modifiers);
ASTNode::ID varDeclarationEnd(Modifiers modifiers, ASTNode::ID type, skstd::string_view name);
ASTNode::ID parameter();
int layoutInt();
skstd::string_view layoutIdentifier();
Layout layout();
Modifiers modifiers();
Modifiers modifiersWithDefaults(int defaultFlags);
ASTNode::ID statement();
ASTNode::ID type();
ASTNode::ID interfaceBlock(Modifiers mods);
ASTNode::ID ifStatement();
ASTNode::ID doStatement();
ASTNode::ID whileStatement();
ASTNode::ID forStatement();
ASTNode::ID switchCase();
ASTNode::ID switchStatement();
ASTNode::ID returnStatement();
ASTNode::ID breakStatement();
ASTNode::ID continueStatement();
ASTNode::ID discardStatement();
ASTNode::ID block();
ASTNode::ID expressionStatement();
ASTNode::ID expression();
ASTNode::ID assignmentExpression();
ASTNode::ID ternaryExpression();
ASTNode::ID logicalOrExpression();
ASTNode::ID logicalXorExpression();
ASTNode::ID logicalAndExpression();
ASTNode::ID bitwiseOrExpression();
ASTNode::ID bitwiseXorExpression();
ASTNode::ID bitwiseAndExpression();
ASTNode::ID equalityExpression();
ASTNode::ID relationalExpression();
ASTNode::ID shiftExpression();
ASTNode::ID additiveExpression();
ASTNode::ID multiplicativeExpression();
ASTNode::ID unaryExpression();
ASTNode::ID postfixExpression();
ASTNode::ID suffix(ASTNode::ID base);
ASTNode::ID term();
bool intLiteral(SKSL_INT* dest);
bool floatLiteral(SKSL_FLOAT* dest);
bool boolLiteral(bool* dest);
bool identifier(skstd::string_view* dest);
template <typename... Args> ASTNode::ID createNode(Args&&... args);
ASTNode::ID addChild(ASTNode::ID target, ASTNode::ID child);
void createEmptyChild(ASTNode::ID target);
class Checkpoint {
public:
Checkpoint(Parser* p) : fParser(p) {
fPushbackCheckpoint = fParser->fPushback;
fLexerCheckpoint = fParser->fLexer.getCheckpoint();
fASTCheckpoint = fParser->fFile->fNodes.size();
fErrorCount = fParser->fErrors.errorCount();
}
void rewind() {
fParser->fPushback = fPushbackCheckpoint;
fParser->fLexer.rewindToCheckpoint(fLexerCheckpoint);
fParser->fFile->fNodes.resize(fASTCheckpoint);
fParser->fErrors.setErrorCount(fErrorCount);
}
private:
Parser* fParser;
Token fPushbackCheckpoint;
int32_t fLexerCheckpoint;
size_t fASTCheckpoint;
int fErrorCount;
};
static std::unordered_map<String, LayoutToken>* layoutTokens;
skstd::string_view fText;
Lexer fLexer;
// current parse depth, used to enforce a recursion limit to try to keep us from overflowing the
// stack on pathological inputs
int fDepth = 0;
Token fPushback;
SymbolTable& fSymbols;
ErrorReporter& fErrors;
std::unique_ptr<ASTFile> fFile;
friend class AutoDepth;
friend class HCodeGenerator;
};
} // namespace SkSL
#endif