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 ConvertForSubr( [NotNull] Type paramType, [NotNull] string name, // ReSharper disable once SuggestBaseTypeForParameter [NotNull][ItemNotNull] object[] attrs, bool isOptional, // ReSharper disable once UnusedParameter.Local object defaultValue) { // [Either], [Required], and [Decl] go on the parameter var isRequired = attrs.OfType <RequiredAttribute>().Any(); if (isRequired && isOptional) { throw new InvalidOperationException("A parameter can't be both required and optional"); } var eitherAttr = attrs.OfType <EitherAttribute>().SingleOrDefault(); var declAttr = attrs.OfType <DeclAttribute>().SingleOrDefault(); // [ZilStructuredParam] and [ZilSequenceParam] go on the element type var(isArray, elementType) = CheckArray(paramType); var structAttr = elementType.GetCustomAttribute <ZilStructuredParamAttribute>(false); var seqAttr = elementType.GetCustomAttribute <ZilSequenceParamAttribute>(false); int attrCount = (eitherAttr != null ? 1 : 0) + (declAttr != null ? 1 : 0) + (structAttr != null ? 1 : 0) + (seqAttr != null ? 1 : 0); if (attrCount > 1) { throw new InvalidOperationException( nameof(EitherAttribute) + ", " + nameof(DeclAttribute) + ", " + nameof(ZilStructuredParamAttribute) + ", or " + nameof(ZilSequenceParamAttribute) + ": pick at most one"); } SignaturePart elemPart = null; if (eitherAttr != null) { elemPart = ConvertEither(eitherAttr.Types, eitherAttr.DefaultParamDesc ?? name); } else if (declAttr != null) { elemPart = SignatureBuilder.MaybeConvertDecl(declAttr); } else if (structAttr != null) { elemPart = ConvertStruct(elementType, structAttr, name); } else if (seqAttr != null) { elemPart = ConvertSequence(elementType, name); } if (elemPart == null) { elemPart = SignatureBuilder.Identifier(name); if (elementType != typeof(ZilObject)) { elemPart = ConstrainByType(elemPart, elementType); } } if (isArray) { elemPart = SignatureBuilder.VarArgs(elemPart, isRequired); } if (isOptional) { //XXX use defaultValue somehow? elemPart = SignatureBuilder.Optional(elemPart); } return(elemPart); }