Exemplo n.º 1
0
        /// <summary>
        /// Wires up parameters for a parameterized instance
        /// </summary>
        /// <param name="state">The validation state</param>
        /// <param name="sourceinstance">The instance to wire up</param>
        private void WireUpParameters(ValidationState state, Instance.IParameterizedInstance sourceinstance)
        {
            if (sourceinstance.MappedParameters.Count < sourceinstance.SourceParameters.Length)
            {
                if (sourceinstance.MappedParameters.Count != 0)
                {
                    throw new Exception("Unexpected half-filled parameter list");
                }

                var position = 0;
                var anynamed = false;
                var map      = new Instance.MappedParameter[sourceinstance.SourceParameters.Length];
                var scope    = state.LocalScopes[sourceinstance];

                // Map for getting the parameter index of a name
                var namelist = sourceinstance
                               .SourceParameters
                               .Zip(
                    Enumerable.Range(0, sourceinstance.SourceParameters.Length),
                    (p, i) => new { i, p.Name.Name }
                    );

                var collisions = namelist
                                 .GroupBy(x => x.Name)
                                 .Where(x => x.Count() != 1)
                                 .FirstOrDefault();

                if (collisions != null)
                {
                    throw new ParserException($"Multiple arguments named {collisions.Key}, positions: {string.Join(", ", collisions.Select(x => x.i.ToString())) }", sourceinstance.SourceParameters[collisions.Last().i].Name);
                }

                var nameindexmap = namelist.ToDictionary(x => x.Name, x => x.i);

                foreach (var p in sourceinstance.ParameterMap)
                {
                    var pos = position;
                    if (p.Name == null)
                    {
                        if (anynamed)
                        {
                            throw new ParserException($"Cannot have positional arguments after named arguments", p);
                        }
                    }
                    else
                    {
                        anynamed = true;
                        if (!nameindexmap.TryGetValue(p.Name.Name, out pos))
                        {
                            throw new ParserException($"No parameter named {p.Name.Name} in {sourceinstance.SourceName}", sourceinstance.SourceItem);
                        }
                    }

                    if (map[pos] != null)
                    {
                        throw new ParserException($"Double argument for {sourceinstance.SourceParameters[pos].Name.Name} detected", sourceinstance.SourceItem);
                    }

                    // Extract the parameter definition
                    var sourceparam = sourceinstance.SourceParameters[pos];

                    Instance.IInstance value;
                    var tc = p.Expression as AST.TypeCast;

                    if (tc != null)
                    {
                        value = state.ResolveSymbol(tc.Expression, scope);
                    }
                    else
                    {
                        value = state.ResolveSymbol(p.Expression, scope);
                    }

                    if (value == null)
                    {
                        throw new ParserException("Unable to resolve expression", p.Expression.SourceToken);
                    }

                    var itemtype      = state.InstanceType(value);
                    var parametertype =
                        sourceparam.ExplictType == null
                        ? itemtype
                        : state.ResolveTypeName(sourceparam.ExplictType, scope);

                    if (parametertype.IsValue && sourceparam.Direction == AST.ParameterDirection.Out)
                    {
                        throw new ParserException($"Cannot use a value-type parameter as output: {sourceparam.SourceToken}", sourceparam);
                    }

                    // We need to expand both types to intrinsics to remove any type aliases that need lookups
                    var intrinsic_itemtype      = state.ResolveToIntrinsics(itemtype, scope);
                    var intrinsic_parametertype = state.ResolveToIntrinsics(parametertype, scope);

                    // If the input is a typecast (and required) we wire it through a process
                    if (tc != null && !state.CanUnifyTypes(intrinsic_itemtype, intrinsic_parametertype, scope))
                    {
                        var typecast_target = state.ResolveToIntrinsics(state.ResolveTypeName(tc.TargetName, scope), scope);
                        var typecast_source = sourceparam.Direction == ParameterDirection.In ? intrinsic_itemtype : intrinsic_parametertype;

                        var sourceSignals = typecast_source
                                            .Shape
                                            .Signals
                                            .Select(x => x.Key)
                                            .ToHashSet();

                        var shared_shape =
                            typecast_target
                            .Shape
                            .Signals
                            .Where(x => sourceSignals.Contains(x.Key))
                            .Select(x => new AST.BusSignalDeclaration(
                                        p.SourceToken,
                                        new AST.Identifier(
                                            new ParseToken(0, 0, 0, x.Key)
                                            ),
                                        x.Value.Type,
                                        null,
                                        x.Value.Direction
                                        ))
                            .ToArray();

                        if (sourceSignals.Count != shared_shape.Length)
                        {
                            throw new ParserException($"The typecast is invalid as the names do not match", p.SourceToken);
                        }

                        var proc = IdentityHelper.CreateTypeCastProcess(
                            state,
                            scope,
                            p.SourceToken,
                            tc.Expression,
                            new AST.Name(p.SourceToken, new[] {
                            new AST.Identifier(new ParseToken(0, 0, 0, sourceinstance.Name)),
                            sourceparam.Name
                        }, null).AsExpression(),
                            shared_shape,
                            shared_shape
                            );

                        throw new ParserException($"Typecasts inside process instantiations are not currently supported", p.SourceToken);
                        // using (state.StartScope(proc))
                        //     CreateAndRegisterInstance(state, proc);
                        // parentCollection.Add(proc);
                    }

                    // Check argument compatibility
                    if (!state.CanUnifyTypes(intrinsic_itemtype, intrinsic_parametertype, scope))
                    {
                        throw new ParserException($"Cannot use {p.Expression.SourceToken} of type {intrinsic_itemtype.ToString()} as the argument for {sourceparam.Name.SourceToken} of type {intrinsic_parametertype}", p.Expression);
                    }

                    // Check that the type we use as input is "larger" than the target
                    var unified = state.UnifiedType(intrinsic_itemtype, parametertype, scope);
                    if (!object.Equals(unified, intrinsic_itemtype))
                    {
                        throw new ParserException($"Cannot use {p.Expression.SourceToken} of type {intrinsic_itemtype.ToString()} as the argument for {sourceparam.Name.SourceToken} of type {intrinsic_parametertype}", p.Expression);
                    }

                    map[pos] = new Instance.MappedParameter(p, sourceparam, value, parametertype);
                    var localname = map[pos].LocalName;

                    // Register the instance in the local symbol table to allow
                    // refering to the instance with the parameter name
                    scope.TryAddSymbol(localname, value, sourceparam.Name);
                    position++;
                }

                if (map.Any(x => x == null))
                {
                    throw new ParserException("Argument missing", sourceinstance.SourceItem);
                }

                sourceinstance.MappedParameters.AddRange(map);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Registers an item for usage in a particular direction
        /// </summary>
        /// <param name="scope">The scope to use</param>
        /// <param name="item">The item to register</param>
        /// <param name="direction">The direction to register</param>
        /// <param name="sourceExpr">The source expression used for error messages</param>
        public void RegisterItemUsageDirection(Instance.IParameterizedInstance scope, object item, ItemUsageDirection direction, AST.ParsedItem sourceExpr)
        {
            if (scope == null)
            {
                throw new ArgumentNullException(nameof(scope));
            }
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (!ItemDirection.TryGetValue(scope, out var usagescope))
            {
                ItemDirection[scope] = usagescope = new Dictionary <object, ItemUsageDirection>();
            }

            if (item is Instance.Signal signalInstance)
            {
                // Get list of parameters with direction from instantiation
                var directionParam = scope
                                     .MappedParameters
                                     .Zip(
                    Enumerable.Range(0, scope.MappedParameters.Count),
                    (x, i) => new
                {
                    Direction = scope.SourceParameters[i].Direction,
                    Bus       = x.MappedItem
                }
                    )
                                     .Where(x => x.Bus == signalInstance.ParentBus)
                                     .FirstOrDefault();

                // Local bus is bi-directional and does not need checking
                if (directionParam != null)
                {
                    var definedDirection = directionParam.Direction;

                    // Flip the signal if it has inverse direction
                    if (signalInstance.Source.Direction == SignalDirection.Inverse)
                    {
                        definedDirection =
                            definedDirection == ParameterDirection.In
                            ? ParameterDirection.Out
                            : ParameterDirection.In;
                    }

                    if (definedDirection == ParameterDirection.Out && direction != ItemUsageDirection.Write)
                    {
                        throw new ParserException($"Can only write to output signal: {signalInstance.Name}", sourceExpr);
                    }
                    if (definedDirection == ParameterDirection.In && direction != ItemUsageDirection.Read)
                    {
                        throw new ParserException($"Can only read from input signal: {signalInstance.Name}", sourceExpr);
                    }
                }
            }

            if (!usagescope.TryGetValue(item, out var d))
            {
                usagescope[item] = direction;
            }
            else if (d != direction)
            {
                usagescope[item] = ItemUsageDirection.Both;
            }
        }