170 lines
4.6 KiB
C#
170 lines
4.6 KiB
C#
using System.Collections;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
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}\"";
|
|
}
|
|
|
|
if (type.IsAssignableTo(typeof(Guid)))
|
|
{
|
|
var val = o.ToString();
|
|
return $"\"{val}\"";
|
|
}
|
|
|
|
string json;
|
|
|
|
if (o is ITuple t)
|
|
{
|
|
var values = Enumerable.Range(0, t.Length).Select(i => t[i]).ToList();
|
|
return values.AutoToString();
|
|
}
|
|
|
|
if (type.IsAssignableTo(typeof(IDictionary)))
|
|
{
|
|
var dictionary = (o as IDictionary);
|
|
var sb = new StringBuilder();
|
|
|
|
sb.Append('{');
|
|
|
|
var first = true;
|
|
foreach (DictionaryEntry entry in dictionary!)
|
|
{
|
|
if (!first) sb.Append(',');
|
|
first = false;
|
|
sb.Append($"\"{entry.Key.ToString()}\": {entry.Value.AutoToString()}");
|
|
}
|
|
|
|
sb.Append('}');
|
|
json = sb.ToString();
|
|
}
|
|
else 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, context.Start.Line);
|
|
}
|
|
}
|
|
|
|
internal static class TokenExtensions
|
|
{
|
|
public static Span GetSpan(this IToken token)
|
|
{
|
|
return new Span(token.TokenSource.SourceName, token.StartIndex, token.StopIndex, token.Line);
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
} |