Chord literals support
This commit is contained in:
parent
74f4393d6a
commit
d6edc2e6e4
47
src/lexer.cc
47
src/lexer.cc
@ -1,5 +1,7 @@
|
||||
#include <musique.hh>
|
||||
|
||||
constexpr std::string_view Notes_Symbols = "abcedefgh";
|
||||
|
||||
auto Lexer::next_token() -> Result<Token>
|
||||
{
|
||||
while (consume_if(unicode::is_space)) {}
|
||||
@ -40,6 +42,51 @@ auto Lexer::next_token() -> Result<Token>
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,7 @@ namespace unicode
|
||||
|
||||
bool is_digit(u32 digit);
|
||||
bool is_space(u32 space);
|
||||
bool is_letter(u32 letter);
|
||||
}
|
||||
|
||||
namespace utf8
|
||||
@ -183,7 +184,7 @@ struct Lexer
|
||||
// Finds next rune in source and returns it, advancing the string
|
||||
auto consume() -> u32;
|
||||
|
||||
inline auto consume_if(auto test) -> u32
|
||||
inline auto consume_if(auto test) -> bool
|
||||
{
|
||||
return test(peek()) && (consume(), true);
|
||||
}
|
||||
|
@ -27,9 +27,12 @@ static void expect_token_type_and_value(
|
||||
{
|
||||
Lexer lexer{source};
|
||||
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";
|
||||
|
||||
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(
|
||||
@ -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, "\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,");
|
||||
};
|
||||
};
|
||||
|
@ -97,3 +97,9 @@ bool unicode::is_space(u32 space)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool unicode::is_letter(u32 letter)
|
||||
{
|
||||
// TODO Unicode letters handling
|
||||
return std::isalpha(letter);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user