meowlang/parser/Utils.cs
2022-02-13 03:02:23 +01:00

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();
}
}