Files
RobustToolbox/Robust.Shared/ContentPack/AssemblyTypeChecker.Parsing.cs
Pieter-Jan Briers a41f64f30e sandboxing (#1408)
2020-11-26 23:37:31 +01:00

206 lines
8.8 KiB
C#

using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Reflection.Metadata;
using Pidgin;
using static Pidgin.Parser;
using static Pidgin.Parser<char>;
namespace Robust.Shared.ContentPack
{
internal sealed partial class AssemblyTypeChecker
{
// Contains primary parsing code for method and field declarations in the sandbox whitelist.
private static readonly Parser<char, PrimitiveTypeCode> VoidTypeParser =
String("void").ThenReturn(PrimitiveTypeCode.Void);
private static readonly Parser<char, PrimitiveTypeCode> BooleanTypeParser =
String("bool").ThenReturn(PrimitiveTypeCode.Boolean);
private static readonly Parser<char, PrimitiveTypeCode> CharTypeParser =
String("char").ThenReturn(PrimitiveTypeCode.Char);
private static readonly Parser<char, PrimitiveTypeCode> SByteTypeParser =
String("sbyte").ThenReturn(PrimitiveTypeCode.SByte);
private static readonly Parser<char, PrimitiveTypeCode> ByteTypeParser =
String("byte").ThenReturn(PrimitiveTypeCode.Byte);
private static readonly Parser<char, PrimitiveTypeCode> Int16TypeParser =
String("short").ThenReturn(PrimitiveTypeCode.Int16);
private static readonly Parser<char, PrimitiveTypeCode> UInt16TypeParser =
String("ushort").ThenReturn(PrimitiveTypeCode.UInt32);
private static readonly Parser<char, PrimitiveTypeCode> Int32TypeParser =
String("int").ThenReturn(PrimitiveTypeCode.Int32);
private static readonly Parser<char, PrimitiveTypeCode> UInt32TypeParser =
String("uint").ThenReturn(PrimitiveTypeCode.UInt32);
private static readonly Parser<char, PrimitiveTypeCode> Int64TypeParser =
String("long").ThenReturn(PrimitiveTypeCode.Int64);
private static readonly Parser<char, PrimitiveTypeCode> UInt64TypeParser =
String("ulong").ThenReturn(PrimitiveTypeCode.UInt64);
private static readonly Parser<char, PrimitiveTypeCode> IntPtrTypeParser =
String("nint").ThenReturn(PrimitiveTypeCode.IntPtr);
private static readonly Parser<char, PrimitiveTypeCode> UIntPtrTypeParser =
String("nuint").ThenReturn(PrimitiveTypeCode.UIntPtr);
private static readonly Parser<char, PrimitiveTypeCode> SingleTypeParser =
String("float").ThenReturn(PrimitiveTypeCode.Single);
private static readonly Parser<char, PrimitiveTypeCode> DoubleTypeParser =
String("double").ThenReturn(PrimitiveTypeCode.Double);
private static readonly Parser<char, PrimitiveTypeCode> StringTypeParser =
String("string").ThenReturn(PrimitiveTypeCode.String);
private static readonly Parser<char, PrimitiveTypeCode> ObjectTypeParser =
String("object").ThenReturn(PrimitiveTypeCode.Object);
private static readonly Parser<char, PrimitiveTypeCode> TypedReferenceTypeParser =
String("typedref").ThenReturn(PrimitiveTypeCode.TypedReference);
private static readonly Parser<char, MType> PrimitiveTypeParser =
OneOf(
Try(VoidTypeParser),
Try(BooleanTypeParser),
Try(CharTypeParser),
Try(SByteTypeParser),
Try(ByteTypeParser),
Try(Int16TypeParser),
Try(UInt16TypeParser),
Try(Int32TypeParser),
Try(UInt32TypeParser),
Try(Int64TypeParser),
Try(UInt64TypeParser),
Try(IntPtrTypeParser),
Try(UIntPtrTypeParser),
Try(SingleTypeParser),
Try(DoubleTypeParser),
Try(StringTypeParser),
Try(ObjectTypeParser),
TypedReferenceTypeParser)
.Select(code => (MType) new MTypePrimitive(code)).Labelled("Primitive type");
private static readonly Parser<char, string> NamespacedIdentifier =
Token(c => char.IsLetterOrDigit(c) || c == '.' || c == '_' || c == '`')
.AtLeastOnceString()
.Labelled("valid identifier");
private static readonly Parser<char, IEnumerable<MType>> GenericParametersParser =
Rec(() => MaybeArrayTypeParser!)
.Between(SkipWhitespaces)
.Separated(Char(','))
.Between(Char('<'), Char('>'));
private static readonly Parser<char, MType> GenericMethodPlaceholderParser =
String("!!")
.Then(Digit.AtLeastOnceString())
.Select(p => (MType) new MTypeGenericMethodPlaceHolder(int.Parse(p, CultureInfo.InvariantCulture)));
private static readonly Parser<char, MType> GenericTypePlaceholderParser =
String("!")
.Then(Digit.AtLeastOnceString())
.Select(p => (MType) new MTypeGenericTypePlaceHolder(int.Parse(p, CultureInfo.InvariantCulture)));
private static readonly Parser<char, MType> GenericPlaceholderParser = Try(GenericTypePlaceholderParser)
.Or(Try(GenericMethodPlaceholderParser)).Labelled("Generic placeholder");
private static readonly Parser<char, MTypeParsed> TypeNameParser =
Parser.Map(
(a, b) => b.Aggregate(new MTypeParsed(a), (parsed, s) => new MTypeParsed(s, parsed)),
NamespacedIdentifier,
Char('/').Then(NamespacedIdentifier).Many());
private static readonly Parser<char, MType> ConstructedObjectTypeParser =
Parser.Map((arg1, arg2) =>
{
MType type = arg1;
if (arg2.HasValue)
{
type = new MTypeGeneric(type, arg2.Value.ToImmutableArray());
}
return type;
},
TypeNameParser,
GenericParametersParser.Optional());
private static readonly Parser<char, MType> MaybeArrayTypeParser = Parser.Map(
(a, b) => b.Aggregate(a, (type, _) => new MTypeSZArray(type)),
Try(GenericPlaceholderParser).Or(Try(PrimitiveTypeParser)).Or(ConstructedObjectTypeParser),
String("[]").Many());
private static readonly Parser<char, MType> ByRefTypeParser =
String("ref")
.Then(SkipWhitespaces)
.Then(MaybeArrayTypeParser)
.Select(t => (MType) new MTypeByRef(t))
.Labelled("ByRef type");
private static readonly Parser<char, MType> TypeParser = Try(ByRefTypeParser).Or(MaybeArrayTypeParser);
private static readonly Parser<char, ImmutableArray<MType>> MethodParamsParser =
TypeParser
.Between(SkipWhitespaces)
.Separated(Char(','))
.Between(Char('('), Char(')'))
.Select(p => p.ToImmutableArray());
internal static readonly Parser<char, int> MethodGenericParameterCountParser =
Try(Char(',').Many().Select(p => p.Count() + 1).Between(Char('<'), Char('>'))).Or(Return(0));
internal static readonly Parser<char, WhitelistMethodDefine> MethodParser =
Parser.Map(
(a, b, d, c) => new WhitelistMethodDefine(b, a, c, d),
SkipWhitespaces.Then(TypeParser),
SkipWhitespaces.Then(NamespacedIdentifier),
MethodGenericParameterCountParser,
SkipWhitespaces.Then(MethodParamsParser));
internal static readonly Parser<char, WhitelistFieldDefine> FieldParser = Parser.Map(
(a, b) => new WhitelistFieldDefine(b, a),
MaybeArrayTypeParser.Between(SkipWhitespaces),
NamespacedIdentifier);
internal sealed class WhitelistMethodDefine
{
public string Name { get; }
public MType ReturnType { get; }
public ImmutableArray<MType> ParameterTypes { get; }
public int GenericParameterCount { get; }
public WhitelistMethodDefine(
string name,
MType returnType,
ImmutableArray<MType> parameterTypes,
int genericParameterCount)
{
Name = name;
ReturnType = returnType;
ParameterTypes = parameterTypes;
GenericParameterCount = genericParameterCount;
}
}
internal sealed class WhitelistFieldDefine
{
public string Name { get; }
public MType FieldType { get; }
public WhitelistFieldDefine(string name, MType fieldType)
{
Name = name;
FieldType = fieldType;
}
}
}
}