Initial shaderlang commit
This commit is contained in:
parent
d59423afca
commit
9a0f201433
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Renderer module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADER_LANGLEXER_HPP
|
||||||
|
#define NAZARA_SHADER_LANGLEXER_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Shader/Config.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Nz::ShaderLang
|
||||||
|
{
|
||||||
|
enum class TokenType
|
||||||
|
{
|
||||||
|
#define NAZARA_SHADERLANG_TOKEN(X) X,
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangTokenList.hpp>
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
unsigned int column;
|
||||||
|
unsigned int line;
|
||||||
|
TokenType type;
|
||||||
|
std::variant<double, long long, std::string> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BadNumber : public std::exception
|
||||||
|
{
|
||||||
|
using exception::exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NumberOutOfRange : public std::exception
|
||||||
|
{
|
||||||
|
using exception::exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnrecognizedToken : public std::exception
|
||||||
|
{
|
||||||
|
using exception::exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAZARA_SHADER_API std::vector<Token> Tokenize(const std::string_view& str);
|
||||||
|
NAZARA_SHADER_API const char* ToString(TokenType tokenType);
|
||||||
|
NAZARA_SHADER_API std::string ToString(const std::vector<Token>& tokens, bool pretty = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangLexer.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Shader generator"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangLexer.hpp>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Renderer module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADER_LANGPARSER_HPP
|
||||||
|
#define NAZARA_SHADER_LANGPARSER_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Shader/Config.hpp>
|
||||||
|
#include <Nazara/Shader/ShaderLangLexer.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderLang
|
||||||
|
{
|
||||||
|
class ExpectedToken : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using exception::exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnexpectedToken : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using exception::exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NAZARA_SHADER_API Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Parser();
|
||||||
|
~Parser() = default;
|
||||||
|
|
||||||
|
void Parse(const std::vector<Token>& tokens);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Token& Advance();
|
||||||
|
void Expect(const Token& token, TokenType type);
|
||||||
|
void ExpectNext(TokenType type);
|
||||||
|
void ParseFunctionBody();
|
||||||
|
void ParseFunctionDeclaration();
|
||||||
|
void ParseFunctionParameter();
|
||||||
|
const Token& PeekNext();
|
||||||
|
|
||||||
|
struct Context
|
||||||
|
{
|
||||||
|
std::size_t tokenCount;
|
||||||
|
std::size_t tokenIndex = 0;
|
||||||
|
const Token* tokens;
|
||||||
|
};
|
||||||
|
|
||||||
|
Context* m_context;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangParser.inl>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Shader generator"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangParser.hpp>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderLang
|
||||||
|
{
|
||||||
|
inline Parser::Parser() :
|
||||||
|
m_context(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/DebugOff.hpp>
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Renderer module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#if !defined(NAZARA_SHADERLANG_TOKEN)
|
||||||
|
#error You must define NAZARA_SHADERLANG_TOKEN before including this file
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADERLANG_TOKENT_LAST
|
||||||
|
#define NAZARA_SHADERLANG_TOKEN_LAST(X) NAZARA_SHADERLANG_TOKEN(X)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Add)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(BoolFalse)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(BoolTrue)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(ClosingParenthesis)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(ClosingCurlyBracket)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Colon)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Comma)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Divide)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Dot)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(FloatingPointValue)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(EndOfStream)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(FunctionDeclaration)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(FunctionReturn)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(IntegerValue)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Identifier)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Multiply)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(OpenCurlyBracket)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(OpenParenthesis)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Semicolon)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Return)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(Subtract)
|
||||||
|
|
||||||
|
#undef NAZARA_SHADERLANG_TOKEN
|
||||||
|
#undef NAZARA_SHADERLANG_TOKEN_LAST
|
||||||
|
|
@ -0,0 +1,327 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Shader generator"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangLexer.hpp>
|
||||||
|
#include <cctype>
|
||||||
|
#include <charconv>
|
||||||
|
#include <locale>
|
||||||
|
#include <optional>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderLang
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class ForceCLocale
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ForceCLocale()
|
||||||
|
{
|
||||||
|
m_previousLocale = std::locale::global(std::locale::classic());
|
||||||
|
}
|
||||||
|
|
||||||
|
~ForceCLocale()
|
||||||
|
{
|
||||||
|
std::locale::global(m_previousLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::locale m_previousLocale;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Token> Tokenize(const std::string_view& str)
|
||||||
|
{
|
||||||
|
// Can't use std::from_chars for double thanks to libc++ and libstdc++ developers being lazy
|
||||||
|
ForceCLocale forceCLocale;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, TokenType> reservedKeywords = {
|
||||||
|
{ "false", TokenType::BoolFalse },
|
||||||
|
{ "fn", TokenType::FunctionDeclaration },
|
||||||
|
{ "return", TokenType::Return },
|
||||||
|
{ "true", TokenType::BoolTrue }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t currentPos = 0;
|
||||||
|
|
||||||
|
auto Peek = [&](std::size_t advance = 1) -> char
|
||||||
|
{
|
||||||
|
if (currentPos + advance < str.size())
|
||||||
|
return str[currentPos + advance];
|
||||||
|
else
|
||||||
|
return char(-1);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto IsAlphaNum = [&](const char c)
|
||||||
|
{
|
||||||
|
return std::isalnum(c) || c == '_';
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int lineNumber = 0;
|
||||||
|
std::size_t lastLineFeed = 0;
|
||||||
|
std::vector<Token> tokens;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
char c = Peek(0);
|
||||||
|
|
||||||
|
Token token;
|
||||||
|
token.column = currentPos - lastLineFeed;
|
||||||
|
token.line = lineNumber;
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
token.type = TokenType::EndOfStream;
|
||||||
|
tokens.push_back(std::move(token));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<TokenType> tokenType;
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
break; //< Ignore blank spaces
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
{
|
||||||
|
lineNumber++;
|
||||||
|
lastLineFeed = currentPos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
{
|
||||||
|
if (Peek() == '>')
|
||||||
|
{
|
||||||
|
tokenType = TokenType::FunctionReturn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenType = TokenType::Subtract;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
{
|
||||||
|
char next = Peek();
|
||||||
|
if (next == '/')
|
||||||
|
{
|
||||||
|
// Line comment
|
||||||
|
do
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
next = Peek();
|
||||||
|
}
|
||||||
|
while (next != -1 && next != '\n');
|
||||||
|
}
|
||||||
|
else if (next == '*')
|
||||||
|
{
|
||||||
|
// Block comment
|
||||||
|
do
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
next = Peek();
|
||||||
|
|
||||||
|
if (next == '*')
|
||||||
|
{
|
||||||
|
currentPos++;
|
||||||
|
if (Peek() == '/')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (next == '\n')
|
||||||
|
{
|
||||||
|
lineNumber++;
|
||||||
|
lastLineFeed = currentPos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (next != -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType == TokenType::Divide;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
{
|
||||||
|
bool floatingPoint = false;
|
||||||
|
|
||||||
|
std::size_t start = currentPos;
|
||||||
|
char next = Peek();
|
||||||
|
|
||||||
|
if (next == 'x' || next == 'X')
|
||||||
|
currentPos++;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
next = Peek();
|
||||||
|
|
||||||
|
if (!isdigit(next))
|
||||||
|
{
|
||||||
|
if (next != '.')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (floatingPoint)
|
||||||
|
break;
|
||||||
|
|
||||||
|
floatingPoint = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (floatingPoint)
|
||||||
|
{
|
||||||
|
tokenType = TokenType::FloatingPointValue;
|
||||||
|
|
||||||
|
std::string valueStr(str.substr(start, currentPos - start + 1));
|
||||||
|
|
||||||
|
char* end;
|
||||||
|
double value = std::strtod(valueStr.c_str(), &end);
|
||||||
|
if (end != &str[currentPos])
|
||||||
|
throw BadNumber{};
|
||||||
|
|
||||||
|
token.data = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tokenType = TokenType::IntegerValue;
|
||||||
|
|
||||||
|
long long value;
|
||||||
|
std::from_chars_result r = std::from_chars(&str[start], &str[currentPos + 1], value);
|
||||||
|
if (r.ptr != &str[currentPos])
|
||||||
|
{
|
||||||
|
if (r.ec == std::errc::result_out_of_range)
|
||||||
|
throw NumberOutOfRange{};
|
||||||
|
|
||||||
|
throw BadNumber{};
|
||||||
|
}
|
||||||
|
|
||||||
|
token.data = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '+': tokenType = TokenType::Add; break;
|
||||||
|
case '*': tokenType = TokenType::Multiply; break;
|
||||||
|
case ':': tokenType = TokenType::Colon; break;
|
||||||
|
case ';': tokenType = TokenType::Semicolon; break;
|
||||||
|
case '.': tokenType = TokenType::Dot; break;
|
||||||
|
case ',': tokenType = TokenType::Comma; break;
|
||||||
|
case '{': tokenType = TokenType::OpenCurlyBracket; break;
|
||||||
|
case '}': tokenType = TokenType::ClosingCurlyBracket; break;
|
||||||
|
case '(': tokenType = TokenType::OpenParenthesis; break;
|
||||||
|
case ')': tokenType = TokenType::ClosingParenthesis; break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenType)
|
||||||
|
{
|
||||||
|
if (IsAlphaNum(c))
|
||||||
|
{
|
||||||
|
std::size_t start = currentPos;
|
||||||
|
|
||||||
|
while (IsAlphaNum(Peek()))
|
||||||
|
currentPos++;
|
||||||
|
|
||||||
|
std::string identifier(str.substr(start, currentPos - start + 1));
|
||||||
|
if (auto it = reservedKeywords.find(identifier); it == reservedKeywords.end())
|
||||||
|
{
|
||||||
|
tokenType = TokenType::Identifier;
|
||||||
|
token.data = std::move(identifier);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tokenType = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenType)
|
||||||
|
{
|
||||||
|
token.type = *tokenType;
|
||||||
|
|
||||||
|
tokens.push_back(std::move(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ToString(TokenType tokenType)
|
||||||
|
{
|
||||||
|
switch (tokenType)
|
||||||
|
{
|
||||||
|
#define NAZARA_SHADERLANG_TOKEN(X) case TokenType:: X: return #X;
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangTokenList.hpp>
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<Error>";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString(const std::vector<Token>& tokens, bool pretty)
|
||||||
|
{
|
||||||
|
if (tokens.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
unsigned int lastLineNumber = tokens.front().line;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
bool empty = true;
|
||||||
|
|
||||||
|
for (const Token& token : tokens)
|
||||||
|
{
|
||||||
|
if (token.line != lastLineNumber && pretty)
|
||||||
|
{
|
||||||
|
lastLineNumber = token.line;
|
||||||
|
if (!empty)
|
||||||
|
ss << '\n';
|
||||||
|
}
|
||||||
|
else if (!empty)
|
||||||
|
ss << ' ';
|
||||||
|
|
||||||
|
ss << ToString(token.type);
|
||||||
|
switch (token.type)
|
||||||
|
{
|
||||||
|
case TokenType::FloatingPointValue:
|
||||||
|
ss << "(" << std::get<double>(token.data) << ")";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TokenType::Identifier:
|
||||||
|
ss << "(" << std::get<std::string>(token.data) << ")";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TokenType::IntegerValue:
|
||||||
|
ss << "(" << std::get<long long>(token.data) << ")";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
empty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << '\n';
|
||||||
|
|
||||||
|
return std::move(ss).str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
// Copyright (C) 2020 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Shader generator"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Shader/ShaderLangParser.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderLang
|
||||||
|
{
|
||||||
|
void Parser::Parse(const std::vector<Token>& tokens)
|
||||||
|
{
|
||||||
|
Context context;
|
||||||
|
context.tokenCount = tokens.size();
|
||||||
|
context.tokens = tokens.data();
|
||||||
|
|
||||||
|
m_context = &context;
|
||||||
|
|
||||||
|
for (const Token& token : tokens)
|
||||||
|
{
|
||||||
|
switch (token.type)
|
||||||
|
{
|
||||||
|
case TokenType::FunctionDeclaration:
|
||||||
|
ParseFunctionDeclaration();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw UnexpectedToken{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token& Parser::Advance()
|
||||||
|
{
|
||||||
|
assert(m_context->tokenIndex + 1 < m_context->tokenCount);
|
||||||
|
return m_context->tokens[++m_context->tokenIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::Expect(const Token& token, TokenType type)
|
||||||
|
{
|
||||||
|
if (token.type != type)
|
||||||
|
throw ExpectedToken{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::ExpectNext(TokenType type)
|
||||||
|
{
|
||||||
|
Expect(m_context->tokens[m_context->tokenIndex + 1], type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::ParseFunctionBody()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::ParseFunctionDeclaration()
|
||||||
|
{
|
||||||
|
ExpectNext(TokenType::Identifier);
|
||||||
|
|
||||||
|
std::string functionName = std::get<std::string>(Advance().data);
|
||||||
|
|
||||||
|
ExpectNext(TokenType::OpenParenthesis);
|
||||||
|
Advance();
|
||||||
|
|
||||||
|
bool firstParameter = true;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const Token& t = PeekNext();
|
||||||
|
if (t.type == TokenType::ClosingParenthesis)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!firstParameter)
|
||||||
|
{
|
||||||
|
Expect(t, TokenType::Comma);
|
||||||
|
Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseFunctionParameter();
|
||||||
|
firstParameter = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpectNext(TokenType::ClosingParenthesis);
|
||||||
|
Advance();
|
||||||
|
|
||||||
|
if (PeekNext().type == TokenType::FunctionReturn)
|
||||||
|
{
|
||||||
|
Advance();
|
||||||
|
|
||||||
|
std::string returnType = std::get<std::string>(Advance().data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ExpectNext(TokenType::OpenCurlyBracket);
|
||||||
|
Advance();
|
||||||
|
|
||||||
|
ParseFunctionBody();
|
||||||
|
|
||||||
|
ExpectNext(TokenType::ClosingCurlyBracket);
|
||||||
|
Advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::ParseFunctionParameter()
|
||||||
|
{
|
||||||
|
ExpectNext(TokenType::Identifier);
|
||||||
|
std::string parameterName = std::get<std::string>(Advance().data);
|
||||||
|
|
||||||
|
ExpectNext(TokenType::Colon);
|
||||||
|
Advance();
|
||||||
|
|
||||||
|
ExpectNext(TokenType::Identifier);
|
||||||
|
std::string parameterType = std::get<std::string>(Advance().data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token& Parser::PeekNext()
|
||||||
|
{
|
||||||
|
assert(m_context->tokenIndex + 1 < m_context->tokenCount);
|
||||||
|
return m_context->tokens[m_context->tokenIndex + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue