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>
|
#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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,");
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user