Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Parsing "Sheet Music" into Channels #18

Merged
merged 25 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7fa871b
:hammer: prepare
AutumnSky1010 Oct 20, 2023
512ab5d
Merge branch 'master' into feature/#3
AutumnSky1010 Feb 26, 2024
f4ce3c8
:hammer: prepare
AutumnSky1010 Feb 26, 2024
c8db9d9
:+1: remove old implements
AutumnSky1010 Feb 27, 2024
d826009
:arrow_double_down: lexer
AutumnSky1010 Feb 27, 2024
2e529d9
:bug: fix number and rest
AutumnSky1010 Feb 28, 2024
9bdc08c
:arrow_double_down: impliment Parser
AutumnSky1010 Mar 8, 2024
01276be
:+1: Add tests for lexer and parser
AutumnSky1010 Mar 8, 2024
59fc5d8
:+1: Add comments
AutumnSky1010 Mar 9, 2024
2e16c99
:recycle: refactoring
AutumnSky1010 Mar 10, 2024
f9bf42e
:+1: Fixed to return result object
AutumnSky1010 Mar 10, 2024
e431805
:arrow_double_down: Add the smsc serializer
AutumnSky1010 Mar 10, 2024
5bcb835
Merge branch 'master' into feature/#3
AutumnSky1010 Mar 10, 2024
cf34c18
:+1: Add serializer test
AutumnSky1010 Mar 10, 2024
a131a15
:recycle: refactoring
AutumnSky1010 Mar 10, 2024
7a7a824
:recycle: Refactoring the Note class
AutumnSky1010 Mar 11, 2024
3dadc11
:recycle: Change from CRLF to LF
AutumnSky1010 Mar 13, 2024
2259ee2
:+1: Change the syntax of SMSC
AutumnSky1010 Mar 14, 2024
d10b625
:arrow_double_down: Add the function to import sound components into …
AutumnSky1010 Mar 14, 2024
0c5acbf
:+1: Add tests of errors.
AutumnSky1010 Mar 14, 2024
ae55589
:+1: Fix a definition of statement
AutumnSky1010 Mar 14, 2024
d5d2df7
:recycle: refatoring
AutumnSky1010 Mar 14, 2024
2ce4002
:+1: Remove dotted component in tuplet
AutumnSky1010 Mar 15, 2024
33088c5
:recycle: Rename workflow name
AutumnSky1010 Mar 15, 2024
73af195
:+1: Add comments
AutumnSky1010 Mar 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 52 additions & 26 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent

# 式のようなメンバー
csharp_style_expression_bodied_accessors = true
csharp_style_expression_bodied_constructors = false
csharp_style_expression_bodied_indexers = true
csharp_style_expression_bodied_lambdas = true
csharp_style_expression_bodied_local_functions = false
csharp_style_expression_bodied_methods = false
csharp_style_expression_bodied_operators = false
csharp_style_expression_bodied_properties = true
csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent

# パターン マッチング設定
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
Expand All @@ -102,7 +102,7 @@ csharp_style_prefer_switch_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion

# 修飾子設定
csharp_prefer_static_local_function = true
csharp_prefer_static_local_function = true:suggestion
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async

# コード ブロックの設定
Expand All @@ -113,27 +113,27 @@ csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent

# 式レベルの設定
csharp_prefer_simple_default_expression = true
csharp_style_deconstructed_variable_declaration = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_style_inlined_variable_declaration = true
csharp_style_prefer_index_operator = true
csharp_style_prefer_local_over_anonymous_function = true
csharp_style_prefer_null_check_over_type_check = true
csharp_style_prefer_range_operator = true
csharp_style_prefer_tuple_swap = true
csharp_style_prefer_utf8_string_literals = true
csharp_style_throw_expression = true
csharp_style_unused_value_assignment_preference = discard_variable
csharp_style_unused_value_expression_statement_preference = discard_variable
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_local_over_anonymous_function = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_prefer_utf8_string_literals = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
csharp_style_unused_value_expression_statement_preference = discard_variable:silent

# 'using' ディレクティブの基本設定
csharp_using_directive_placement = outside_namespace:silent

# 改行設定
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
csharp_style_allow_embedded_statements_on_same_line_experimental = true
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent

#### C# 書式ルール ####

Expand Down Expand Up @@ -224,6 +224,10 @@ dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_prefer_readonly_struct = true:suggestion
csharp_style_prefer_readonly_struct_member = true:suggestion
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent

[*.{cs,vb}]
tab_width = 4
Expand All @@ -237,5 +241,27 @@ dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
dotnet_style_operator_placement_when_wrapping = beginning_of_line
end_of_line = lf
dotnet_code_quality_unused_parameters = all:suggestion
end_of_line = crlf
dotnet_style_readonly_field = true:suggestion
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_prefer_collection_expression = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = false:silent
dotnet_style_prefer_conditional_expression_over_return = false:silent
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: .NET Core Desktop
name: Build and Test

on:
push:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,6 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
/Shinko.cs

