scriptlang: start on structs
This commit is contained in:
parent
83cf664271
commit
04a8fdc4c3
@ -11,6 +11,11 @@ project(
|
|||||||
fmt_dep = dependency('fmt')
|
fmt_dep = dependency('fmt')
|
||||||
sdl2_dep = dependency('sdl2')
|
sdl2_dep = dependency('sdl2')
|
||||||
|
|
||||||
|
add_project_arguments(
|
||||||
|
'-Wno-gnu-statement-expression-from-macro-expansion',
|
||||||
|
language: 'cpp',
|
||||||
|
)
|
||||||
|
|
||||||
common_sources = []
|
common_sources = []
|
||||||
subdir('utils')
|
subdir('utils')
|
||||||
subdir('scriptlang')
|
subdir('scriptlang')
|
||||||
@ -18,7 +23,6 @@ subdir('markup')
|
|||||||
|
|
||||||
browser_sources = common_sources
|
browser_sources = common_sources
|
||||||
subdir('browser')
|
subdir('browser')
|
||||||
browser_sources
|
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'web-browser',
|
'web-browser',
|
||||||
|
17
scriptlang/error.hpp
Normal file
17
scriptlang/error.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace scriptlang {
|
||||||
|
|
||||||
|
enum class Errors {
|
||||||
|
NotImplemented,
|
||||||
|
LexerNoTokenYet,
|
||||||
|
LexerStringNotTerminated,
|
||||||
|
LexerUnexpectedCharacer,
|
||||||
|
LexerMultilineCommentNotTerminated,
|
||||||
|
NoLexerOutput,
|
||||||
|
ParserExhausted,
|
||||||
|
ParserMalformedStringLiteral,
|
||||||
|
ParserStructNotTerminated,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,14 @@
|
|||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
namespace scriptlang {
|
namespace scriptlang {
|
||||||
|
|
||||||
auto constexpr Lexer::next() noexcept -> Result<Token, void>
|
auto Lexer::make_token() noexcept -> Result<Token, Errors>
|
||||||
{
|
{
|
||||||
if (done())
|
if (done())
|
||||||
return token(Tokens::Eof, index);
|
return token(Tokens::Eof, index, current_location());
|
||||||
if (std::isdigit(current()) != 0)
|
if (std::isdigit(current()) != 0)
|
||||||
return make_number();
|
return make_number();
|
||||||
if (std::isalpha(current()) != 0 or current() == '_')
|
if (std::isalpha(current()) != 0 or current() == '_')
|
||||||
@ -17,32 +18,34 @@ auto constexpr Lexer::next() noexcept -> Result<Token, void>
|
|||||||
return make_static();
|
return make_static();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::make_number() noexcept -> Result<Token, void>
|
auto Lexer::make_number() noexcept -> Result<Token, Errors>
|
||||||
{
|
{
|
||||||
auto begin = index;
|
auto begin = index;
|
||||||
|
auto span_from = current_location();
|
||||||
while (!done() and std::isdigit(current()) != 0)
|
while (!done() and std::isdigit(current()) != 0)
|
||||||
step();
|
step();
|
||||||
if (current() == '.') {
|
if (current() == '.') {
|
||||||
step();
|
step();
|
||||||
while (!done() and std::isdigit(current()) != 0)
|
while (!done() and std::isdigit(current()) != 0)
|
||||||
step();
|
step();
|
||||||
return token(Tokens::Float, begin);
|
return token(Tokens::Float, begin, span_from);
|
||||||
}
|
}
|
||||||
return token(Tokens::Int, begin);
|
return token(Tokens::Int, begin, span_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::make_id() noexcept -> Result<Token, void>
|
auto Lexer::make_id() noexcept -> Result<Token, Errors>
|
||||||
{
|
{
|
||||||
auto begin = index;
|
auto begin = index;
|
||||||
|
auto span_from = current_location();
|
||||||
while (!done()
|
while (!done()
|
||||||
and (std::isalpha(current()) != 0 or std::isdigit(current()) != 0
|
and (std::isalpha(current()) != 0 or std::isdigit(current()) != 0
|
||||||
or current() == '_'))
|
or current() == '_'))
|
||||||
step();
|
step();
|
||||||
return token(id_or_keyword_type(text.substr(begin, index - begin)), begin);
|
return token(id_or_keyword_type(text.substr(begin, index - begin)), begin,
|
||||||
|
span_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::id_or_keyword_type(std::string_view substring) noexcept
|
auto Lexer::id_or_keyword_type(std::string_view substring) noexcept -> Tokens
|
||||||
-> Tokens
|
|
||||||
{
|
{
|
||||||
if (substring.compare("if") == 0)
|
if (substring.compare("if") == 0)
|
||||||
return Tokens::If;
|
return Tokens::If;
|
||||||
@ -75,9 +78,10 @@ auto constexpr Lexer::id_or_keyword_type(std::string_view substring) noexcept
|
|||||||
return Tokens::Id;
|
return Tokens::Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::make_string() noexcept -> Result<Token, void>
|
auto Lexer::make_string() noexcept -> Result<Token, Errors>
|
||||||
{
|
{
|
||||||
auto begin = index;
|
auto begin = index;
|
||||||
|
auto span_from = current_location();
|
||||||
step();
|
step();
|
||||||
auto escaped = false;
|
auto escaped = false;
|
||||||
while (!done() and (current() != '"' or escaped)) {
|
while (!done() and (current() != '"' or escaped)) {
|
||||||
@ -85,22 +89,23 @@ auto constexpr Lexer::make_string() noexcept -> Result<Token, void>
|
|||||||
step();
|
step();
|
||||||
}
|
}
|
||||||
if (current() != '"')
|
if (current() != '"')
|
||||||
return {};
|
return Errors::LexerStringNotTerminated;
|
||||||
step();
|
step();
|
||||||
return token(Tokens::String, begin);
|
return token(Tokens::String, begin, span_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::make_static() noexcept -> Result<Token, void>
|
auto Lexer::make_static() noexcept -> Result<Token, Errors>
|
||||||
{
|
{
|
||||||
auto begin = index;
|
auto begin = index;
|
||||||
|
auto span_from = current_location();
|
||||||
auto type = static_token_type();
|
auto type = static_token_type();
|
||||||
if (!type)
|
if (!type)
|
||||||
return {};
|
return type.transform<Token>();
|
||||||
return token(*type, begin);
|
return token(*type, begin, span_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||||
auto constexpr Lexer::static_token_type() noexcept -> Result<Tokens, void>
|
auto Lexer::static_token_type() noexcept -> Result<Tokens, Errors>
|
||||||
{
|
{
|
||||||
using TT = Tokens;
|
using TT = Tokens;
|
||||||
auto stepped = [&](Tokens v) {
|
auto stepped = [&](Tokens v) {
|
||||||
@ -202,10 +207,10 @@ auto constexpr Lexer::static_token_type() noexcept -> Result<Tokens, void>
|
|||||||
return stepped(TT::GreaterEqual);
|
return stepped(TT::GreaterEqual);
|
||||||
return TT::Greater;
|
return TT::Greater;
|
||||||
}
|
}
|
||||||
return {};
|
return Errors::LexerUnexpectedCharacer;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::skip_multiline_comment() noexcept -> Result<Tokens, void>
|
auto Lexer::skip_multiline_comment() noexcept -> Result<Tokens, Errors>
|
||||||
{
|
{
|
||||||
step();
|
step();
|
||||||
auto last = current();
|
auto last = current();
|
||||||
@ -213,12 +218,12 @@ auto constexpr Lexer::skip_multiline_comment() noexcept -> Result<Tokens, void>
|
|||||||
while (!done() and last != '*' and current() != '/')
|
while (!done() and last != '*' and current() != '/')
|
||||||
step();
|
step();
|
||||||
if (last != '*' or current() != '/')
|
if (last != '*' or current() != '/')
|
||||||
return {};
|
return Errors::LexerMultilineCommentNotTerminated;
|
||||||
step();
|
step();
|
||||||
return Tokens::MultilineComment;
|
return Tokens::MultilineComment;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto constexpr Lexer::skip_singleline_comment() noexcept -> Result<Tokens, void>
|
auto Lexer::skip_singleline_comment() noexcept -> Result<Tokens, Errors>
|
||||||
{
|
{
|
||||||
step();
|
step();
|
||||||
while (!done() and current() != '\n')
|
while (!done() and current() != '\n')
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "error.hpp"
|
||||||
#include "utils/all.hpp"
|
#include "utils/all.hpp"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@ -80,10 +81,14 @@ struct Location {
|
|||||||
int line, column;
|
int line, column;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Span {
|
||||||
|
Location from, to;
|
||||||
|
};
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
Tokens type;
|
Tokens type;
|
||||||
size_t index, length;
|
size_t index, length;
|
||||||
Location location;
|
Span span;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Lexer {
|
class Lexer {
|
||||||
@ -91,29 +96,39 @@ public:
|
|||||||
Lexer(std::string_view text)
|
Lexer(std::string_view text)
|
||||||
: text { text }
|
: text { text }
|
||||||
{ }
|
{ }
|
||||||
auto constexpr next() noexcept -> Result<Token, void>;
|
auto next() noexcept -> Result<Token, Errors> { return make_token(); }
|
||||||
auto peek() noexcept -> Result<Token, void>
|
auto peek() noexcept -> Result<Token, Errors>
|
||||||
{
|
{
|
||||||
if (last_token)
|
if (last_token)
|
||||||
return Result<Token, void>::create_ok(*last_token);
|
return Result<Token, Errors>::create_ok(*last_token);
|
||||||
return {};
|
return Errors::LexerNoTokenYet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto constexpr make_number() noexcept -> Result<Token, void>;
|
auto make_token() noexcept -> Result<Token, Errors>;
|
||||||
auto constexpr make_id() noexcept -> Result<Token, void>;
|
auto make_number() noexcept -> Result<Token, Errors>;
|
||||||
auto constexpr id_or_keyword_type(std::string_view substring) noexcept
|
auto make_id() noexcept -> Result<Token, Errors>;
|
||||||
-> Tokens;
|
auto id_or_keyword_type(std::string_view substring) noexcept -> Tokens;
|
||||||
auto constexpr make_string() noexcept -> Result<Token, void>;
|
auto make_string() noexcept -> Result<Token, Errors>;
|
||||||
auto constexpr make_static() noexcept -> Result<Token, void>;
|
auto make_static() noexcept -> Result<Token, Errors>;
|
||||||
auto constexpr static_token_type() noexcept -> Result<Tokens, void>;
|
auto static_token_type() noexcept -> Result<Tokens, Errors>;
|
||||||
auto constexpr skip_multiline_comment() noexcept -> Result<Tokens, void>;
|
auto skip_multiline_comment() noexcept -> Result<Tokens, Errors>;
|
||||||
auto constexpr skip_singleline_comment() noexcept -> Result<Tokens, void>;
|
auto skip_singleline_comment() noexcept -> Result<Tokens, Errors>;
|
||||||
|
|
||||||
[[nodiscard]] auto constexpr inline token(
|
[[nodiscard]] auto constexpr inline current_location() const noexcept
|
||||||
Tokens type, size_t begin) noexcept -> Token
|
-> Location
|
||||||
{
|
{
|
||||||
auto token = Token { type, begin, index - begin, { line, column } };
|
return { line, column };
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto constexpr inline token(
|
||||||
|
Tokens type, size_t begin, Location span_from) noexcept -> Token
|
||||||
|
{
|
||||||
|
auto token = Token {
|
||||||
|
type,
|
||||||
|
begin,
|
||||||
|
index - begin,
|
||||||
|
{ span_from, { line, column } },
|
||||||
|
};
|
||||||
last_token = token;
|
last_token = token;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
common_sources += files(
|
common_sources += files(
|
||||||
'parser.cpp',
|
|
||||||
'lexer.cpp',
|
'lexer.cpp',
|
||||||
|
'parser.cpp',
|
||||||
)
|
)
|
||||||
|
@ -1,14 +1,110 @@
|
|||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace scriptlang {
|
namespace scriptlang {
|
||||||
|
|
||||||
auto Parser::parse_value() noexcept -> Result<std::unique_ptr<Expression>, void>
|
auto parse_expression(bool strictly_values) noexcept
|
||||||
|
-> Result<std::unique_ptr<Expression>, Errors>
|
||||||
{
|
{
|
||||||
switch (lexer.peek()->type) {
|
if (strictly_values)
|
||||||
|
return parse_expression(true);
|
||||||
|
return Errors::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Parser::parse_struct(bool strictly_values) noexcept
|
||||||
|
-> Result<std::unique_ptr<Expression>, Errors>
|
||||||
|
{
|
||||||
|
auto values = std::map<std::string, std::unique_ptr<Expression>> {};
|
||||||
|
auto first_brace = TRY(lexer.peek());
|
||||||
|
if (TRY(lexer.peek()).type == Tokens::LBrace) {
|
||||||
|
TRY(lexer.next());
|
||||||
|
auto last_brace = TRY(lexer.peek());
|
||||||
|
if (last_brace.type != Tokens::RBrace)
|
||||||
|
return Errors::ParserStructNotTerminated;
|
||||||
|
return {
|
||||||
|
std::make_unique<Struct>(
|
||||||
|
token_span(first_brace, last_brace), std::move(values)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return parse_atom();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Parser::parse_atom() noexcept
|
||||||
|
-> Result<std::unique_ptr<Expression>, Errors>
|
||||||
|
{
|
||||||
|
auto token = TRY(lexer.peek());
|
||||||
|
switch (token.type) {
|
||||||
case Tokens::Id:
|
case Tokens::Id:
|
||||||
|
return {
|
||||||
|
std::make_unique<Id>(token_span(token, token),
|
||||||
|
token_text(lexer.peek()->index, lexer.peek()->length)),
|
||||||
|
};
|
||||||
|
case Tokens::Int:
|
||||||
|
return {
|
||||||
|
std::make_unique<Int>(token_span(token, token),
|
||||||
|
std::atol(
|
||||||
|
token_text(lexer.peek()->index, lexer.peek()->length)
|
||||||
|
.c_str())),
|
||||||
|
};
|
||||||
|
case Tokens::Float:
|
||||||
|
return {
|
||||||
|
std::make_unique<Float>(token_span(token, token),
|
||||||
|
std::atof(
|
||||||
|
token_text(lexer.peek()->index, lexer.peek()->length)
|
||||||
|
.c_str())),
|
||||||
|
};
|
||||||
|
case Tokens::False:
|
||||||
|
return {
|
||||||
|
std::make_unique<Bool>(token_span(token, token), false),
|
||||||
|
};
|
||||||
|
case Tokens::True:
|
||||||
|
return {
|
||||||
|
std::make_unique<Bool>(token_span(token, token), true),
|
||||||
|
};
|
||||||
|
case Tokens::String:
|
||||||
|
return {
|
||||||
|
std::make_unique<String>(token_span(token, token),
|
||||||
|
*parse_string_value(
|
||||||
|
token_text(lexer.peek()->index, lexer.peek()->length))),
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return {};
|
return Errors::ParserExhausted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Parser::parse_string_value(std::string_view literal) noexcept
|
||||||
|
-> Result<std::string, Errors>
|
||||||
|
{
|
||||||
|
if (literal.size() < 2)
|
||||||
|
return Errors::ParserMalformedStringLiteral;
|
||||||
|
auto value = std::string {};
|
||||||
|
auto escaped = false;
|
||||||
|
for (const auto c : literal.substr(1, literal.size() - 2)) {
|
||||||
|
if (escaped) {
|
||||||
|
value.push_back([&] {
|
||||||
|
switch (c) {
|
||||||
|
case 'n':
|
||||||
|
return '\n';
|
||||||
|
case 'r':
|
||||||
|
return '\r';
|
||||||
|
case 't':
|
||||||
|
return '\t';
|
||||||
|
case 'v':
|
||||||
|
return '\n';
|
||||||
|
default:
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
escaped = false;
|
||||||
|
} else if (c == '\\') {
|
||||||
|
escaped = true;
|
||||||
|
} else {
|
||||||
|
value.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "error.hpp"
|
||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
#include "utils/all.hpp"
|
#include "utils/all.hpp"
|
||||||
#include "utils/result.hpp"
|
#include "utils/result.hpp"
|
||||||
@ -12,10 +13,6 @@
|
|||||||
|
|
||||||
namespace scriptlang {
|
namespace scriptlang {
|
||||||
|
|
||||||
struct Span {
|
|
||||||
Location from, to;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Expressions {
|
enum class Expressions {
|
||||||
Binary,
|
Binary,
|
||||||
Negate,
|
Negate,
|
||||||
@ -25,6 +22,7 @@ enum class Expressions {
|
|||||||
Call,
|
Call,
|
||||||
Operator,
|
Operator,
|
||||||
|
|
||||||
|
Struct,
|
||||||
Id,
|
Id,
|
||||||
Int,
|
Int,
|
||||||
Float,
|
Float,
|
||||||
@ -47,66 +45,101 @@ public:
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class Id final : public Expression {
|
class Struct final : public Expression {
|
||||||
public:
|
public:
|
||||||
Id(std::string value)
|
Struct(Span span, std::map<std::string, std::unique_ptr<Expression>> values)
|
||||||
: m_value { std::move(value) }
|
: m_span { span }
|
||||||
|
, m_values { std::move(values) }
|
||||||
{ }
|
{ }
|
||||||
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
{
|
{
|
||||||
return Expressions::Id;
|
return Expressions::Id;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto span() const noexcept -> Span override { return m_span; }
|
||||||
|
[[nodiscard]] auto values() const noexcept -> auto& { return m_values; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Span m_span;
|
||||||
|
std::map<std::string, std::unique_ptr<Expression>> m_values;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Id final : public Expression {
|
||||||
|
public:
|
||||||
|
Id(Span span, std::string value)
|
||||||
|
: m_span { span }
|
||||||
|
, m_value { std::move(value) }
|
||||||
|
{ }
|
||||||
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
|
{
|
||||||
|
return Expressions::Id;
|
||||||
|
}
|
||||||
|
[[nodiscard]] auto span() const noexcept -> Span override { return m_span; }
|
||||||
[[nodiscard]] auto value() const noexcept { return m_value; }
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Span m_span;
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Int final : public Expression {
|
class Int final : public Expression {
|
||||||
public:
|
public:
|
||||||
Int(int64_t value)
|
Int(Span span, int64_t value)
|
||||||
: m_value { value }
|
: m_span { span }
|
||||||
|
, m_value { value }
|
||||||
{ }
|
{ }
|
||||||
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
{
|
{
|
||||||
return Expressions::Int;
|
return Expressions::Int;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto span() const noexcept -> Span override { return m_span; }
|
||||||
[[nodiscard]] auto value() const noexcept { return m_value; }
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Span m_span;
|
||||||
int64_t m_value;
|
int64_t m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Float final : public Expression {
|
class Float final : public Expression {
|
||||||
public:
|
public:
|
||||||
Float(double value)
|
Float(Span span, double value)
|
||||||
: m_value { value }
|
: m_span { span }
|
||||||
|
, m_value { value }
|
||||||
{ }
|
{ }
|
||||||
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
{
|
{
|
||||||
return Expressions::Float;
|
return Expressions::Float;
|
||||||
}
|
}
|
||||||
[[nodiscard]] auto value() const noexcept { return m_value; }
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
[[nodiscard]] auto span() const noexcept -> Span override { return m_span; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Span m_span;
|
||||||
double m_value;
|
double m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bool final : public Expression {
|
class Bool final : public Expression {
|
||||||
public:
|
public:
|
||||||
Bool(bool value)
|
Bool(Span span, bool value)
|
||||||
: m_value { value }
|
: m_span { span }
|
||||||
|
, m_value { value }
|
||||||
{ }
|
{ }
|
||||||
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
{
|
{
|
||||||
return Expressions::Bool;
|
return Expressions::Bool;
|
||||||
}
|
}
|
||||||
[[nodiscard]] auto value() const noexcept { return m_value; }
|
[[nodiscard]] auto value() const noexcept { return m_value; }
|
||||||
|
[[nodiscard]] auto span() const noexcept -> Span override { return m_span; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Span m_span;
|
||||||
bool m_value;
|
bool m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class String final : public Expression {
|
class String final : public Expression {
|
||||||
public:
|
public:
|
||||||
String(std::string value)
|
String(Span span, std::string value)
|
||||||
: m_value { std::move(value) }
|
: m_span { span }
|
||||||
|
, m_value { std::move(value) }
|
||||||
{ }
|
{ }
|
||||||
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
[[nodiscard]] auto expression_type() const noexcept -> Expressions override
|
||||||
{
|
{
|
||||||
@ -116,8 +149,10 @@ public:
|
|||||||
{
|
{
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto span() const noexcept -> Span override { return m_span; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Span m_span;
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,11 +162,25 @@ public:
|
|||||||
: text { text }
|
: text { text }
|
||||||
, lexer(text)
|
, lexer(text)
|
||||||
{ }
|
{ }
|
||||||
auto parse_expression() noexcept
|
auto parse_expression(bool strictly_values) noexcept
|
||||||
-> Result<std::unique_ptr<Expression>, void>;
|
-> Result<std::unique_ptr<Expression>, Errors>;
|
||||||
auto parse_value() noexcept -> Result<std::unique_ptr<Expression>, void>;
|
auto parse_struct(bool strictly_values) noexcept
|
||||||
|
-> Result<std::unique_ptr<Expression>, Errors>;
|
||||||
|
auto parse_atom() noexcept -> Result<std::unique_ptr<Expression>, Errors>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] static auto parse_string_value(
|
||||||
|
std::string_view literal) noexcept -> Result<std::string, Errors>;
|
||||||
|
[[nodiscard]] auto token_text(size_t index, size_t length) const noexcept
|
||||||
|
-> std::string
|
||||||
|
{
|
||||||
|
return std::string { text.substr(index, length) };
|
||||||
|
}
|
||||||
|
[[nodiscard]] static auto token_span(Token from, Token to) noexcept -> Span
|
||||||
|
{
|
||||||
|
return { from.span.from, to.span.to };
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view text;
|
std::string_view text;
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
};
|
};
|
||||||
|
@ -157,6 +157,15 @@ public:
|
|||||||
return unwrap();
|
return unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transforms `Result<T, E>` into `Result<Y, E>`.
|
||||||
|
// Requries result to be an error.
|
||||||
|
template <typename NewValue>
|
||||||
|
[[nodiscard]] constexpr auto transform() const noexcept
|
||||||
|
-> Result<NewValue, Error>
|
||||||
|
{
|
||||||
|
return Result<NewValue, Error>::create_error(unwrap_error());
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto map(auto func) noexcept
|
[[nodiscard]] constexpr auto map(auto func) noexcept
|
||||||
{
|
{
|
||||||
using NewValue = decltype(func(unwrap()));
|
using NewValue = decltype(func(unwrap()));
|
||||||
@ -643,3 +652,12 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||||
|
#define TRY(expr) \
|
||||||
|
({ \
|
||||||
|
auto result = (expr); \
|
||||||
|
if (result.is_error()) \
|
||||||
|
return { std::move(result.unwrap_error()) }; \
|
||||||
|
std::move(result.unwrap()); \
|
||||||
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user