using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Questionable.Model.V1; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Questionable.QuestPathGenerator; public static class RoslynShortcuts { public static IEnumerable SyntaxNodeList(params SyntaxNodeOrToken?[] nodes) { nodes = nodes.Where(x => x != null).ToArray(); if (nodes.Length == 0) return []; List list = new(); for (int i = 0; i < nodes.Length; ++i) { if (i > 0) list.Add(Token(SyntaxKind.CommaToken)); list.Add(nodes[i].GetValueOrDefault()); } return list; } public static ExpressionSyntax LiteralValue(T? value) { if (value is string s) return LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(s)); else if (value is bool b) return LiteralExpression(b ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression); else if (value is short i16) return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(i16)); else if (value is int i32) return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(i32)); else if (value is ushort u16) return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(u16)); else if (value is uint u32) return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(u32)); else if (value is float f) return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(f)); else if (value != null && value.GetType().IsEnum) return MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(value.GetType().Name), IdentifierName(value.GetType().GetEnumName(value)!)); else if (value is Vector3 vector) { return ObjectCreationExpression( IdentifierName(nameof(Vector3))) .WithArgumentList( ArgumentList( SeparatedList( new SyntaxNodeOrToken[] { Argument(LiteralValue(vector.X)), Token(SyntaxKind.CommaToken), Argument(LiteralValue(vector.Y)), Token(SyntaxKind.CommaToken), Argument(LiteralValue(vector.Z)) }))); } else if (value is AethernetShortcut aethernetShortcut) { return ObjectCreationExpression( IdentifierName(nameof(AethernetShortcut))) .WithInitializer( InitializerExpression( SyntaxKind.ObjectInitializerExpression, SeparatedList( SyntaxNodeList( Assignment(nameof(AethernetShortcut.From), aethernetShortcut.From, null) .AsSyntaxNodeOrToken(), Assignment(nameof(AethernetShortcut.To), aethernetShortcut.To, null) .AsSyntaxNodeOrToken())))); } else if (value is ChatMessage chatMessage) { ChatMessage emptyMessage = new(); return ObjectCreationExpression( IdentifierName(nameof(ChatMessage))) .WithInitializer( InitializerExpression( SyntaxKind.ObjectInitializerExpression, SeparatedList( SyntaxNodeList( Assignment(nameof(ChatMessage.ExcelSheet), chatMessage.ExcelSheet, emptyMessage.ExcelSheet) .AsSyntaxNodeOrToken(), Assignment(nameof(ChatMessage.Key), chatMessage.Key, emptyMessage.Key) .AsSyntaxNodeOrToken())))); } else if (value is DialogueChoice dialogueChoice) { DialogueChoice emptyChoice = new(); return ObjectCreationExpression( IdentifierName(nameof(DialogueChoice))) .WithInitializer( InitializerExpression( SyntaxKind.ObjectInitializerExpression, SeparatedList( SyntaxNodeList( Assignment(nameof(DialogueChoice.Type), dialogueChoice.Type, null) .AsSyntaxNodeOrToken(), Assignment(nameof(DialogueChoice.ExcelSheet), dialogueChoice.ExcelSheet, emptyChoice.ExcelSheet) .AsSyntaxNodeOrToken(), Assignment(nameof(DialogueChoice.Prompt), dialogueChoice.Prompt, emptyChoice.Prompt) .AsSyntaxNodeOrToken(), Assignment(nameof(DialogueChoice.Yes), dialogueChoice.Yes, emptyChoice.Yes) .AsSyntaxNodeOrToken(), Assignment(nameof(DialogueChoice.Answer), dialogueChoice.Answer, emptyChoice.Answer) .AsSyntaxNodeOrToken(), Assignment(nameof(DialogueChoice.DataId), dialogueChoice.DataId, emptyChoice.DataId) .AsSyntaxNodeOrToken())))); } else if (value is JumpDestination jumpDestination) { return ObjectCreationExpression( IdentifierName(nameof(JumpDestination))) .WithInitializer( InitializerExpression( SyntaxKind.ObjectInitializerExpression, SeparatedList( SyntaxNodeList( Assignment(nameof(JumpDestination.Position), jumpDestination.Position, null) .AsSyntaxNodeOrToken(), Assignment(nameof(JumpDestination.StopDistance), jumpDestination.StopDistance, null) .AsSyntaxNodeOrToken(), Assignment(nameof(JumpDestination.DelaySeconds), jumpDestination.DelaySeconds, null) .AsSyntaxNodeOrToken())))); } else if (value is ExcelRef excelRef) { if (excelRef.Type == ExcelRef.EType.Key) { return ObjectCreationExpression( IdentifierName(nameof(ExcelRef))) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument(LiteralValue(excelRef.AsKey()))))); } else if (excelRef.Type == ExcelRef.EType.RowId) { return ObjectCreationExpression( IdentifierName(nameof(ExcelRef))) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument(LiteralValue(excelRef.AsRowId()))))); } else throw new Exception($"Unsupported ExcelRef type {excelRef.Type}"); } else if (value is null) return LiteralExpression(SyntaxKind.NullLiteralExpression); else throw new Exception($"Unsupported data type {value.GetType()} = {value}"); } public static AssignmentExpressionSyntax? Assignment(string name, T? value, T? defaultValue) { if (value == null && defaultValue == null) return null; if (value != null && defaultValue != null && value.Equals(defaultValue)) return null; return AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(name), LiteralValue(value)); } public static AssignmentExpressionSyntax? AssignmentList(string name, IEnumerable value) { IEnumerable list = value.ToList(); if (!list.Any()) return null; return AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, IdentifierName(name), CollectionExpression( SeparatedList( SyntaxNodeList(list.Select(x => ExpressionElement( LiteralValue(x)).AsSyntaxNodeOrToken()).ToArray()) ))); } public static SyntaxNodeOrToken? AsSyntaxNodeOrToken(this SyntaxNode? node) { if (node == null) return null; return node; } }