mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 21:07:59 +03:00
moddable post-processing pipeline
This commit is contained in:
parent
e7fb8b6fd8
commit
04843fed6d
130 changed files with 8645 additions and 608 deletions
301
components/fx/lexer.cpp
Normal file
301
components/fx/lexer.cpp
Normal file
|
@ -0,0 +1,301 @@
|
|||
#include "lexer.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <exception>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace Lexer
|
||||
{
|
||||
Lexer::Lexer(std::string_view buffer)
|
||||
: mHead(buffer.data())
|
||||
, mTail(mHead + buffer.length())
|
||||
, mAbsolutePos(0)
|
||||
, mColumn(0)
|
||||
, mLine(0)
|
||||
, mBuffer(buffer)
|
||||
, mLastToken(Eof{})
|
||||
{ }
|
||||
|
||||
Token Lexer::next()
|
||||
{
|
||||
if (mLookahead)
|
||||
{
|
||||
auto token = *mLookahead;
|
||||
drop();
|
||||
return token;
|
||||
}
|
||||
|
||||
mLastToken = scanToken();
|
||||
|
||||
return mLastToken;
|
||||
}
|
||||
|
||||
Token Lexer::peek()
|
||||
{
|
||||
if (!mLookahead)
|
||||
mLookahead = scanToken();
|
||||
|
||||
return *mLookahead;
|
||||
}
|
||||
|
||||
void Lexer::drop()
|
||||
{
|
||||
mLookahead = std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string_view> Lexer::jump()
|
||||
{
|
||||
bool multi = false;
|
||||
bool single = false;
|
||||
auto start = mHead;
|
||||
std::size_t level = 1;
|
||||
|
||||
mLastJumpBlock.line = mLine;
|
||||
|
||||
if (head() == '}')
|
||||
{
|
||||
mLastJumpBlock.content = {};
|
||||
return mLastJumpBlock.content;
|
||||
}
|
||||
|
||||
for (; mHead != mTail; advance())
|
||||
{
|
||||
if (head() == '\n')
|
||||
{
|
||||
mLine++;
|
||||
mColumn = 0;
|
||||
if (single)
|
||||
{
|
||||
single = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (multi && head() == '*' && peekChar('/'))
|
||||
{
|
||||
multi = false;
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
else if (multi || single)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (head() == '/' && peekChar('/'))
|
||||
{
|
||||
single = true;
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
else if (head() == '/' && peekChar('*'))
|
||||
{
|
||||
multi = true;
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (head() == '{')
|
||||
level++;
|
||||
else if (head() == '}')
|
||||
level--;
|
||||
|
||||
if (level == 0)
|
||||
{
|
||||
mHead--;
|
||||
auto sv = std::string_view{start, static_cast<std::string_view::size_type>(mHead + 1 - start)};
|
||||
mLastJumpBlock.content = sv;
|
||||
return sv;
|
||||
}
|
||||
}
|
||||
|
||||
mLastJumpBlock = {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Lexer::Block Lexer::getLastJumpBlock() const
|
||||
{
|
||||
return mLastJumpBlock;
|
||||
}
|
||||
|
||||
[[noreturn]] void Lexer::error(const std::string& msg)
|
||||
{
|
||||
throw LexerException(Misc::StringUtils::format("Line %zu Col %zu. %s", mLine + 1, mColumn, msg));
|
||||
}
|
||||
|
||||
void Lexer::advance()
|
||||
{
|
||||
mAbsolutePos++;
|
||||
mHead++;
|
||||
mColumn++;
|
||||
}
|
||||
|
||||
char Lexer::head()
|
||||
{
|
||||
return *mHead;
|
||||
}
|
||||
|
||||
bool Lexer::peekChar(char c)
|
||||
{
|
||||
if (mHead == mTail)
|
||||
return false;
|
||||
return *(mHead + 1) == c;
|
||||
}
|
||||
|
||||
Token Lexer::scanToken()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (mHead == mTail)
|
||||
return {Eof{}};
|
||||
|
||||
if (head() == '\n')
|
||||
{
|
||||
mLine++;
|
||||
mColumn = 0;
|
||||
}
|
||||
|
||||
if (!std::isspace(head()))
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (head() == '\"')
|
||||
return scanStringLiteral();
|
||||
|
||||
if (std::isalpha(head()))
|
||||
return scanLiteral();
|
||||
|
||||
if (std::isdigit(head()) || head() == '.' || head() == '-')
|
||||
return scanNumber();
|
||||
|
||||
switch(head())
|
||||
{
|
||||
case '=':
|
||||
advance();
|
||||
return {Equal{}};
|
||||
case '{':
|
||||
advance();
|
||||
return {Open_bracket{}};
|
||||
case '}':
|
||||
advance();
|
||||
return {Close_bracket{}};
|
||||
case '(':
|
||||
advance();
|
||||
return {Open_Parenthesis{}};
|
||||
case ')':
|
||||
advance();
|
||||
return {Close_Parenthesis{}};
|
||||
case '\"':
|
||||
advance();
|
||||
return {Quote{}};
|
||||
case ':':
|
||||
advance();
|
||||
return {Colon{}};
|
||||
case ';':
|
||||
advance();
|
||||
return {SemiColon{}};
|
||||
case '|':
|
||||
advance();
|
||||
return {VBar{}};
|
||||
case ',':
|
||||
advance();
|
||||
return {Comma{}};
|
||||
default:
|
||||
error(Misc::StringUtils::format("unexpected token <%c>", head()));
|
||||
}
|
||||
}
|
||||
|
||||
Token Lexer::scanLiteral()
|
||||
{
|
||||
auto start = mHead;
|
||||
advance();
|
||||
|
||||
while (mHead != mTail && (std::isalnum(head()) || head() == '_'))
|
||||
advance();
|
||||
|
||||
std::string_view value{start, static_cast<std::string_view::size_type>(mHead - start)};
|
||||
|
||||
if (value == "shared") return Shared{};
|
||||
if (value == "technique") return Technique{};
|
||||
if (value == "main_pass") return Main_Pass{};
|
||||
if (value == "render_target") return Render_Target{};
|
||||
if (value == "vertex") return Vertex{};
|
||||
if (value == "fragment") return Fragment{};
|
||||
if (value == "compute") return Compute{};
|
||||
if (value == "sampler_1d") return Sampler_1D{};
|
||||
if (value == "sampler_2d") return Sampler_2D{};
|
||||
if (value == "sampler_3d") return Sampler_3D{};
|
||||
if (value == "uniform_bool") return Uniform_Bool{};
|
||||
if (value == "uniform_float") return Uniform_Float{};
|
||||
if (value == "uniform_int") return Uniform_Int{};
|
||||
if (value == "uniform_vec2") return Uniform_Vec2{};
|
||||
if (value == "uniform_vec3") return Uniform_Vec3{};
|
||||
if (value == "uniform_vec4") return Uniform_Vec4{};
|
||||
if (value == "true") return True{};
|
||||
if (value == "false") return False{};
|
||||
if (value == "vec2") return Vec2{};
|
||||
if (value == "vec3") return Vec3{};
|
||||
if (value == "vec4") return Vec4{};
|
||||
|
||||
return Literal{value};
|
||||
}
|
||||
|
||||
Token Lexer::scanStringLiteral()
|
||||
{
|
||||
advance(); // consume quote
|
||||
auto start = mHead;
|
||||
|
||||
bool terminated = false;
|
||||
|
||||
for (; mHead != mTail; advance())
|
||||
{
|
||||
if (head() == '\"')
|
||||
{
|
||||
terminated = true;
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!terminated)
|
||||
error("unterminated string");
|
||||
|
||||
return String{{start, static_cast<std::string_view::size_type>(mHead - start - 1)}};
|
||||
}
|
||||
|
||||
Token Lexer::scanNumber()
|
||||
{
|
||||
double buffer;
|
||||
|
||||
char* endPtr;
|
||||
buffer = std::strtod(mHead, &endPtr);
|
||||
|
||||
if (endPtr == nullptr)
|
||||
error("critical error while parsing number");
|
||||
|
||||
const char* tmp = mHead;
|
||||
mHead = endPtr;
|
||||
|
||||
for (; tmp != endPtr; ++tmp)
|
||||
{
|
||||
if ((*tmp == '.'))
|
||||
return Float{static_cast<float>(buffer)};
|
||||
}
|
||||
|
||||
return Integer{static_cast<int>(buffer)};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue