139 lines
3.7 KiB
C#
139 lines
3.7 KiB
C#
|
using System.Collections;
|
||
|
using System.Reflection;
|
||
|
using System.Text;
|
||
|
using Antlr4.Runtime;
|
||
|
using Newtonsoft.Json;
|
||
|
|
||
|
namespace meowlang.parser;
|
||
|
|
||
|
[AttributeUsage(AttributeTargets.Property)]
|
||
|
public class IgnoreAttribute : Attribute
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public static class ObjectExtensions
|
||
|
{
|
||
|
public static string AutoToString(this object? o, bool prettyPrint = true, bool encapsulate = true)
|
||
|
{
|
||
|
if (o == null) return "null";
|
||
|
var type = o.GetType();
|
||
|
if (o is string s)
|
||
|
{
|
||
|
var escaped = s.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
||
|
return $"\"{escaped}\"";
|
||
|
}
|
||
|
|
||
|
if (o is bool b)
|
||
|
{
|
||
|
return b ? "true" : "false";
|
||
|
}
|
||
|
|
||
|
if (type.IsPrimitive)
|
||
|
{
|
||
|
return o.ToString()!;
|
||
|
}
|
||
|
|
||
|
if (type.IsEnum)
|
||
|
{
|
||
|
var val = Enum.GetName(type, o);
|
||
|
return $"\"{val}\"";
|
||
|
}
|
||
|
|
||
|
string json;
|
||
|
|
||
|
if (type.IsAssignableTo(typeof(IEnumerable)))
|
||
|
{
|
||
|
var enumerable = (o as IEnumerable)!.Cast<object>();
|
||
|
var sb = new StringBuilder();
|
||
|
sb.Append('[');
|
||
|
sb.AppendJoin(", ", enumerable.Select(x => x.AutoToString(false)));
|
||
|
sb.Append(']');
|
||
|
json = sb.ToString();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var properties = type.GetProperties();
|
||
|
var sb = new StringBuilder();
|
||
|
|
||
|
sb.Append('{');
|
||
|
sb.Append($"\"@type\": \"{type.Name}\"");
|
||
|
|
||
|
|
||
|
for (var index = 0; index < properties.Length; index++)
|
||
|
{
|
||
|
var propertyInfo = properties[index];
|
||
|
if (propertyInfo.GetCustomAttribute<IgnoreAttribute>() != null) continue;
|
||
|
sb.Append(',');
|
||
|
sb.Append($"\"{propertyInfo.Name}\": ");
|
||
|
var propertyValue = propertyInfo.GetValue(o);
|
||
|
sb.Append(propertyValue.AutoToString());
|
||
|
}
|
||
|
|
||
|
sb.Append('}');
|
||
|
json = sb.ToString();
|
||
|
}
|
||
|
|
||
|
if (prettyPrint)
|
||
|
{
|
||
|
var temp = JsonConvert.DeserializeObject(json);
|
||
|
json = JsonConvert.SerializeObject(temp, Formatting.Indented);
|
||
|
}
|
||
|
|
||
|
return json;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static class ParserRuleContextExtensions
|
||
|
{
|
||
|
public static Span GetSpan(this ParserRuleContext context)
|
||
|
{
|
||
|
return new Span(context.Start.TokenSource.SourceName, context.Start.StartIndex, context.Stop.StopIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static class TokenExtensions
|
||
|
{
|
||
|
public static Span GetSpan(this IToken token)
|
||
|
{
|
||
|
return new Span(token.TokenSource.SourceName, token.StartIndex, token.StopIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static class StringExtensions
|
||
|
{
|
||
|
public static string Unescape(this string str)
|
||
|
{
|
||
|
StringBuilder builder = new();
|
||
|
var startPos = 0;
|
||
|
int backslashPos;
|
||
|
while ((backslashPos = str.IndexOf('\\', startPos)) > -1)
|
||
|
{
|
||
|
builder.Append(str[startPos..backslashPos]);
|
||
|
int length;
|
||
|
string ch;
|
||
|
switch (str[backslashPos + 1])
|
||
|
{
|
||
|
case '\\':
|
||
|
ch = "\\";
|
||
|
length = 1;
|
||
|
break;
|
||
|
case '\'':
|
||
|
ch = "'";
|
||
|
length = 1;
|
||
|
break;
|
||
|
case '"':
|
||
|
ch = "\"";
|
||
|
length = 1;
|
||
|
break;
|
||
|
default:
|
||
|
throw new InvalidEscapeSequenceException($"\\{str[backslashPos + 1]}");
|
||
|
}
|
||
|
|
||
|
builder.Append(ch);
|
||
|
startPos = backslashPos + length + 1;
|
||
|
}
|
||
|
|
||
|
builder.Append(str[startPos..]);
|
||
|
return builder.ToString();
|
||
|
}
|
||
|
}
|