diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h new file mode 100644 index 0000000000..24d723b2e7 --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/Token.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023, Dan Klishch + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#include "AST/AST.h" + +namespace JSSpecCompiler { + +constexpr i32 ambiguous_operator_precedence = -2; +constexpr i32 pre_merged_operator_precedence = 2; +constexpr i32 unary_operator_precedence = 3; +constexpr i32 closing_bracket_precedence = 18; + +// NOTE: Operator precedence is generally the same as in +// https://en.cppreference.com/w/cpp/language/operator_precedence (common sense applies). +#define ENUMERATE_TOKENS(F) \ + F(Invalid, -1, Invalid, Invalid, Invalid) \ + F(SectionNumber, -1, Invalid, Invalid, Invalid) \ + F(Identifier, -1, Invalid, Invalid, Invalid) \ + F(Number, -1, Invalid, Invalid, Invalid) \ + F(String, -1, Invalid, Invalid, Invalid) \ + F(Undefined, -1, Invalid, Invalid, Invalid) \ + F(Word, -1, Invalid, Invalid, Invalid) \ + F(ParenOpen, -1, Invalid, Invalid, ParenClose) \ + F(ParenClose, 18, Invalid, Invalid, ParenOpen) \ + F(BraceOpen, -1, Invalid, Invalid, BraceClose) \ + F(BraceClose, 18, Invalid, Invalid, BraceOpen) \ + F(Comma, 17, Invalid, Comma, Invalid) \ + F(MemberAccess, 2, Invalid, MemberAccess, Invalid) \ + F(Dot, -1, Invalid, Invalid, Invalid) \ + F(Colon, -1, Invalid, Invalid, Invalid) \ + F(Less, 9, Invalid, CompareLess, Invalid) \ + F(Greater, 9, Invalid, CompareGreater, Invalid) \ + F(NotEquals, 10, Invalid, CompareNotEqual, Invalid) \ + F(Equals, 10, Invalid, CompareEqual, Invalid) \ + F(Plus, 6, Invalid, Plus, Invalid) \ + F(AmbiguousMinus, -2, Invalid, Invalid, Invalid) \ + F(UnaryMinus, 3, Minus, Invalid, Invalid) \ + F(BinaryMinus, 6, Invalid, Minus, Invalid) \ + F(Multiplication, 5, Invalid, Multiplication, Invalid) \ + F(Division, 5, Invalid, Division, Invalid) \ + F(FunctionCall, 2, Invalid, FunctionCall, Invalid) \ + F(ArraySubscript, 2, Invalid, ArraySubscript, Invalid) \ + F(ExclamationMark, 3, AssertCompletion, Invalid, Invalid) \ + F(Is, -1, Invalid, Invalid, Invalid) + +enum class TokenType { +#define ID(name, precedence, unary_name, binary_name, matching_bracket) name, + ENUMERATE_TOKENS(ID) +#undef ID +}; + +constexpr struct TokenInfo { + StringView name; + i32 precedence; + UnaryOperator as_unary_operator; + BinaryOperator as_binary_operator; + TokenType matching_bracket; +} token_info[] = { +#define TOKEN_INFO(name, precedence, unary_name, binary_name, matching_bracket) \ + { \ + #name##sv, \ + precedence, \ + UnaryOperator::unary_name, \ + BinaryOperator::binary_name, \ + TokenType::matching_bracket, \ + }, + ENUMERATE_TOKENS(TOKEN_INFO) +#undef TOKEN_INFO +}; + +struct Token { + TokenInfo const& info() const { return token_info[to_underlying(type)]; } + + StringView name() const { return token_info[to_underlying(type)].name; } + i32 precedence() const { return info().precedence; } + bool is_operator() const { return precedence() > 0 && precedence() < closing_bracket_precedence; } + bool is_ambiguous_operator() const { return precedence() == ambiguous_operator_precedence; } + bool is_pre_merged_binary_operator() const { return precedence() == pre_merged_operator_precedence; } + bool is_unary_operator() const { return precedence() == unary_operator_precedence; } + bool is_binary_operator() const { return is_operator() && !is_unary_operator(); } + bool is_bracket() const { return info().matching_bracket != TokenType::Invalid; } + bool is_opening_bracket() const { return is_bracket() && precedence() == -1; } + bool is_closing_bracket() const { return is_bracket() && precedence() == closing_bracket_precedence; } + + UnaryOperator as_unary_operator() const + { + VERIFY(is_unary_operator()); + return info().as_unary_operator; + } + + BinaryOperator as_binary_operator() const + { + VERIFY(is_binary_operator()); + return info().as_binary_operator; + } + + bool matches_with(Token const& bracket) + { + VERIFY(is_bracket()); + return info().matching_bracket == bracket.type; + } + + TokenType type; + StringView data; + XML::Node const* node; +}; + +}