From 4f902396ec3708a40abe5636bf36535693838d2e Mon Sep 17 00:00:00 2001 From: Juha Date: Wed, 22 Jan 2025 15:17:54 +0900 Subject: [PATCH 1/6] =?UTF-8?q?yaml=E3=83=91=E3=83=BC=E3=82=B9=E3=81=AE?= =?UTF-8?q?=E5=9F=BA=E7=9B=A4=E3=81=AE=E4=BD=9C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mooresmaster.Generator/Json/Yaml.cs | 15 ----- .../MooresmasterSourceGenerator.cs | 7 +-- mooresmaster.Generator/Yaml/YamlParser.cs | 61 +++++++++++++++++++ mooresmaster.Tests/Test.cs | 6 +- 4 files changed, 67 insertions(+), 22 deletions(-) delete mode 100644 mooresmaster.Generator/Json/Yaml.cs create mode 100644 mooresmaster.Generator/Yaml/YamlParser.cs diff --git a/mooresmaster.Generator/Json/Yaml.cs b/mooresmaster.Generator/Json/Yaml.cs deleted file mode 100644 index 502235b..0000000 --- a/mooresmaster.Generator/Json/Yaml.cs +++ /dev/null @@ -1,15 +0,0 @@ -using YamlDotNet.Serialization; - -namespace mooresmaster.Generator.Json; - -public static class Yaml -{ - public static string ToJson(string yaml) - { - var yamlDeserializer = new Deserializer(); - var yamlObject = yamlDeserializer.Deserialize(yaml); - var serializer = new SerializerBuilder().JsonCompatible().Build(); - - return serializer.Serialize(yamlObject).Trim(); - } -} diff --git a/mooresmaster.Generator/MooresmasterSourceGenerator.cs b/mooresmaster.Generator/MooresmasterSourceGenerator.cs index f8f8a34..45e3d34 100644 --- a/mooresmaster.Generator/MooresmasterSourceGenerator.cs +++ b/mooresmaster.Generator/MooresmasterSourceGenerator.cs @@ -8,11 +8,11 @@ using mooresmaster.Generator.Analyze.Analyzers; using mooresmaster.Generator.CodeGenerate; using mooresmaster.Generator.Definitions; -using mooresmaster.Generator.Json; using mooresmaster.Generator.JsonSchema; using mooresmaster.Generator.LoaderGenerate; using mooresmaster.Generator.NameResolve; using mooresmaster.Generator.Semantic; +using mooresmaster.Generator.Yaml; namespace mooresmaster.Generator; @@ -108,9 +108,8 @@ private void Emit(SourceProductionContext context, (Compilation compilation, Imm foreach (var additionalText in additionalTexts.Where(a => Path.GetExtension(a.Path) == ".yml").Where(a => !parsedFiles.Contains(a.Path))) { var yamlText = additionalText.GetText()!.ToString(); - var jsonText = Yaml.ToJson(yamlText); - var json = JsonParser.Parse(JsonTokenizer.GetTokens(jsonText)); - var schema = JsonSchemaParser.ParseSchema((json as JsonObject)!, schemaTable); + var json = YamlParser.Parse(yamlText); + var schema = JsonSchemaParser.ParseSchema(json!, schemaTable); schemas.Add(new SchemaFile(additionalText.Path, schema)); parsedFiles.Add(additionalText.Path); } diff --git a/mooresmaster.Generator/Yaml/YamlParser.cs b/mooresmaster.Generator/Yaml/YamlParser.cs new file mode 100644 index 0000000..87ae428 --- /dev/null +++ b/mooresmaster.Generator/Yaml/YamlParser.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.IO; +using mooresmaster.Generator.Json; +using YamlDotNet.RepresentationModel; + +namespace mooresmaster.Generator.Yaml; + +public static class YamlParser +{ + public static JsonObject Parse(string yamlText) + { + var document = ParseYamlDocument(yamlText); + foreach (var node in document.RootNode.AllNodes) Console.WriteLine($"{node.GetType()} {node}"); + + return ParseYamlNode(document); + } + + private static YamlDocument ParseYamlDocument(string yamlText) + { + var input = new StringReader(yamlText); + var yamlStream = new YamlStream(); + yamlStream.Load(input); + var document = yamlStream.Documents[0]; + + return document; + } + + private static JsonObject ParseYamlNode(YamlDocument yamlDocument) + { + return null; + } + + private static IJsonNode ParseYamlNode(YamlNode yamlNode, IJsonNode jsonNode, string propertyName) + { + return yamlNode switch + { + YamlMappingNode yamlMappingNode => ParseYamlMappingNode(yamlMappingNode, jsonNode, propertyName), + YamlScalarNode yamlScalarNode => throw new NotImplementedException(), + YamlSequenceNode yamlSequenceNode => throw new NotImplementedException(), + YamlAliasNode => throw new Exception("alias is not supported"), + _ => throw new ArgumentOutOfRangeException(nameof(yamlNode)) + }; + } + + private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, IJsonNode jsonNode, string propertyName) + { + var dictionary = new Dictionary(); + var parent = new JsonObject(dictionary, jsonNode, propertyName); + + foreach (var map in yamlMappingNode.Children) + { + var key = map.Key as YamlScalarNode; + var childParentName = key!.Value; + var value = ParseYamlNode(map.Value, parent, childParentName); + dictionary[childParentName] = value; + } + + return parent; + } +} diff --git a/mooresmaster.Tests/Test.cs b/mooresmaster.Tests/Test.cs index c1fbd54..2cf3720 100644 --- a/mooresmaster.Tests/Test.cs +++ b/mooresmaster.Tests/Test.cs @@ -10,6 +10,7 @@ using mooresmaster.Generator.JsonSchema; using mooresmaster.Generator.NameResolve; using mooresmaster.Generator.Semantic; +using mooresmaster.Generator.Yaml; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Xunit; @@ -89,9 +90,8 @@ public static (SchemaTable schemaTable, NameTable nameTable, Semantics semantics foreach (var yaml in yamlTexts) { - var jsonSchema = Yaml.ToJson(yaml); - var json = JsonParser.Parse(JsonTokenizer.GetTokens(jsonSchema)); - var schema = JsonSchemaParser.ParseSchema(json as JsonObject, schemaTable); + var json = YamlParser.Parse(yaml); + var schema = JsonSchemaParser.ParseSchema(json, schemaTable); schemaFileList.Add(new SchemaFile("", schema)); } From 4080e67540f1b96294e6a5bcaba0791c8449c65a Mon Sep 17 00:00:00 2001 From: Juha Date: Mon, 27 Jan 2025 13:46:15 +0900 Subject: [PATCH 2/6] =?UTF-8?q?yaml=E3=81=8B=E3=82=89json=E3=82=92?= =?UTF-8?q?=E7=8B=AC=E8=87=AA=E3=81=AB=E7=94=9F=E6=88=90=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jsonparserはもうお役御免 --- .../MooresmasterSourceGenerator.cs | 8 +-- mooresmaster.Generator/Yaml/YamlParser.cs | 54 +++++++++++++++---- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/mooresmaster.Generator/MooresmasterSourceGenerator.cs b/mooresmaster.Generator/MooresmasterSourceGenerator.cs index 45e3d34..c3df0b6 100644 --- a/mooresmaster.Generator/MooresmasterSourceGenerator.cs +++ b/mooresmaster.Generator/MooresmasterSourceGenerator.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.IO; -using System.Linq; using Microsoft.CodeAnalysis; using mooresmaster.Generator.Analyze; using mooresmaster.Generator.Analyze.Analyzers; @@ -13,6 +12,8 @@ using mooresmaster.Generator.NameResolve; using mooresmaster.Generator.Semantic; using mooresmaster.Generator.Yaml; +using Enumerable = System.Linq.Enumerable; +using ImmutableArrayExtensions = System.Linq.ImmutableArrayExtensions; namespace mooresmaster.Generator; @@ -37,6 +38,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var isSourceGeneratorDebug = environmentVariables.TryGetValue(Tokens.IsSourceGeneratorDebug, out var value) && value == "true"; #pragma warning restore RS1035 if (isSourceGeneratorDebug) throw e; + throw e; } }); } @@ -76,7 +78,7 @@ private void Emit(SourceProductionContext context, (Compilation compilation, Imm analyzer.PostJsonSchemaLayerAnalyze(analysis, schemas, schemaTable); analyzer.PreSemanticsLayerAnalyze(analysis, schemas, schemaTable); - var semantics = SemanticsGenerator.Generate(schemas.Select(schema => schema.Schema).ToImmutableArray(), schemaTable); + var semantics = SemanticsGenerator.Generate(ImmutableArrayExtensions.Select(schemas, schema => schema.Schema).ToImmutableArray(), schemaTable); analyzer.PostSemanticsLayerAnalyze(analysis, semantics, schemas, schemaTable); var nameTable = NameResolver.Resolve(semantics, schemaTable); @@ -105,7 +107,7 @@ private void Emit(SourceProductionContext context, (Compilation compilation, Imm var schemaTable = new SchemaTable(); var parsedFiles = new HashSet(); - foreach (var additionalText in additionalTexts.Where(a => Path.GetExtension(a.Path) == ".yml").Where(a => !parsedFiles.Contains(a.Path))) + foreach (var additionalText in Enumerable.Where(ImmutableArrayExtensions.Where(additionalTexts, a => Path.GetExtension(a.Path) == ".yml"), a => !parsedFiles.Contains(a.Path))) { var yamlText = additionalText.GetText()!.ToString(); var json = YamlParser.Parse(yamlText); diff --git a/mooresmaster.Generator/Yaml/YamlParser.cs b/mooresmaster.Generator/Yaml/YamlParser.cs index 87ae428..4fd0ead 100644 --- a/mooresmaster.Generator/Yaml/YamlParser.cs +++ b/mooresmaster.Generator/Yaml/YamlParser.cs @@ -11,7 +11,7 @@ public static class YamlParser public static JsonObject Parse(string yamlText) { var document = ParseYamlDocument(yamlText); - foreach (var node in document.RootNode.AllNodes) Console.WriteLine($"{node.GetType()} {node}"); + foreach (var node in ((YamlMappingNode)document.RootNode).Children) Console.WriteLine($"{node.GetType()} {node}"); return ParseYamlNode(document); } @@ -28,34 +28,70 @@ private static YamlDocument ParseYamlDocument(string yamlText) private static JsonObject ParseYamlNode(YamlDocument yamlDocument) { - return null; + var node = (YamlMappingNode)yamlDocument.RootNode; + return ParseYamlMappingNode(node, null, null); } - private static IJsonNode ParseYamlNode(YamlNode yamlNode, IJsonNode jsonNode, string propertyName) + private static IJsonNode ParseYamlNode(YamlNode yamlNode, IJsonNode jsonNode, string? propertyName) { return yamlNode switch { YamlMappingNode yamlMappingNode => ParseYamlMappingNode(yamlMappingNode, jsonNode, propertyName), - YamlScalarNode yamlScalarNode => throw new NotImplementedException(), - YamlSequenceNode yamlSequenceNode => throw new NotImplementedException(), + YamlScalarNode yamlScalarNode => ParseYamlScalarNode(yamlScalarNode, jsonNode, propertyName), + YamlSequenceNode yamlSequenceNode => ParseYamlSequenceNode(yamlSequenceNode, jsonNode, propertyName), YamlAliasNode => throw new Exception("alias is not supported"), _ => throw new ArgumentOutOfRangeException(nameof(yamlNode)) }; } - private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, IJsonNode jsonNode, string propertyName) + private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, IJsonNode parentJsonNode, string? propertyName) { var dictionary = new Dictionary(); - var parent = new JsonObject(dictionary, jsonNode, propertyName); + var jsonObject = new JsonObject(dictionary, parentJsonNode, propertyName); foreach (var map in yamlMappingNode.Children) { var key = map.Key as YamlScalarNode; var childParentName = key!.Value; - var value = ParseYamlNode(map.Value, parent, childParentName); + var value = ParseYamlNode(map.Value, jsonObject, childParentName); dictionary[childParentName] = value; } - return parent; + return jsonObject; + } + + /// + /// boolean(true) boolean(false) integer float string + /// 上の順で評価 + /// + private static IJsonNode ParseYamlScalarNode(YamlScalarNode yamlScalarNode, IJsonNode parentJsonNode, string? propertyName) + { + // boolean + if (yamlScalarNode.Value is "true" or "True" or "TRUE") return new JsonBoolean(true, parentJsonNode, propertyName); + if (yamlScalarNode.Value is "false" or "False" or "FALSE") return new JsonBoolean(false, parentJsonNode, propertyName); + + // integer + if (long.TryParse(yamlScalarNode.Value, out var intValue)) return new JsonInt(intValue, parentJsonNode, propertyName); + + // float + if (double.TryParse(yamlScalarNode.Value, out var floatValue)) return new JsonNumber(floatValue, parentJsonNode, propertyName); + + // string + return new JsonString(yamlScalarNode.Value ?? "", parentJsonNode, propertyName); + } + + private static JsonArray ParseYamlSequenceNode(YamlSequenceNode yamlSequenceNode, IJsonNode parentJsonNode, string? propertyName) + { + var nodes = new IJsonNode[yamlSequenceNode.Children.Count]; + var jsonArray = new JsonArray(nodes, parentJsonNode, propertyName); + + for (var i = 0; i < yamlSequenceNode.Children.Count; i++) + { + var child = yamlSequenceNode.Children[i]; + var childJsonNode = ParseYamlNode(child, jsonArray, null); + nodes[i] = childJsonNode; + } + + return jsonArray; } } From ba6badce98d24d6780919d116fb02864f6e91d39 Mon Sep 17 00:00:00 2001 From: Juha Date: Mon, 27 Jan 2025 14:17:33 +0900 Subject: [PATCH 3/6] =?UTF-8?q?yaml=E3=81=8B=E3=82=89json=E3=81=ABlocation?= =?UTF-8?q?=E6=83=85=E5=A0=B1=E3=82=92=E6=B8=A1=E3=81=99=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mooresmaster.Generator/Json/JsonParser.cs | 166 ++++++---------------- mooresmaster.Generator/Yaml/YamlParser.cs | 16 ++- 2 files changed, 49 insertions(+), 133 deletions(-) diff --git a/mooresmaster.Generator/Json/JsonParser.cs b/mooresmaster.Generator/Json/JsonParser.cs index 2bf90fd..72bba3e 100644 --- a/mooresmaster.Generator/Json/JsonParser.cs +++ b/mooresmaster.Generator/Json/JsonParser.cs @@ -1,172 +1,86 @@ -using System; using System.Collections.Generic; +using YamlDotNet.Core; +using YamlDotNet.RepresentationModel; namespace mooresmaster.Generator.Json; +public struct Location +{ + public long StartLine; + public long StartColumn; + public long EndLine; + public long EndColumn; + + private static Location Create(Mark start, Mark end) + { + return new Location + { + StartLine = start.Line, + StartColumn = start.Column, + EndLine = end.Line, + EndColumn = end.Column + }; + } + + public static Location Create(YamlNode yamlNode) + { + return Create(yamlNode.Start, yamlNode.End); + } +} + public interface IJsonNode { IJsonNode? Parent { get; } string? PropertyName { get; } + Location Location { get; } } -public record JsonObject(Dictionary Nodes, IJsonNode? Parent, string? PropertyName) : IJsonNode +public record JsonObject(Dictionary Nodes, IJsonNode? Parent, string? PropertyName, Location Location) : IJsonNode { public readonly Dictionary Nodes = Nodes; public IJsonNode? this[string key] => Nodes.ContainsKey(key) ? Nodes[key] : null; public IJsonNode? Parent { get; } = Parent; public string? PropertyName { get; } = PropertyName; + public Location Location { get; } = Location; } -public record JsonArray(IJsonNode[] Nodes, IJsonNode? Parent, string? PropertyName) : IJsonNode +public record JsonArray(IJsonNode[] Nodes, IJsonNode? Parent, string? PropertyName, Location Location) : IJsonNode { public IJsonNode[] Nodes = Nodes; public IJsonNode? this[int index] => Nodes.Length > index ? Nodes[index] : null; public IJsonNode? Parent { get; } = Parent; public string? PropertyName { get; } = PropertyName; + public Location Location { get; } = Location; } -public record JsonString(string Literal, IJsonNode? Parent, string? PropertyName) : IJsonNode +public record JsonString(string Literal, IJsonNode? Parent, string? PropertyName, Location Location) : IJsonNode { + public readonly string Literal = Literal; public string? PropertyName { get; } = PropertyName; + public Location Location { get; } = Location; public IJsonNode? Parent { get; } = Parent; - public readonly string Literal = Literal; } -public record JsonBoolean(bool Literal, IJsonNode? Parent, string? PropertyName) : IJsonNode +public record JsonBoolean(bool Literal, IJsonNode? Parent, string? PropertyName, Location Location) : IJsonNode { public readonly bool Literal = Literal; public IJsonNode? Parent { get; } = Parent; public string? PropertyName { get; } = PropertyName; + public Location Location { get; } = Location; } -public record JsonNumber(double Literal, IJsonNode? Parent, string? PropertyName) : IJsonNode +public record JsonNumber(double Literal, IJsonNode? Parent, string? PropertyName, Location Location) : IJsonNode { public readonly double Literal = Literal; public IJsonNode? Parent { get; } = Parent; public string? PropertyName { get; } = PropertyName; + public Location Location { get; } = Location; } -public record JsonInt(long Literal, IJsonNode? Parent, string? PropertyName) : IJsonNode +public record JsonInt(long Literal, IJsonNode? Parent, string? PropertyName, Location Location) : IJsonNode { public readonly long Literal = Literal; public IJsonNode? Parent { get; } = Parent; public string? PropertyName { get; } = PropertyName; -} - -public static class JsonParser -{ - public static IJsonNode Parse(Token[] tokens) - { - var iterator = new Iterator(tokens); - return Parse(ref iterator, null, null); - } - - private static IJsonNode Parse(ref Iterator iterator, IJsonNode? parent, string? name) - { - return iterator.CurrentToken.Type switch - { - TokenType.String => ParseString(ref iterator, parent, name), - TokenType.LBrace => ParseObject(ref iterator, parent, name), - TokenType.LSquare => ParseArray(ref iterator, parent, name), - TokenType.True or TokenType.False => ParseBoolean(ref iterator, parent, name), - TokenType.Number => ParseNumber(ref iterator, parent, name), - TokenType.Int => ParseInt(ref iterator, parent, name), - _ => throw new Exception($"""Unexpected token: {iterator.CurrentToken.Type} "{iterator.CurrentToken.Literal}" """) - }; - } - - private static IJsonNode ParseMinus(ref Iterator iterator, IJsonNode? parent, string? name) - { - iterator.CurrentIndex++; // skip '-' - switch (iterator.CurrentToken.Type) - { - case TokenType.Int: - var intValue = ParseInt(ref iterator, parent, name); - return new JsonInt(-intValue.Literal, parent, name); - case TokenType.Number: - var numberValue = ParseNumber(ref iterator, parent, name); - return new JsonNumber(-numberValue.Literal, parent, name); - default: - throw new ArgumentOutOfRangeException(); - } - } - - private static JsonInt ParseInt(ref Iterator iterator, IJsonNode? parent, string? name) - { - var value = iterator.CurrentToken.Literal; - iterator.CurrentIndex++; // skip int - return new JsonInt(long.Parse(value), parent, name); - } - - private static JsonNumber ParseNumber(ref Iterator iterator, IJsonNode? parent, string? name) - { - var value = iterator.CurrentToken.Literal; - iterator.CurrentIndex++; // skip number - return new JsonNumber(double.Parse(value), parent, name); - } - - private static JsonBoolean ParseBoolean(ref Iterator iterator, IJsonNode? parent, string? name) - { - var value = iterator.CurrentToken.Literal; - iterator.CurrentIndex++; // skip boolean - return new JsonBoolean(value == "true", parent, name); - } - - private static JsonString ParseString(ref Iterator iterator, IJsonNode? parent, string? name) - { - var value = iterator.CurrentToken.Literal; - iterator.CurrentIndex++; // skip string - return new JsonString(value, parent, name); - } - - private static JsonArray ParseArray(ref Iterator iterator, IJsonNode? parent, string? name) - { - var nodes = new List(); - iterator.CurrentIndex++; // skip '[' - - var jsonNode = new JsonArray([], parent, name); - - while (iterator.CurrentToken.Type != TokenType.RSquare) - { - nodes.Add(Parse(ref iterator, jsonNode, null)); - if (iterator.CurrentToken.Type == TokenType.RSquare) break; - iterator.CurrentIndex++; // skip ',' - } - - iterator.CurrentIndex++; // skip ']' - - jsonNode.Nodes = nodes.ToArray(); - - return jsonNode; - } - - private static JsonObject ParseObject(ref Iterator iterator, IJsonNode? parent, string? name) - { - var nodes = new Dictionary(); - iterator.CurrentIndex++; // skip '{' - - var jsonNode = new JsonObject(nodes, parent, name); - - while (iterator.CurrentToken.Type != TokenType.RBrace) - { - var key = iterator.CurrentToken.Literal; - iterator.CurrentIndex++; // skip string - iterator.CurrentIndex++; // skip ':' - var value = Parse(ref iterator, jsonNode, key); - nodes.Add(key, value); - if (iterator.CurrentToken.Type == TokenType.RBrace) break; - iterator.CurrentIndex++; // skip ',' - } - - iterator.CurrentIndex++; // skip '}' - - return jsonNode; - } - - public struct Iterator(Token[] tokens) - { - public int CurrentIndex; - public Token CurrentToken => tokens.Length > CurrentIndex ? tokens[CurrentIndex] : new Token(TokenType.Illegal, ""); - public Token NextToken => tokens.Length > CurrentIndex + 1 ? tokens[CurrentIndex + 1] : new Token(TokenType.Illegal, ""); - } + public Location Location { get; } = Location; } diff --git a/mooresmaster.Generator/Yaml/YamlParser.cs b/mooresmaster.Generator/Yaml/YamlParser.cs index 4fd0ead..46edcda 100644 --- a/mooresmaster.Generator/Yaml/YamlParser.cs +++ b/mooresmaster.Generator/Yaml/YamlParser.cs @@ -47,7 +47,7 @@ private static IJsonNode ParseYamlNode(YamlNode yamlNode, IJsonNode jsonNode, st private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, IJsonNode parentJsonNode, string? propertyName) { var dictionary = new Dictionary(); - var jsonObject = new JsonObject(dictionary, parentJsonNode, propertyName); + var jsonObject = new JsonObject(dictionary, parentJsonNode, propertyName, Location.Create(yamlMappingNode)); foreach (var map in yamlMappingNode.Children) { @@ -66,24 +66,26 @@ private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, /// private static IJsonNode ParseYamlScalarNode(YamlScalarNode yamlScalarNode, IJsonNode parentJsonNode, string? propertyName) { + var location = Location.Create(yamlScalarNode); + // boolean - if (yamlScalarNode.Value is "true" or "True" or "TRUE") return new JsonBoolean(true, parentJsonNode, propertyName); - if (yamlScalarNode.Value is "false" or "False" or "FALSE") return new JsonBoolean(false, parentJsonNode, propertyName); + if (yamlScalarNode.Value is "true" or "True" or "TRUE") return new JsonBoolean(true, parentJsonNode, propertyName, location); + if (yamlScalarNode.Value is "false" or "False" or "FALSE") return new JsonBoolean(false, parentJsonNode, propertyName, location); // integer - if (long.TryParse(yamlScalarNode.Value, out var intValue)) return new JsonInt(intValue, parentJsonNode, propertyName); + if (long.TryParse(yamlScalarNode.Value, out var intValue)) return new JsonInt(intValue, parentJsonNode, propertyName, location); // float - if (double.TryParse(yamlScalarNode.Value, out var floatValue)) return new JsonNumber(floatValue, parentJsonNode, propertyName); + if (double.TryParse(yamlScalarNode.Value, out var floatValue)) return new JsonNumber(floatValue, parentJsonNode, propertyName, location); // string - return new JsonString(yamlScalarNode.Value ?? "", parentJsonNode, propertyName); + return new JsonString(yamlScalarNode.Value ?? "", parentJsonNode, propertyName, location); } private static JsonArray ParseYamlSequenceNode(YamlSequenceNode yamlSequenceNode, IJsonNode parentJsonNode, string? propertyName) { var nodes = new IJsonNode[yamlSequenceNode.Children.Count]; - var jsonArray = new JsonArray(nodes, parentJsonNode, propertyName); + var jsonArray = new JsonArray(nodes, parentJsonNode, propertyName, Location.Create(yamlSequenceNode)); for (var i = 0; i < yamlSequenceNode.Children.Count; i++) { From cf5f08cc06633e2abc9eae2e3cf86e1c65cbd767 Mon Sep 17 00:00:00 2001 From: Juha Date: Wed, 29 Jan 2025 08:55:23 +0900 Subject: [PATCH 4/6] =?UTF-8?q?defineinterface=E9=96=A2=E4=BF=82=E3=81=AE?= =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=A7=E5=AE=9F=E9=9A=9B=E3=81=AB?= =?UTF-8?q?location=E3=82=92=E7=B5=84=E3=81=BF=E8=BE=BC=E3=82=80=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mooresmaster.Generator/Analyze/Analysis.cs | 2 ++ .../Analyzers/DefineInterfaceScopeAnalyzer.cs | 19 +++++++++++++++---- mooresmaster.Generator/DefineInterface.cs | 11 ++++++++++- .../JsonSchema/JsonSchemaParser.cs | 13 ++++++++++--- .../MooresmasterSourceGenerator.cs | 1 - mooresmaster.SandBox/schema/blocks.yml | 7 +++++++ 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/mooresmaster.Generator/Analyze/Analysis.cs b/mooresmaster.Generator/Analyze/Analysis.cs index e294e1b..5a535fd 100644 --- a/mooresmaster.Generator/Analyze/Analysis.cs +++ b/mooresmaster.Generator/Analyze/Analysis.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using mooresmaster.Generator.Json; namespace mooresmaster.Generator.Analyze; @@ -26,6 +27,7 @@ public void ThrowDiagnostics() public interface IDiagnostics { string Message { get; } + public Location Location { get; } } public class AnalyzeException : Exception diff --git a/mooresmaster.Generator/Analyze/Analyzers/DefineInterfaceScopeAnalyzer.cs b/mooresmaster.Generator/Analyze/Analyzers/DefineInterfaceScopeAnalyzer.cs index 98384f4..976b557 100644 --- a/mooresmaster.Generator/Analyze/Analyzers/DefineInterfaceScopeAnalyzer.cs +++ b/mooresmaster.Generator/Analyze/Analyzers/DefineInterfaceScopeAnalyzer.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using System.Linq; +using mooresmaster.Generator.Json; using mooresmaster.Generator.JsonSchema; using mooresmaster.Generator.Semantic; @@ -15,11 +16,16 @@ public void PostSemanticsLayerAnalyze(Analysis analysis, Semantics semantics, Im // 依存対象のinterfaceも後で調査するため再起的に全て調査する必要はない foreach (var (implementationInterfaceId, implementation) in implementations.Select(i => (i, semantics.InterfaceSemanticsTable[i]))) + { + var node = interfaceSemantics.Interface.ImplementationNodes[implementation.Interface.InterfaceName]; + var location = node.Location; + if (interfaceSemantics.Interface.IsGlobal) { // グローバルなら依存対象も全てglobalでないといけない if (implementation.Interface.IsGlobal) continue; - analysis.ReportDiagnostics(new DefineInterfaceGlobalScopeDiagnostics(id, implementationInterfaceId, semantics)); + + analysis.ReportDiagnostics(new DefineInterfaceGlobalScopeDiagnostics(id, implementationInterfaceId, semantics, location)); } else { @@ -27,12 +33,13 @@ public void PostSemanticsLayerAnalyze(Analysis analysis, Semantics semantics, Im if (implementation.Interface.IsGlobal) continue; if (implementation.Schema.SchemaId == interfaceSemantics.Schema.SchemaId) continue; - analysis.ReportDiagnostics(new DefineInterfaceLocalScopeDiagnostics(id, implementationInterfaceId, semantics)); + analysis.ReportDiagnostics(new DefineInterfaceLocalScopeDiagnostics(id, implementationInterfaceId, semantics, location)); } + } } } - public class DefineInterfaceGlobalScopeDiagnostics(InterfaceId targetInterfaceId, InterfaceId implementationInterfaceId, Semantics semantics) : IDiagnostics + public class DefineInterfaceGlobalScopeDiagnostics(InterfaceId targetInterfaceId, InterfaceId implementationInterfaceId, Semantics semantics, Location location) : IDiagnostics { public string Message => $""" Global interface cannot depend on local interface. @@ -40,10 +47,14 @@ Global interface cannot depend on local interface. TargetInterface {semantics.InterfaceSemanticsTable[targetInterfaceId].Interface.InterfaceName} ImplementationInterface {semantics.InterfaceSemanticsTable[implementationInterfaceId].Interface.InterfaceName} """; + + public Location Location => location; } - public class DefineInterfaceLocalScopeDiagnostics(InterfaceId targetInterfaceId, InterfaceId implementationInterfaceId, Semantics semantics) : IDiagnostics + public class DefineInterfaceLocalScopeDiagnostics(InterfaceId targetInterfaceId, InterfaceId implementationInterfaceId, Semantics semantics, Location location) : IDiagnostics { + public Location Location { get; } = location; + public string Message => $""" Local interface can only depend on global interface or same scope local interface. diff --git a/mooresmaster.Generator/DefineInterface.cs b/mooresmaster.Generator/DefineInterface.cs index d702aa6..682597f 100644 --- a/mooresmaster.Generator/DefineInterface.cs +++ b/mooresmaster.Generator/DefineInterface.cs @@ -1,11 +1,20 @@ using System.Collections.Generic; +using mooresmaster.Generator.Json; using mooresmaster.Generator.JsonSchema; namespace mooresmaster.Generator; -public class DefineInterface(string rootSchemaId, string interfaceName, Dictionary properties, string[] implementationInterfaces, bool isGlobal) +public class DefineInterface( + string rootSchemaId, + string interfaceName, + Dictionary properties, + string[] implementationInterfaces, + Dictionary implementationNodes, + bool isGlobal +) { public string[] ImplementationInterfaces = implementationInterfaces; + public Dictionary ImplementationNodes = implementationNodes; public string InterfaceName = interfaceName; public bool IsGlobal = isGlobal; public Dictionary Properties = properties; diff --git a/mooresmaster.Generator/JsonSchema/JsonSchemaParser.cs b/mooresmaster.Generator/JsonSchema/JsonSchemaParser.cs index 18e5dbb..13287c1 100644 --- a/mooresmaster.Generator/JsonSchema/JsonSchemaParser.cs +++ b/mooresmaster.Generator/JsonSchema/JsonSchemaParser.cs @@ -74,18 +74,25 @@ private static DefineInterface ParseDefineInterface(string id, JsonObject node, } // interfaceの継承情報を取得 - var implementationInterfaces = new List(); + var implementationNodes = new Dictionary(); if (node.Nodes.TryGetValue(Tokens.ImplementationInterfaceKey, out var implementationInterfacesNode) && implementationInterfacesNode is JsonArray nodesArray) foreach (var implementationInterfaceNode in nodesArray.Nodes) { var name = (JsonString)implementationInterfaceNode; - implementationInterfaces.Add(name.Literal); + implementationNodes[name.Literal] = name; } if (interfaceName == null) throw new Exception("interfaceName is null"); if (properties == null) throw new Exception("properties is null"); - return new DefineInterface(id, interfaceName, properties, implementationInterfaces.ToArray(), isGlobal); + return new DefineInterface( + id, + interfaceName, + properties, + implementationNodes.Keys.ToArray(), + implementationNodes, + isGlobal + ); } private static SchemaId Parse(JsonObject root, SchemaId? parent, SchemaTable schemaTable) diff --git a/mooresmaster.Generator/MooresmasterSourceGenerator.cs b/mooresmaster.Generator/MooresmasterSourceGenerator.cs index c3df0b6..ed611a5 100644 --- a/mooresmaster.Generator/MooresmasterSourceGenerator.cs +++ b/mooresmaster.Generator/MooresmasterSourceGenerator.cs @@ -38,7 +38,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var isSourceGeneratorDebug = environmentVariables.TryGetValue(Tokens.IsSourceGeneratorDebug, out var value) && value == "true"; #pragma warning restore RS1035 if (isSourceGeneratorDebug) throw e; - throw e; } }); } diff --git a/mooresmaster.SandBox/schema/blocks.yml b/mooresmaster.SandBox/schema/blocks.yml index 8846145..47bf248 100644 --- a/mooresmaster.SandBox/schema/blocks.yml +++ b/mooresmaster.SandBox/schema/blocks.yml @@ -8,6 +8,13 @@ defineInterface: type: integer - key: outputSlotCount type: integer +globalDefineInterface: + - interfaceName: IGlobalTest + implementationInterface: + - IMachineParam + properties: + - key: test + type: integer properties: - key: data type: array From a9684e6af483b52b7d7196b2287f05002a9484b2 Mon Sep 17 00:00:00 2001 From: Juha Date: Wed, 29 Jan 2025 08:59:02 +0900 Subject: [PATCH 5/6] =?UTF-8?q?location=E3=82=92=E5=AE=9F=E9=9A=9B?= =?UTF-8?q?=E3=81=ABdiagnostics=E3=81=AEmessage=E3=81=AB=E5=87=BA=E3=81=99?= =?UTF-8?q?=E3=82=88=E3=81=86=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mooresmaster.Generator/Analyze/Analysis.cs | 9 ++++++++- mooresmaster.Generator/Json/JsonParser.cs | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mooresmaster.Generator/Analyze/Analysis.cs b/mooresmaster.Generator/Analyze/Analysis.cs index 5a535fd..da30f5d 100644 --- a/mooresmaster.Generator/Analyze/Analysis.cs +++ b/mooresmaster.Generator/Analyze/Analysis.cs @@ -38,7 +38,14 @@ public AnalyzeException(IDiagnostics[] diagnosticsArray) { DiagnosticsArray = diagnosticsArray; var messages = new List(); - foreach (var diagnostics in diagnosticsArray) messages.Add($"type: {diagnostics.GetType().Name}\n {diagnostics.Message.Replace("\n", "\n ")}"); + foreach (var diagnostics in diagnosticsArray) + messages.Add( + $""" + type: {diagnostics.GetType().Name} + location: {diagnostics.Location} + {diagnostics.Message.Replace("\n", "\n ")} + """ + ); Message = string.Join("\n", messages); } diff --git a/mooresmaster.Generator/Json/JsonParser.cs b/mooresmaster.Generator/Json/JsonParser.cs index 72bba3e..12964b2 100644 --- a/mooresmaster.Generator/Json/JsonParser.cs +++ b/mooresmaster.Generator/Json/JsonParser.cs @@ -26,6 +26,11 @@ public static Location Create(YamlNode yamlNode) { return Create(yamlNode.Start, yamlNode.End); } + + public override string ToString() + { + return $"({StartLine}:{StartColumn} - {EndLine}:{EndColumn})"; + } } public interface IJsonNode From 26b3e4189c10b0dc79a6f85698df6489a2f3800a Mon Sep 17 00:00:00 2001 From: Juha Date: Wed, 29 Jan 2025 09:40:32 +0900 Subject: [PATCH 6/6] =?UTF-8?q?filepath=E3=82=82=E5=90=AB=E3=82=81?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mooresmaster.Generator/Json/JsonParser.cs | 12 ++++--- .../MooresmasterSourceGenerator.cs | 2 +- mooresmaster.Generator/Yaml/YamlParser.cs | 32 +++++++++---------- mooresmaster.Tests/Test.cs | 2 +- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/mooresmaster.Generator/Json/JsonParser.cs b/mooresmaster.Generator/Json/JsonParser.cs index 12964b2..ec4774d 100644 --- a/mooresmaster.Generator/Json/JsonParser.cs +++ b/mooresmaster.Generator/Json/JsonParser.cs @@ -6,30 +6,32 @@ namespace mooresmaster.Generator.Json; public struct Location { + public string FilePath; public long StartLine; public long StartColumn; public long EndLine; public long EndColumn; - private static Location Create(Mark start, Mark end) + private static Location Create(string filePath, Mark start, Mark end) { return new Location { StartLine = start.Line, StartColumn = start.Column, EndLine = end.Line, - EndColumn = end.Column + EndColumn = end.Column, + FilePath = filePath }; } - public static Location Create(YamlNode yamlNode) + public static Location Create(string filePath, YamlNode yamlNode) { - return Create(yamlNode.Start, yamlNode.End); + return Create(filePath, yamlNode.Start, yamlNode.End); } public override string ToString() { - return $"({StartLine}:{StartColumn} - {EndLine}:{EndColumn})"; + return $"({StartLine}:{StartColumn} - {EndLine}:{EndColumn}) in {FilePath}"; } } diff --git a/mooresmaster.Generator/MooresmasterSourceGenerator.cs b/mooresmaster.Generator/MooresmasterSourceGenerator.cs index ed611a5..a7f437a 100644 --- a/mooresmaster.Generator/MooresmasterSourceGenerator.cs +++ b/mooresmaster.Generator/MooresmasterSourceGenerator.cs @@ -109,7 +109,7 @@ private void Emit(SourceProductionContext context, (Compilation compilation, Imm foreach (var additionalText in Enumerable.Where(ImmutableArrayExtensions.Where(additionalTexts, a => Path.GetExtension(a.Path) == ".yml"), a => !parsedFiles.Contains(a.Path))) { var yamlText = additionalText.GetText()!.ToString(); - var json = YamlParser.Parse(yamlText); + var json = YamlParser.Parse(additionalText.Path, yamlText); var schema = JsonSchemaParser.ParseSchema(json!, schemaTable); schemas.Add(new SchemaFile(additionalText.Path, schema)); parsedFiles.Add(additionalText.Path); diff --git a/mooresmaster.Generator/Yaml/YamlParser.cs b/mooresmaster.Generator/Yaml/YamlParser.cs index 46edcda..67ab325 100644 --- a/mooresmaster.Generator/Yaml/YamlParser.cs +++ b/mooresmaster.Generator/Yaml/YamlParser.cs @@ -8,12 +8,12 @@ namespace mooresmaster.Generator.Yaml; public static class YamlParser { - public static JsonObject Parse(string yamlText) + public static JsonObject Parse(string filePath, string yamlText) { var document = ParseYamlDocument(yamlText); foreach (var node in ((YamlMappingNode)document.RootNode).Children) Console.WriteLine($"{node.GetType()} {node}"); - return ParseYamlNode(document); + return ParseYamlNode(filePath, document); } private static YamlDocument ParseYamlDocument(string yamlText) @@ -26,34 +26,34 @@ private static YamlDocument ParseYamlDocument(string yamlText) return document; } - private static JsonObject ParseYamlNode(YamlDocument yamlDocument) + private static JsonObject ParseYamlNode(string filePath, YamlDocument yamlDocument) { var node = (YamlMappingNode)yamlDocument.RootNode; - return ParseYamlMappingNode(node, null, null); + return ParseYamlMappingNode(filePath, node, null, null); } - private static IJsonNode ParseYamlNode(YamlNode yamlNode, IJsonNode jsonNode, string? propertyName) + private static IJsonNode ParseYamlNode(string filePath, YamlNode yamlNode, IJsonNode jsonNode, string? propertyName) { return yamlNode switch { - YamlMappingNode yamlMappingNode => ParseYamlMappingNode(yamlMappingNode, jsonNode, propertyName), - YamlScalarNode yamlScalarNode => ParseYamlScalarNode(yamlScalarNode, jsonNode, propertyName), - YamlSequenceNode yamlSequenceNode => ParseYamlSequenceNode(yamlSequenceNode, jsonNode, propertyName), + YamlMappingNode yamlMappingNode => ParseYamlMappingNode(filePath, yamlMappingNode, jsonNode, propertyName), + YamlScalarNode yamlScalarNode => ParseYamlScalarNode(filePath, yamlScalarNode, jsonNode, propertyName), + YamlSequenceNode yamlSequenceNode => ParseYamlSequenceNode(filePath, yamlSequenceNode, jsonNode, propertyName), YamlAliasNode => throw new Exception("alias is not supported"), _ => throw new ArgumentOutOfRangeException(nameof(yamlNode)) }; } - private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, IJsonNode parentJsonNode, string? propertyName) + private static JsonObject ParseYamlMappingNode(string filePath, YamlMappingNode yamlMappingNode, IJsonNode parentJsonNode, string? propertyName) { var dictionary = new Dictionary(); - var jsonObject = new JsonObject(dictionary, parentJsonNode, propertyName, Location.Create(yamlMappingNode)); + var jsonObject = new JsonObject(dictionary, parentJsonNode, propertyName, Location.Create(filePath, yamlMappingNode)); foreach (var map in yamlMappingNode.Children) { var key = map.Key as YamlScalarNode; var childParentName = key!.Value; - var value = ParseYamlNode(map.Value, jsonObject, childParentName); + var value = ParseYamlNode(filePath, map.Value, jsonObject, childParentName); dictionary[childParentName] = value; } @@ -64,9 +64,9 @@ private static JsonObject ParseYamlMappingNode(YamlMappingNode yamlMappingNode, /// boolean(true) boolean(false) integer float string /// 上の順で評価 /// - private static IJsonNode ParseYamlScalarNode(YamlScalarNode yamlScalarNode, IJsonNode parentJsonNode, string? propertyName) + private static IJsonNode ParseYamlScalarNode(string filePath, YamlScalarNode yamlScalarNode, IJsonNode parentJsonNode, string? propertyName) { - var location = Location.Create(yamlScalarNode); + var location = Location.Create(filePath, yamlScalarNode); // boolean if (yamlScalarNode.Value is "true" or "True" or "TRUE") return new JsonBoolean(true, parentJsonNode, propertyName, location); @@ -82,15 +82,15 @@ private static IJsonNode ParseYamlScalarNode(YamlScalarNode yamlScalarNode, IJso return new JsonString(yamlScalarNode.Value ?? "", parentJsonNode, propertyName, location); } - private static JsonArray ParseYamlSequenceNode(YamlSequenceNode yamlSequenceNode, IJsonNode parentJsonNode, string? propertyName) + private static JsonArray ParseYamlSequenceNode(string filePath, YamlSequenceNode yamlSequenceNode, IJsonNode parentJsonNode, string? propertyName) { var nodes = new IJsonNode[yamlSequenceNode.Children.Count]; - var jsonArray = new JsonArray(nodes, parentJsonNode, propertyName, Location.Create(yamlSequenceNode)); + var jsonArray = new JsonArray(nodes, parentJsonNode, propertyName, Location.Create(filePath, yamlSequenceNode)); for (var i = 0; i < yamlSequenceNode.Children.Count; i++) { var child = yamlSequenceNode.Children[i]; - var childJsonNode = ParseYamlNode(child, jsonArray, null); + var childJsonNode = ParseYamlNode(filePath, child, jsonArray, null); nodes[i] = childJsonNode; } diff --git a/mooresmaster.Tests/Test.cs b/mooresmaster.Tests/Test.cs index 2cf3720..ab64e11 100644 --- a/mooresmaster.Tests/Test.cs +++ b/mooresmaster.Tests/Test.cs @@ -90,7 +90,7 @@ public static (SchemaTable schemaTable, NameTable nameTable, Semantics semantics foreach (var yaml in yamlTexts) { - var json = YamlParser.Parse(yaml); + var json = YamlParser.Parse("TestDummyFilePath", yaml); var schema = JsonSchemaParser.ParseSchema(json, schemaTable); schemaFileList.Add(new SchemaFile("", schema)); }