Exemple #1
0
        private bool AssertDecodeInstruction(
            LNode insnNode,
            Dictionary <Symbol, ValueTag> valueTags,
            out Instruction result)
        {
            if (!FeedbackHelpers.AssertIsCall(insnNode, Log))
            {
                result = default(Instruction);
                return(false);
            }

            // Decode the prototype.
            var prototype = DecodeInstructionProtoype(insnNode.Target);

            // Decode the instruction arguments.
            IReadOnlyList <ValueTag> args;

            if (AssertDecodeValueTags(insnNode.Args, valueTags, out args))
            {
                result = prototype.Instantiate(args);
                return(true);
            }
            else
            {
                result = default(Instruction);
                return(false);
            }
        }
Exemple #2
0
        private BasicBlockBuilder DecodeBasicBlock(
            LNode node,
            FlowGraphBuilder graph,
            Dictionary <Symbol, BasicBlockBuilder> blocks,
            Dictionary <Symbol, ValueTag> valueTags)
        {
            // Each basic block is essentially a
            // (name, parameters, instructions, flow) tuple.
            // We just parse all four elements and call it a day.

            // Parse the block's name and create the block.
            var name = FeedbackHelpers.AssertIsId(node.Args[0], Log)
                ? node.Args[0].Name
                : GSymbol.Empty;

            var blockBuilder = GetBasicBlock(name, graph, blocks);

            // Parse the block's parameter list.
            foreach (var paramNode in node.Args[1].Args)
            {
                if (FeedbackHelpers.AssertArgCount(paramNode, 2, Log))
                {
                    blockBuilder.AppendParameter(
                        new BlockParameter(
                            DecodeType(paramNode.Args[0]),
                            FeedbackHelpers.AssertIsId(paramNode.Args[1], Log)
                                ? GetValueTag(paramNode.Args[1].Name, valueTags)
                                : new ValueTag()));
                }
                else
                {
                    blockBuilder.AppendParameter(new BlockParameter(ErrorType.Instance));
                }
            }

            // Parse the block's instructions.
            foreach (var valueNode in node.Args[2].Args)
            {
                // Decode the instruction.
                Instruction insn;
                if (!FeedbackHelpers.AssertIsCall(valueNode, Log) ||
                    !FeedbackHelpers.AssertArgCount(valueNode, 2, Log) ||
                    !FeedbackHelpers.AssertIsId(valueNode.Args[0], Log) ||
                    !AssertDecodeInstruction(valueNode.Args[1], valueTags, out insn))
                {
                    continue;
                }

                // Append the instruction to the basic block.
                blockBuilder.AppendInstruction(
                    insn,
                    GetValueTag(valueNode.Args[0].Name, valueTags));
            }

            // Parse the block's flow.
            blockBuilder.Flow = DecodeBlockFlow(node.Args[3], graph, blocks, valueTags);

            return(blockBuilder);
        }
        /// <summary>
        /// Decodes a particular piece of data.
        /// </summary>
        /// <param name="data">
        /// Encoded data to decode.
        /// </param>
        /// <param name="state">
        /// The decoder's state.
        /// </param>
        /// <returns>
        /// A decoded object.
        /// </returns>
        public override TObj Decode(LNode data, DecoderState state)
        {
            if (!FeedbackHelpers.AssertIsCall(data, state.Log) &&
                !FeedbackHelpers.AssertIsId(data.Target, state.Log))
            {
                return(default(TObj));
            }

            var identifier = data.Name;
            var args       = data.Args;

            return(Decode(identifier, data, state));
        }
Exemple #4
0
        private bool AssertDecodeBranch(
            LNode node,
            FlowGraphBuilder graph,
            Dictionary <Symbol, BasicBlockBuilder> blocks,
            Dictionary <Symbol, ValueTag> valueTags,
            out Branch result)
        {
            IReadOnlyList <BranchArgument> args;

            if (FeedbackHelpers.AssertIsCall(node, Log) &&
                FeedbackHelpers.AssertIsId(node.Target, Log) &&
                AssertDecodeBranchArguments(node.Args, valueTags, out args))
            {
                result = new Branch(
                    GetBasicBlock(node.Target.Name, graph, blocks).Tag,
                    args);
                return(true);
            }
            else
            {
                result = default(Branch);
                return(false);
            }
        }
