Files
ft/Client/Packages/io.github.hatayama.uloopmcp/Editor/Compilation/DynamicCodeSourcePreparer.cs

101 lines
3.6 KiB
C#

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<HoistedLiteralBinding>());
}
if ((shape.HasNamespaceDeclaration || shape.HasTypeDeclaration) && shape.HasTopLevelStatements)
{
return new PreparedDynamicCode(null, false, new List<HoistedLiteralBinding>());
}
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<HoistedLiteralBinding>(), new List<string>())
: 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;
}
}
}