scriptlang: some work on parser
This commit is contained in:
parent
e187da0d8d
commit
9737d9e56f
@ -7,11 +7,13 @@ namespace scriptlang {
|
|||||||
auto constexpr Lexer::next() noexcept -> Result<Token, void>
|
auto constexpr Lexer::next() noexcept -> Result<Token, void>
|
||||||
{
|
{
|
||||||
if (done())
|
if (done())
|
||||||
return token(TokenTypes::Eof, index);
|
return token(Tokens::Eof, index);
|
||||||
if (std::isdigit(current()) != 0)
|
if (std::isdigit(current()) != 0)
|
||||||
return make_number();
|
return make_number();
|
||||||
if (std::isalpha(current()) != 0 || current() == '_')
|
if (std::isalpha(current()) != 0 or current() == '_')
|
||||||
return make_id();
|
return make_id();
|
||||||
|
if (current() == '"')
|
||||||
|
return make_string();
|
||||||
return make_static();
|
return make_static();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,12 +26,11 @@ auto constexpr Lexer::make_number() noexcept -> Result<Token, void>
|
|||||||
step();
|
step();
|
||||||
while (!done() and std::isdigit(current()) != 0)
|
while (!done() and std::isdigit(current()) != 0)
|
||||||
step();
|
step();
|
||||||
return token(TokenTypes::Float, begin);
|
return token(Tokens::Float, begin);
|
||||||
}
|
}
|
||||||
return token(TokenTypes::Int, begin);
|
return token(Tokens::Int, begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
|
||||||
auto constexpr Lexer::make_id() noexcept -> Result<Token, void>
|
auto constexpr Lexer::make_id() noexcept -> Result<Token, void>
|
||||||
{
|
{
|
||||||
auto begin = index;
|
auto begin = index;
|
||||||
@ -41,37 +42,52 @@ auto constexpr Lexer::make_id() noexcept -> Result<Token, void>
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::id_or_keyword_type(std::string_view substring) noexcept
|
auto constexpr Lexer::id_or_keyword_type(std::string_view substring) noexcept
|
||||||
-> TokenTypes
|
-> Tokens
|
||||||
{
|
{
|
||||||
if (substring.compare("if") == 0)
|
if (substring.compare("if") == 0)
|
||||||
return TokenTypes::If;
|
return Tokens::If;
|
||||||
if (substring.compare("else") == 0)
|
if (substring.compare("else") == 0)
|
||||||
return TokenTypes::Else;
|
return Tokens::Else;
|
||||||
if (substring.compare("for") == 0)
|
if (substring.compare("for") == 0)
|
||||||
return TokenTypes::For;
|
return Tokens::For;
|
||||||
if (substring.compare("loop") == 0)
|
if (substring.compare("loop") == 0)
|
||||||
return TokenTypes::Loop;
|
return Tokens::Loop;
|
||||||
if (substring.compare("while") == 0)
|
if (substring.compare("while") == 0)
|
||||||
return TokenTypes::While;
|
return Tokens::While;
|
||||||
if (substring.compare("break") == 0)
|
if (substring.compare("break") == 0)
|
||||||
return TokenTypes::Break;
|
return Tokens::Break;
|
||||||
if (substring.compare("continue") == 0)
|
if (substring.compare("continue") == 0)
|
||||||
return TokenTypes::Continue;
|
return Tokens::Continue;
|
||||||
if (substring.compare("fn") == 0)
|
if (substring.compare("fn") == 0)
|
||||||
return TokenTypes::Fn;
|
return Tokens::Fn;
|
||||||
if (substring.compare("return") == 0)
|
if (substring.compare("return") == 0)
|
||||||
return TokenTypes::Return;
|
return Tokens::Return;
|
||||||
if (substring.compare("false") == 0)
|
if (substring.compare("false") == 0)
|
||||||
return TokenTypes::False;
|
return Tokens::False;
|
||||||
if (substring.compare("true") == 0)
|
if (substring.compare("true") == 0)
|
||||||
return TokenTypes::True;
|
return Tokens::True;
|
||||||
if (substring.compare("and") == 0)
|
if (substring.compare("and") == 0)
|
||||||
return TokenTypes::And;
|
return Tokens::And;
|
||||||
if (substring.compare("or") == 0)
|
if (substring.compare("or") == 0)
|
||||||
return TokenTypes::Or;
|
return Tokens::Or;
|
||||||
if (substring.compare("xor") == 0)
|
if (substring.compare("xor") == 0)
|
||||||
return TokenTypes::Xor;
|
return Tokens::Xor;
|
||||||
return TokenTypes::Id;
|
return Tokens::Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto constexpr Lexer::make_string() noexcept -> Result<Token, void>
|
||||||
|
{
|
||||||
|
auto begin = index;
|
||||||
|
step();
|
||||||
|
auto escaped = false;
|
||||||
|
while (!done() and (current() != '"' or escaped)) {
|
||||||
|
escaped = escaped ? false : current() == '\\';
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
if (current() != '"')
|
||||||
|
return {};
|
||||||
|
step();
|
||||||
|
return token(Tokens::String, begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::make_static() noexcept -> Result<Token, void>
|
auto constexpr Lexer::make_static() noexcept -> Result<Token, void>
|
||||||
@ -84,10 +100,10 @@ auto constexpr Lexer::make_static() noexcept -> Result<Token, void>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||||
auto constexpr Lexer::static_token_type() noexcept -> Result<TokenTypes, void>
|
auto constexpr Lexer::static_token_type() noexcept -> Result<Tokens, void>
|
||||||
{
|
{
|
||||||
using TT = TokenTypes;
|
using TT = Tokens;
|
||||||
auto stepped = [&](TokenTypes v) {
|
auto stepped = [&](Tokens v) {
|
||||||
step();
|
step();
|
||||||
return v;
|
return v;
|
||||||
};
|
};
|
||||||
@ -171,8 +187,8 @@ auto constexpr Lexer::static_token_type() noexcept -> Result<TokenTypes, void>
|
|||||||
if (current() == '!') {
|
if (current() == '!') {
|
||||||
step();
|
step();
|
||||||
if (current() == '=')
|
if (current() == '=')
|
||||||
return stepped(TT::ExlamationEqual);
|
return stepped(TT::ExclamationEqual);
|
||||||
return TT::Exlamation;
|
return TT::Exclamation;
|
||||||
}
|
}
|
||||||
if (current() == '<') {
|
if (current() == '<') {
|
||||||
step();
|
step();
|
||||||
@ -189,8 +205,7 @@ auto constexpr Lexer::static_token_type() noexcept -> Result<TokenTypes, void>
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::skip_multiline_comment() noexcept
|
auto constexpr Lexer::skip_multiline_comment() noexcept -> Result<Tokens, void>
|
||||||
-> Result<TokenTypes, void>
|
|
||||||
{
|
{
|
||||||
step();
|
step();
|
||||||
auto last = current();
|
auto last = current();
|
||||||
@ -200,18 +215,17 @@ auto constexpr Lexer::skip_multiline_comment() noexcept
|
|||||||
if (last != '*' or current() != '/')
|
if (last != '*' or current() != '/')
|
||||||
return {};
|
return {};
|
||||||
step();
|
step();
|
||||||
return TokenTypes::MultilineComment;
|
return Tokens::MultilineComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::skip_singleline_comment() noexcept
|
auto constexpr Lexer::skip_singleline_comment() noexcept -> Result<Tokens, void>
|
||||||
-> Result<TokenTypes, void>
|
|
||||||
{
|
{
|
||||||
step();
|
step();
|
||||||
while (!done() and current() != '\n')
|
while (!done() and current() != '\n')
|
||||||
step();
|
step();
|
||||||
if (current() == '\n')
|
if (current() == '\n')
|
||||||
step();
|
step();
|
||||||
return TokenTypes::SinglelineComment;
|
return Tokens::SinglelineComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
namespace scriptlang {
|
namespace scriptlang {
|
||||||
|
|
||||||
enum class TokenTypes {
|
enum class Tokens {
|
||||||
Eof,
|
Eof,
|
||||||
|
|
||||||
MultilineComment,
|
MultilineComment,
|
||||||
@ -13,6 +13,7 @@ enum class TokenTypes {
|
|||||||
Id,
|
Id,
|
||||||
Int,
|
Int,
|
||||||
Float,
|
Float,
|
||||||
|
String,
|
||||||
|
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
@ -65,8 +66,8 @@ enum class TokenTypes {
|
|||||||
FatArrow,
|
FatArrow,
|
||||||
DoubleEqual,
|
DoubleEqual,
|
||||||
|
|
||||||
Exlamation,
|
Exclamation,
|
||||||
ExlamationEqual,
|
ExclamationEqual,
|
||||||
|
|
||||||
Less,
|
Less,
|
||||||
LessEqual,
|
LessEqual,
|
||||||
@ -75,12 +76,16 @@ enum class TokenTypes {
|
|||||||
GreaterEqual,
|
GreaterEqual,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token {
|
struct Location {
|
||||||
TokenTypes type;
|
|
||||||
size_t index, length;
|
|
||||||
int line, column;
|
int line, column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
Tokens type;
|
||||||
|
size_t index, length;
|
||||||
|
Location location;
|
||||||
|
};
|
||||||
|
|
||||||
class Lexer {
|
class Lexer {
|
||||||
public:
|
public:
|
||||||
Lexer(std::string_view text)
|
Lexer(std::string_view text)
|
||||||
@ -98,18 +103,17 @@ private:
|
|||||||
auto constexpr make_number() noexcept -> Result<Token, void>;
|
auto constexpr make_number() noexcept -> Result<Token, void>;
|
||||||
auto constexpr make_id() noexcept -> Result<Token, void>;
|
auto constexpr make_id() noexcept -> Result<Token, void>;
|
||||||
auto constexpr id_or_keyword_type(std::string_view substring) noexcept
|
auto constexpr id_or_keyword_type(std::string_view substring) noexcept
|
||||||
-> TokenTypes;
|
-> Tokens;
|
||||||
|
auto constexpr make_string() noexcept -> Result<Token, void>;
|
||||||
auto constexpr make_static() noexcept -> Result<Token, void>;
|
auto constexpr make_static() noexcept -> Result<Token, void>;
|
||||||
auto constexpr static_token_type() noexcept -> Result<TokenTypes, void>;
|
auto constexpr static_token_type() noexcept -> Result<Tokens, void>;
|
||||||
auto constexpr skip_multiline_comment() noexcept
|
auto constexpr skip_multiline_comment() noexcept -> Result<Tokens, void>;
|
||||||
-> Result<TokenTypes, void>;
|
auto constexpr skip_singleline_comment() noexcept -> Result<Tokens, void>;
|
||||||
auto constexpr skip_singleline_comment() noexcept
|
|
||||||
-> Result<TokenTypes, void>;
|
|
||||||
|
|
||||||
[[nodiscard]] auto constexpr inline token(
|
[[nodiscard]] auto constexpr inline token(
|
||||||
TokenTypes type, size_t begin) noexcept -> Token
|
Tokens type, size_t begin) noexcept -> Token
|
||||||
{
|
{
|
||||||
auto token = Token { type, begin, index - begin, line, column };
|
auto token = Token { type, begin, index - begin, { line, column } };
|
||||||
last_token = token;
|
last_token = token;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
|
|
||||||
namespace scriptlang { }
|
namespace scriptlang {
|
||||||
|
|
||||||
|
auto Parser::parse_value() noexcept -> Result<std::unique_ptr<Expression>, void>
|
||||||
|
{
|
||||||
|
switch (lexer.peek()->type) {
|
||||||
|
case Tokens::Id:
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,7 +1,139 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "lexer.hpp"
|
||||||
|
#include "utils/all.hpp"
|
||||||
|
#include "utils/result.hpp"
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace scriptlang {
|
namespace scriptlang {
|
||||||
|
|
||||||
class Parser final { };
|
struct Span {
|
||||||
|
Location from, to;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Expressions {
|
||||||
|
Binary,
|
||||||
|
Negate,
|
||||||
|
Not,
|
||||||
|
Index,
|
||||||
|
Access,
|
||||||
|
Call,
|
||||||
|
Operator,
|
||||||
|
|
||||||
|
Id,
|
||||||
|
Int,
|
||||||
|
Float,
|
||||||
|
Bool,
|
||||||
|
String,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Expression {
|
||||||
|
public:
|
||||||
|
Expression() = default;
|
||||||
|
Expression(const Expression&) = delete;
|
||||||
|
Expression(Expression&&) = delete;
|
||||||
|
auto operator=(const Expression&) -> Expression& = delete;
|
||||||
|
auto operator=(Expression&&) -> Expression& = delete;
|
||||||
|
virtual ~Expression() = default;
|
||||||
|
[[nodiscard]] virtual auto expression_type() const noexcept -> Expressions
|
||||||
|
= 0;
|
||||||
|
[[nodiscard]] virtual auto span() const noexcept -> Span = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
class Id final : public Expression {
|
||||||
|
public:
|
||||||
|
Id(std::string value)
|
||||||
|
: m_value { std::move(value) }
|
||||||
|
{ }
|
||||||
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
|
{
|
||||||
|
return Expressions::Id;
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_value;
|
||||||
|
};
|
||||||
|
class Int final : public Expression {
|
||||||
|
public:
|
||||||
|
Int(int64_t value)
|
||||||
|
: m_value { value }
|
||||||
|
{ }
|
||||||
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
|
{
|
||||||
|
return Expressions::Int;
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int64_t m_value;
|
||||||
|
};
|
||||||
|
class Float final : public Expression {
|
||||||
|
public:
|
||||||
|
Float(double value)
|
||||||
|
: m_value { value }
|
||||||
|
{ }
|
||||||
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
|
{
|
||||||
|
return Expressions::Float;
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
double m_value;
|
||||||
|
};
|
||||||
|
class Bool final : public Expression {
|
||||||
|
public:
|
||||||
|
Bool(bool value)
|
||||||
|
: m_value { value }
|
||||||
|
{ }
|
||||||
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
|
{
|
||||||
|
return Expressions::Bool;
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_value;
|
||||||
|
};
|
||||||
|
class String final : public Expression {
|
||||||
|
public:
|
||||||
|
String(std::string value)
|
||||||
|
: m_value { std::move(value) }
|
||||||
|
{ }
|
||||||
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
|
{
|
||||||
|
return Expressions::String;
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto value() const noexcept -> const std::string&
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Parser final {
|
||||||
|
public:
|
||||||
|
Parser(std::string_view text)
|
||||||
|
: text { text }
|
||||||
|
, lexer(text)
|
||||||
|
{ }
|
||||||
|
auto parse_expression() noexcept
|
||||||
|
-> Result<std::unique_ptr<Expression>, void>;
|
||||||
|
auto parse_value() noexcept -> Result<std::unique_ptr<Expression>, void>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string_view text;
|
||||||
|
Lexer lexer;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user