101 lines
3.6 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|