public static ISignature FromBuiltinSpec([NotNull] BuiltinSpec spec) { var pis = spec.Method.GetParameters(); var parts = pis .Skip(spec.Attr.Data == null ? 1 : 2) .Select(ConvertBuiltinParam) .ToArray(); var returnPart = ConvertBuiltinParam( spec.Method.ReturnParameter ?? throw new InvalidOperationException($"Missing {nameof(spec.Method.ReturnParameter)}")); return(new ZBuiltinSignature( spec.MinArgs, spec.MaxArgs, spec.Attr.MinVersion, spec.Attr.MaxVersion, parts, returnPart)); // helper SignaturePart ConvertBuiltinParam(ParameterInfo pi) { var type = pi.ParameterType; if (type == typeof(void)) { if (spec.CallType == typeof(VoidCall)) { return(LiteralPart.From("T")); } var part = SignatureBuilder.Constrained( SignatureBuilder.Identifier("$return"), spec.CallType == typeof(PredCall) ? Constraint.Boolean : Constraint.AnyObject); return(ApplyParamAttributes(part, pi)); } if (ParameterTypeHandler.Handlers.TryGetValue(type, out var handler)) { return(ConvertWithHandler(handler, pi)); } // ReSharper disable once PatternAlwaysOfType if (type.IsArray && type.GetElementType() is Type t && ParameterTypeHandler.Handlers.TryGetValue(t, out handler)) { var part = ConvertWithHandler(handler, pi); return(SignatureBuilder.VarArgs(part, false)); } throw new InvalidOperationException("Unexpected builtin param type"); } }
static SignaturePart ConstrainByType([NotNull] SignaturePart part, [NotNull] Type elementType) { System.Diagnostics.Debug.Assert(!elementType.IsArray); // treat Nullable<Foo> as an optional Foo bool isOptional = false; var nullableUnderlyingType = Nullable.GetUnderlyingType(elementType); if (nullableUnderlyingType != null) { isOptional = true; elementType = nullableUnderlyingType; } // treat LocalEnvironment as an optional ZilEnvironment if (elementType == typeof(LocalEnvironment)) { isOptional = true; elementType = typeof(ZilEnvironment); } // find an appropriate type or primtype constraint for the element type if (!StandardTypeConstraints.TryGetValue(elementType, out var constraint)) { BuiltinPrimTypeAttribute primTypeAttr; if ((primTypeAttr = elementType.GetCustomAttribute <BuiltinPrimTypeAttribute>(false)) != null) { constraint = Constraint.OfPrimType(primTypeAttr.PrimType); } else { BuiltinTypeAttribute typeAttr; if ((typeAttr = elementType.GetCustomAttribute <BuiltinTypeAttribute>(false)) != null) { constraint = Constraint.OfType(typeAttr.Name); } else { throw new UnhandledCaseException(elementType.Name); } } } part = SignatureBuilder.Constrained(part, constraint); return(isOptional ? SignatureBuilder.Optional(part) : part); }
static SignaturePart ApplyParamAttributes([NotNull] SignaturePart part, [NotNull] ParameterInfo pi) { // TODO: also handle VariableAttribute? if (pi.IsDefined(typeof(TableAttribute), false)) { part = SignatureBuilder.Constrained(part, Constraint.OfPrimType(PrimType.TABLE)); } if (pi.IsDefined(typeof(ObjectAttribute), false)) { part = SignatureBuilder.Constrained(part, Constraint.OfType(StdAtom.OBJECT)); } if (pi.IsOptional) { part = SignatureBuilder.Optional(part); } return(part); }