Exemple #5
0
        private BlockFlow DecodeBlockFlow(
            LNode node,
            FlowGraphBuilder graph,
            Dictionary <Symbol, BasicBlockBuilder> blocks,
            Dictionary <Symbol, ValueTag> valueTags)
        {
            if (node.Calls(CodeSymbols.Goto))
            {
                Branch target;
                if (FeedbackHelpers.AssertArgCount(node, 1, Log) &&
                    AssertDecodeBranch(node.Args[0], graph, blocks, valueTags, out target))
                {
                    return(new JumpFlow(target));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.Calls(CodeSymbols.Switch))
            {
                // Decode the value being switched on as well as the default branch.
                Instruction switchVal;
                Branch      defaultTarget;
                if (FeedbackHelpers.AssertArgCount(node, 3, Log) &&
                    AssertDecodeInstruction(node.Args[0], valueTags, out switchVal) &&
                    AssertDecodeBranch(node.Args[1], graph, blocks, valueTags, out defaultTarget))
                {
                    // Decode the switch cases.
                    var switchCases = ImmutableList.CreateBuilder <SwitchCase>();
                    foreach (var caseNode in node.Args[2].Args)
                    {
                        if (!FeedbackHelpers.AssertArgCount(caseNode, 2, Log) ||
                            !FeedbackHelpers.AssertIsCall(caseNode.Args[0], Log))
                        {
                            continue;
                        }

                        var constants = ImmutableHashSet.CreateRange <Constant>(
                            caseNode.Args[0].Args
                            .Select(DecodeConstant)
                            .Where(x => x != null));

                        Branch caseTarget;
                        if (AssertDecodeBranch(caseNode.Args[1], graph, blocks, valueTags, out caseTarget))
                        {
                            switchCases.Add(new SwitchCase(constants, caseTarget));
                        }
                    }
                    return(new SwitchFlow(switchVal, switchCases.ToImmutable(), defaultTarget));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.Calls(CodeSymbols.Return))
            {
                Instruction retValue;
                if (FeedbackHelpers.AssertArgCount(node, 1, Log) &&
                    AssertDecodeInstruction(node.Args[0], valueTags, out retValue))
                {
                    return(new ReturnFlow(retValue));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.Calls(CodeSymbols.Try))
            {
                Instruction tryValue;
                Branch      successBranch;
                Branch      exceptionBranch;
                if (FeedbackHelpers.AssertArgCount(node, 3, Log) &&
                    AssertDecodeInstruction(node.Args[0], valueTags, out tryValue) &&
                    AssertDecodeBranch(node.Args[1], graph, blocks, valueTags, out successBranch) &&
                    AssertDecodeBranch(node.Args[2], graph, blocks, valueTags, out exceptionBranch))
                {
                    return(new TryFlow(tryValue, successBranch, exceptionBranch));
                }
                else
                {
                    return(UnreachableFlow.Instance);
                }
            }
            else if (node.IsIdNamed(EncoderState.unreachableFlowSymbol))
            {
                return(UnreachableFlow.Instance);
            }
            else
            {
                FeedbackHelpers.LogSyntaxError(
                    Log,
                    node,
                    Quotation.QuoteEvenInBold(
                        "unknown type of flow; expected one of ",
                        CodeSymbols.Goto.Name, ", ",
                        CodeSymbols.Switch.Name, ", ",
                        CodeSymbols.Try.Name, ", ",
                        CodeSymbols.Return.Name, " or ",
                        EncoderState.unreachableFlowSymbol.Name, "."));
                return(UnreachableFlow.Instance);
            }
        }
Exemple #6
0
        /// <inheritdoc/>
        public override ITypeMember Decode(LNode data, DecoderState state)
        {
            if (data.Calls(accessorSymbol))
            {
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log) ||
                    !FeedbackHelpers.AssertIsId(data.Args[1], state.Log))
                {
                    return(null);
                }

                var property = state.DecodeProperty(data.Args[0]);
                if (property == null)
                {
                    return(null);
                }
                else
                {
                    var kindName = data.Args[1].Name.Name;
                    var accessor = property.Accessors.FirstOrDefault(
                        acc => accessorKindEncodings[acc.Kind] == kindName);

                    if (accessor == null)
                    {
                        FeedbackHelpers.LogSyntaxError(
                            state.Log,
                            data.Args[1],
                            Quotation.QuoteEvenInBold(
                                "property ",
                                FeedbackHelpers.Print(data.Args[0]),
                                " does not define a ",
                                kindName,
                                " accessor."));
                    }
                    return(accessor);
                }
            }
            else if (data.Calls(CodeSymbols.Dot))
            {
                // Simple dot indicates a field.
                IType      parentType;
                SimpleName name;
                if (!AssertDecodeTypeAndName(data, state, out parentType, out name))
                {
                    return(null);
                }

                var candidates = state.TypeMemberIndex
                                 .GetAll(parentType, name)
                                 .OfType <IField>()
                                 .ToArray();

                return(CheckSingleCandidate(
                           candidates,
                           data.Args[0],
                           data.Args[1],
                           "field",
                           state));
            }
            else if (data.CallsMin(CodeSymbols.IndexBracks, 1))
            {
                IType      parentType;
                SimpleName name;
                if (!AssertDecodeTypeAndName(data.Args[0], state, out parentType, out name))
                {
                    return(null);
                }

                var indexTypes = data.Args
                                 .Slice(1)
                                 .EagerSelect(state.DecodeType);

                var candidates = state.TypeMemberIndex
                                 .GetAll(parentType, name)
                                 .OfType <IProperty>()
                                 .Where(prop =>
                                        prop.IndexerParameters
                                        .Select(p => p.Type)
                                        .SequenceEqual(indexTypes))
                                 .ToArray();

                return(CheckSingleCandidate(
                           candidates,
                           data.Args[0].Args[0],
                           data,
                           "property",
                           state));
            }
            else if (data.Calls(CodeSymbols.Lambda))
            {
                IType      parentType;
                SimpleName name;
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log) ||
                    !FeedbackHelpers.AssertIsCall(data.Args[0], state.Log) ||
                    !AssertDecodeTypeAndName(data.Args[0].Target, state, out parentType, out name))
                {
                    return(null);
                }

                // TODO: implement generic parameter decoding, use generic
                // parameters in resolution process.

                var paramTypes = data.Args[0].Args
                                 .EagerSelect(state.DecodeType);

                var retType = state.DecodeType(data.Args[1]);

                var candidates = state.TypeMemberIndex
                                 .GetAll(parentType, name)
                                 .OfType <IMethod>()
                                 .Where(method =>
                                        method.Parameters
                                        .Select(p => p.Type)
                                        .SequenceEqual(paramTypes) &&
                                        object.Equals(
                                            method.ReturnParameter.Type,
                                            retType))
                                 .ToArray();

                return(CheckSingleCandidate(
                           candidates,
                           data.Args[0].Target.Args[0],
                           data,
                           "method",
                           state));
            }
            else if (data.Calls(CodeSymbols.Of))
            {
                if (!FeedbackHelpers.AssertMinArgCount(data, 1, state.Log))
                {
                    return(null);
                }

                var func = state.DecodeMethod(data.Args[0]);
                var args = data.Args.Slice(1).EagerSelect(state.DecodeType);

                if (func.GenericParameters.Count == args.Count)
                {
                    return(func.MakeGenericMethod(args));
                }
                else
                {
                    state.Log.LogSyntaxError(
                        data,
                        Quotation.QuoteEvenInBold(
                            "generic arity mismatch; expected ",
                            func.GenericParameters.Count.ToString(),
                            " parameters but got ",
                            args.Count.ToString(),
                            "."));
                    return(null);
                }
            }
            else
            {
                state.Log.LogSyntaxError(
                    data,
                    Quotation.QuoteEvenInBold(
                        "cannot interpret ",
                        FeedbackHelpers.Print(data),
                        " as a type member; expected a call to one of ",
                        accessorSymbol.Name, ", ",
                        CodeSymbols.Dot.Name, ", ",
                        CodeSymbols.IndexBracks.Name, ", ",
                        CodeSymbols.Of.Name, " or ",
                        CodeSymbols.Lambda.Name));
                return(null);
            }
        }