using System; using System.Collections.Generic; namespace io.github.hatayama.uLoopMCP { internal static class DynamicCodeSourcePreparer { private const string InterpolatedStringMarker = "$\""; private const string InterpolatedVerbatimStringMarker = "$@\""; private const string VerbatimInterpolatedStringMarker = "@$\""; public static PreparedDynamicCode PrepareWithoutLiteralHoisting( string source, string namespaceName, string className) { return Prepare(source, namespaceName, className, false); } public static PreparedDynamicCode Prepare( string source, string namespaceName, string className) { return Prepare(source, namespaceName, className, true); } private static PreparedDynamicCode Prepare( string source, string namespaceName, string className, bool enableLiteralHoisting) { SourceShapeResult shape = SourceShaper.Analyze(source); if ((shape.HasNamespaceDeclaration || shape.HasTypeDeclaration) && !shape.HasTopLevelStatements) { return new PreparedDynamicCode(source, false, new List()); } if ((shape.HasNamespaceDeclaration || shape.HasTypeDeclaration) && shape.HasTopLevelStatements) { return new PreparedDynamicCode(null, false, new List()); } string body = shape.TopLevelBodyBuilder.ToString().TrimEnd(); bool hasReturn = TopLevelReturnDetector.HasTopLevelReturn(body); if (!hasReturn) { body = string.IsNullOrWhiteSpace(body) ? "return null;" : body + "\nreturn null;"; } HoistedLiteralRewriteResult hoistedResult = !enableLiteralHoisting || ShouldSkipLiteralHoisting(body) ? new HoistedLiteralRewriteResult(body, new List(), new List()) : DynamicCodeLiteralHoister.Rewrite(body); string preparedSource = WrapperTemplate.Build( shape.UsingDirectives, namespaceName, className, hoistedResult.RewrittenSource, hoistedResult.DeclarationLines); return new PreparedDynamicCode(preparedSource, true, hoistedResult.Bindings); } private static bool ShouldSkipLiteralHoisting(string body) { return body.Contains(InterpolatedStringMarker) || body.Contains(InterpolatedVerbatimStringMarker) || body.Contains(VerbatimInterpolatedStringMarker) || ContainsInterpolatedRawStringMarker(body); } private static bool ContainsInterpolatedRawStringMarker(string body) { int quoteIndex = body.IndexOf("\"\"\"", StringComparison.Ordinal); while (quoteIndex >= 0) { int dollarCount = 0; int markerIndex = quoteIndex - 1; while (markerIndex >= 0 && body[markerIndex] == '$') { dollarCount++; markerIndex--; } if (dollarCount > 0) { return true; } quoteIndex = body.IndexOf("\"\"\"", quoteIndex + 3, StringComparison.Ordinal); } return false; } } }