Chord literals support

This commit is contained in:
Robert Bendun 2022-05-02 19:00:11 +02:00
parent 74f4393d6a
commit d6edc2e6e4
4 changed files with 70 additions and 4 deletions

View File

@ -1,5 +1,7 @@
#include <musique.hh> #include <musique.hh>
constexpr std::string_view Notes_Symbols = "abcedefgh";
auto Lexer::next_token() -> Result<Token> auto Lexer::next_token() -> Result<Token>
{ {
while (consume_if(unicode::is_space)) {} while (consume_if(unicode::is_space)) {}
@ -40,6 +42,51 @@ auto Lexer::next_token() -> Result<Token>
return { Token::Type::Numeric, finish(), token_location }; return { Token::Type::Numeric, finish(), token_location };
} }
if (consume_if([](u32 ch) { return Notes_Symbols.find(ch) != std::string_view::npos; })) {
// chord declaration
constexpr u8 Expect_Number = 0b01;
constexpr u8 Expect_Move = 0b10;
constexpr u8 Expect_Number_Or_Move = 0b11;
auto current = Expect_Number;
std::string_view accepted_digits = "12357";
usize digit_cursor = 0;
for (;;) {
if ((current & Expect_Move) == Expect_Move
&& consume_if([](u32 c) { return c == ',' || c == '\''; })
) {
current = Expect_Number;
continue;
}
if ((current & Expect_Number) == Expect_Number) {
bool found = false;
for (; digit_cursor < accepted_digits.size(); ++digit_cursor) {
if (consume_if([&](u32 c) { return u32(accepted_digits[digit_cursor]) == c; })) {
found = true;
break;
}
}
if (found) {
current = digit_cursor < accepted_digits.size()
? Expect_Number_Or_Move
: Expect_Move;
continue;
}
}
break;
}
if (unicode::is_letter(peek())) {
assert(false && "symbols are not implemented yet");
}
return { Token::Type::Chord, finish(), token_location };
}
return errors::unrecognized_character(peek(), token_location); return errors::unrecognized_character(peek(), token_location);
} }

View File

@ -113,6 +113,7 @@ namespace unicode
bool is_digit(u32 digit); bool is_digit(u32 digit);
bool is_space(u32 space); bool is_space(u32 space);
bool is_letter(u32 letter);
} }
namespace utf8 namespace utf8
@ -183,7 +184,7 @@ struct Lexer
// Finds next rune in source and returns it, advancing the string // Finds next rune in source and returns it, advancing the string
auto consume() -> u32; auto consume() -> u32;
inline auto consume_if(auto test) -> u32 inline auto consume_if(auto test) -> bool
{ {
return test(peek()) && (consume(), true); return test(peek()) && (consume(), true);
} }

View File

@ -27,9 +27,12 @@ static void expect_token_type_and_value(
{ {
Lexer lexer{source}; Lexer lexer{source};
auto result = lexer.next_token(); auto result = lexer.next_token();
expect(result.has_value() >> fatal, sl) << "have not parsed any tokens"; expect(result.has_value(), sl) << "have not parsed any tokens";
expect(eq(under(result->type), under(expected_type)), sl) << "different token type then expected";
expect(eq(result->source, expected), sl) << "tokenized source is not equal to original"; if (result.has_value()) {
expect(eq(under(result->type), under(expected_type)), sl) << "different token type then expected";
expect(eq(result->source, expected), sl) << "tokenized source is not equal to original";
}
} }
static void expect_token_type_and_value( static void expect_token_type_and_value(
@ -86,4 +89,13 @@ suite lexer_test = [] {
expect_token_type_and_location(Token::Type::Numeric, "\n123", Location::at(2, 1)); expect_token_type_and_location(Token::Type::Numeric, "\n123", Location::at(2, 1));
expect_token_type_and_location(Token::Type::Numeric, "\n 123", Location::at(2, 3)); expect_token_type_and_location(Token::Type::Numeric, "\n 123", Location::at(2, 3));
}; };
"Chord literals"_test = [] {
expect_token_type_and_value(Token::Type::Chord, "c1");
expect_token_type_and_value(Token::Type::Chord, "d1257");
expect_token_type_and_value(Token::Type::Chord, "e1'");
expect_token_type_and_value(Token::Type::Chord, "g127");
expect_token_type_and_value(Token::Type::Chord, "f1'2'3'5'7'");
expect_token_type_and_value(Token::Type::Chord, "b1,2,5,7,");
};
}; };

View File

@ -97,3 +97,9 @@ bool unicode::is_space(u32 space)
} }
return false; return false;
} }
bool unicode::is_letter(u32 letter)
{
// TODO Unicode letters handling
return std::isalpha(letter);
}