# VS Code workspace
SoundMaker.code-workspace
6 changes: 6 additions & 0 deletions SoundMaker.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoundMakerTests", "test\Sou
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SoundMakerConsole", "src\SoundMakerConsole\SoundMakerConsole.csproj", "{56C904EC-478C-4219-9599-63C1F2041DB4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ソリューション項目", "ソリューション項目", "{A79A7D6C-7F61-4B70-B921-18678D37B354}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
3 changes: 3 additions & 0 deletions src/SoundMaker/ForTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("SoundMakerTests")]
28 changes: 28 additions & 0 deletions src/SoundMaker/ScoreData/SMSC/Error.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace SoundMaker.ScoreData.SMSC;
public record Error
{
internal Error(SMSCReadErrorType type, Token? token)
{
Type = type;
LineNumber = token?.LineNumber ?? 0;
Literal = token?.Literal ?? "";
}

/// <summary>
/// Type of errors <br/>
/// エラーの種類
/// </summary>
public SMSCReadErrorType Type { get; }

/// <summary>
/// String of error location <br/>
/// エラー箇所の文字列
/// </summary>
public string Literal { get; }

/// <summary>
/// Line number of error.<br/>
/// エラー箇所の行番号
/// </summary>
public int LineNumber { get; }
}
162 changes: 162 additions & 0 deletions src/SoundMaker/ScoreData/SMSC/Lexer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using System.Text;
using System.Text.RegularExpressions;

namespace SoundMaker.ScoreData.SMSC;
internal class Lexer
{
private readonly Regex _alphaRegex = new("[a-z]|[A-Z]");

private readonly string _data = "";

public Lexer(string data)
{
_data = data;
}

public List<Token> ReadAll()
{
var tokens = new List<Token>();
var data = _data.Replace("\r\n", "\n").Replace('\r', '\n');
// 空白、空文字列、コメントだけの行をあらかじめ除外する
var lines = data.Split('\n').ToArray();
for (var i = 0; i < lines.Length; i++)
{
var line = lines[i];

// 空白またはコメントだけの行はスキップする
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//"))
{
continue;
}

var lineNumber = i + 1;
var chars = line.ToCharArray();
var otherTypeLiteralBuilder = new StringBuilder();
var numberLiteralBuilder = new StringBuilder();
for (var j = 0; j < chars.Length; j++)
{
char? next = j + 1 < chars.Length ? chars[j + 1] : null;
// numbers
if (char.IsNumber(chars[j]))
{
_ = numberLiteralBuilder.Append(chars[j]);
if (otherTypeLiteralBuilder.Length != 0)
{
var literal = otherTypeLiteralBuilder.ToString();
var type = MatchOtherType(literal);
tokens.Add(new(type, otherTypeLiteralBuilder.ToString(), lineNumber));
_ = otherTypeLiteralBuilder.Clear();
}
continue;
}
// others
if (IsOtherChar(chars[j], next))
{
_ = otherTypeLiteralBuilder.Append(chars[j]);
if (numberLiteralBuilder.Length != 0)
{
var literal = numberLiteralBuilder.ToString();
tokens.Add(new(TokenType.Number, literal, lineNumber));
_ = numberLiteralBuilder.Clear();
}
continue;
}

if (numberLiteralBuilder.Length != 0)
{
var literal = numberLiteralBuilder.ToString();
tokens.Add(new(TokenType.Number, literal, lineNumber));
_ = numberLiteralBuilder.Clear();
}
if (otherTypeLiteralBuilder.Length != 0)
{
var literal = otherTypeLiteralBuilder.ToString();
var type = MatchOtherType(literal);
tokens.Add(new(type, literal, lineNumber));
_ = otherTypeLiteralBuilder.Clear();
}

// comment out
if (j + 1 < chars.Length && IsCommentPrefix(chars[j], next))
{
break;
}

// space
if (char.IsWhiteSpace(chars[j]))
{
continue;
}

// symbols
Token token = chars[j] switch
{
'.' => new(TokenType.Dot, ".", lineNumber),
'#' => new(TokenType.Sharp, "#", lineNumber),
'(' => new(TokenType.LeftParentheses, "(", lineNumber),
')' => new(TokenType.RightParentheses, ")", lineNumber),
',' => new(TokenType.Comma, ",", lineNumber),
';' => new(TokenType.Semicolon, ";", lineNumber),
_ => new(TokenType.Unknown, chars[j].ToString(), lineNumber),
};
tokens.Add(token);
}

if (numberLiteralBuilder.Length != 0)
{
var literal = numberLiteralBuilder.ToString();
tokens.Add(new(TokenType.Number, literal, lineNumber));
_ = numberLiteralBuilder.Clear();
}

if (otherTypeLiteralBuilder.Length != 0)
{
var literal = otherTypeLiteralBuilder.ToString();
var type = MatchOtherType(literal);
tokens.Add(new(type, literal, lineNumber));
_ = otherTypeLiteralBuilder.Clear();
}

tokens.Add(new(TokenType.LineBreak, "\n", lineNumber));
}
return tokens;
}

private TokenType MatchOtherType(string other)
{
if (int.TryParse(other, out _))
{
return TokenType.Number;
}
if (_alphaRegex.IsMatch(other))
{
return other switch
{
"tie" => TokenType.Tie,
"tup" => TokenType.Tuplet,
"rest" => TokenType.Rest,
_ => TokenType.Alphabet,
};
}
return TokenType.Unknown;
}

private bool IsOtherChar(char character, char? nextCharacter)
{
var next = nextCharacter ?? 'a'; // 'a' is not comment prefix.
return
!IsSymbol(character) &&
!IsCommentPrefix(character, next) &&
!char.IsWhiteSpace(character);
}

private bool IsCommentPrefix(char character, char? nextCharacter)
{
return character is '/' && nextCharacter is '/';
}

private bool IsSymbol(char character)
{
return character is '.' or '#' or '(' or ')' or ',' or ';';
}
}
Loading
Loading