Example #1
0
        private bool AssertDecodeBranchArguments(
            IEnumerable <LNode> nodes,
            Dictionary <Symbol, ValueTag> valueTags,
            out IReadOnlyList <BranchArgument> args)
        {
            var results = new List <BranchArgument>();

            foreach (var argNode in nodes)
            {
                if (!FeedbackHelpers.AssertIsId(argNode, Log))
                {
                    args = null;
                    return(false);
                }

                var name = argNode.Name;
                if (name == CodeSymbols.Result)
                {
                    results.Add(BranchArgument.TryResult);
                }
                else if (name == EncoderState.tryFlowExceptionSymbol)
                {
                    results.Add(BranchArgument.TryException);
                }
                else
                {
                    results.Add(BranchArgument.FromValue(GetValueTag(argNode.Name, valueTags)));
                }
            }
            args = results;
            return(true);
        }
Example #2
0
        private static bool AssertDecodeTypeAndName(
            LNode parentAndName,
            DecoderState state,
            out IType parentType,
            out SimpleName name)
        {
            if (!FeedbackHelpers.AssertArgCount(parentAndName, 2, state.Log))
            {
                parentType = null;
                name       = null;
                return(false);
            }

            parentType = state.DecodeType(parentAndName.Args[0]);

            if (parentType != ErrorType.Instance &&
                state.AssertDecodeSimpleName(parentAndName.Args[1], out name))
            {
                return(true);
            }
            else
            {
                parentType = null;
                name       = null;
                return(false);
            }
        }
Example #3
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);
            }
        }
Example #4
0
        private static bool AssertSingleGlobalType(
            IReadOnlyList <IType> types,
            LNode nameNode,
            DecoderState state)
        {
            if (types.Count == 1)
            {
                return(true);
            }

            if (types.Count == 0)
            {
                FeedbackHelpers.LogSyntaxError(
                    state.Log,
                    nameNode,
                    FeedbackHelpers.QuoteEven(
                        "there is no type named ",
                        FeedbackHelpers.Print(nameNode),
                        "."));
            }
            else
            {
                FeedbackHelpers.LogSyntaxError(
                    state.Log,
                    nameNode,
                    FeedbackHelpers.QuoteEven(
                        "there is more than one type named ",
                        FeedbackHelpers.Print(nameNode),
                        "."));
            }
            return(false);
        }
Example #5
0
        /// <summary>
        /// Decodes an LNode as a type definition.
        /// </summary>
        /// <param name="node">The node to decode.</param>
        /// <param name="state">The decoder's state.</param>
        /// <returns>A decoded type.</returns>
        public static IrType Decode(LNode node, DecoderState state)
        {
            QualifiedName name;

            if (!FeedbackHelpers.AssertArgCount(node, 4, state.Log) ||
                !state.AssertDecodeQualifiedName(node.Args[0], out name))
            {
                return(null);
            }
            else if (node.Calls(TypeParameterDefinitionSymbol))
            {
                return(new IrGenericParameter(node, state));
            }
            else if (node.Calls(TypeDefinitionSymbol))
            {
                return(new IrType(node, state));
            }
            else
            {
                state.Log.LogSyntaxError(
                    node,
                    FeedbackHelpers.QuoteEven(
                        "expected ",
                        TypeDefinitionSymbol.Name,
                        " or ",
                        TypeParameterDefinitionSymbol.Name,
                        "."));
                return(null);
            }
        }
Example #6
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);
        }
 private static IntrinsicPrototype DecodeIntrinsic(IReadOnlyList <LNode> data, DecoderState state)
 {
     // TODO: decode exception specifications.
     return(IntrinsicPrototype.Create(
                FeedbackHelpers.AssertIsId(data[0], state.Log)
             ? data[0].Name.Name
             : "error",
                state.DecodeType(data[1]),
                data[2].Args.EagerSelect <LNode, IType>(state.DecodeType)));
 }
Example #8
0
        /// <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));
        }
Example #9
0
        /// <summary>
        /// Decodes an assembly from an LNode.
        /// </summary>
        /// <param name="data">The LNode to decode.</param>
        /// <param name="state">The decoder to use.</param>
        /// <returns>
        /// A decoded assembly if the node can be decoded;
        /// otherwise, <c>null</c>.
        /// </returns>
        public static IrAssembly Decode(LNode data, DecoderState state)
        {
            QualifiedName name;

            if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log) ||
                !state.AssertDecodeQualifiedName(data.Args[0], out name))
            {
                return(null);
            }
            else
            {
                return(new IrAssembly(data, state));
            }
        }
Example #10
0
        /// <summary>
        /// Decodes a method from an LNode.
        /// </summary>
        /// <param name="data">The LNode to decode.</param>
        /// <param name="state">The decoder to use.</param>
        /// <returns>
        /// A decoded method if the node can be decoded;
        /// otherwise, <c>null</c>.
        /// </returns>
        public static IMethod Decode(LNode data, DecoderState state)
        {
            SimpleName name;

            if (!FeedbackHelpers.AssertMinArgCount(data, 6, state.Log) ||
                !state.AssertDecodeSimpleName(data.Args[0], out name))
            {
                return(null);
            }
            else
            {
                return(new IrMethod(data, state));
            }
        }
Example #11
0
 /// <summary>
 /// Decodes an LNode as a reference to a generic member.
 /// Logs an error if the decoding process fails.
 /// </summary>
 /// <param name="node">A node to decode as a generic member.</param>
 /// <param name="genericMember">The generic member described by <paramref name="node"/>.</param>
 /// <returns>
 /// <c>true</c> if <paramref name="node"/> can be decoded as a
 /// generic member; otherwise, <c>false</c>.
 /// </returns>
 public bool AssertDecodeGenericMember(
     LNode node,
     out IGenericMember genericMember)
 {
     if (node.Calls(EncoderState.typeHintSymbol))
     {
         if (!FeedbackHelpers.AssertArgCount(node, 1, Log))
         {
             genericMember = null;
             return(false);
         }
         else
         {
             var type = DecodeType(node.Args[0]);
             genericMember = type;
             return(!(type == null || type is ErrorType));
         }
     }
     else if (node.Calls(EncoderState.methodHintSymbol))
     {
         if (!FeedbackHelpers.AssertArgCount(node, 1, Log))
         {
             genericMember = null;
             return(false);
         }
         else
         {
             var method = DecodeMethod(node.Args[0]);
             genericMember = method;
             return(method != null);
         }
     }
     else
     {
         FeedbackHelpers.LogSyntaxError(
             Log,
             node,
             FeedbackHelpers.QuoteEven(
                 "unknown kind of generic member; " +
                 "generic member kinds must be hinted using either ",
                 EncoderState.methodHintSymbol.ToString(),
                 " or ",
                 EncoderState.typeHintSymbol.ToString(),
                 " nodes."));
         genericMember = null;
         return(false);
     }
 }
Example #12
0
        private bool AssertDecodeValueTags(
            IEnumerable <LNode> nodes,
            Dictionary <Symbol, ValueTag> valueTags,
            out IReadOnlyList <ValueTag> tags)
        {
            var results = new List <ValueTag>();

            foreach (var argNode in nodes)
            {
                if (!FeedbackHelpers.AssertIsId(argNode, Log))
                {
                    tags = null;
                    return(false);
                }

                results.Add(GetValueTag(argNode.Name, valueTags));
            }
            tags = results;
            return(true);
        }
Example #13
0
        private static bool AssertSingleChildType(
            IReadOnlyList <IType> types,
            LNode parentAndNameNode,
            DecoderState state,
            string parentKindDescription)
        {
            if (types.Count == 1)
            {
                return(true);
            }

            var parentNode = parentAndNameNode.Args[0];
            var nameNode   = parentAndNameNode.Args[1];

            if (types.Count == 0)
            {
                FeedbackHelpers.LogSyntaxError(
                    state.Log,
                    nameNode,
                    FeedbackHelpers.QuoteEven(
                        parentKindDescription + " ",
                        FeedbackHelpers.Print(parentNode),
                        " does not define a type named ",
                        FeedbackHelpers.Print(nameNode),
                        "."));
            }
            else
            {
                FeedbackHelpers.LogSyntaxError(
                    state.Log,
                    nameNode,
                    FeedbackHelpers.QuoteEven(
                        parentKindDescription + " ",
                        FeedbackHelpers.Print(parentNode),
                        " defines more than one type named ",
                        FeedbackHelpers.Print(nameNode),
                        "."));
            }
            return(false);
        }
Example #14
0
        /// <summary>
        /// Decodes a parameter node.
        /// </summary>
        /// <param name="node">A parameter node to decode.</param>
        /// <returns>A decoded parameter.</returns>
        public Parameter DecodeParameter(LNode node)
        {
            var attrs = DecodeAttributeMap(node.Attrs);

            if (node.Calls(EncoderState.parameterSymbol))
            {
                if (FeedbackHelpers.AssertArgCount(node, 2, Log))
                {
                    return(new Parameter(
                               DecodeType(node.Args[0]),
                               DecodeSimpleName(node.Args[1]),
                               attrs));
                }
                else
                {
                    return(new Parameter(ErrorType.Instance).WithAttributes(attrs));
                }
            }
            else
            {
                return(new Parameter(DecodeType(node)).WithAttributes(attrs));
            }
        }
Example #15
0
 private static T CheckSingleCandidate <T>(
     T[] candidates,
     LNode parentType,
     LNode signature,
     string memberKind,
     DecoderState state)
     where T : class
 {
     if (candidates.Length == 0)
     {
         state.Log.LogSyntaxError(
             signature,
             Quotation.QuoteEvenInBold(
                 "type ",
                 FeedbackHelpers.Print(parentType),
                 " does not define a " + memberKind + " ",
                 FeedbackHelpers.Print(signature),
                 "."));
         return(null);
     }
     else if (candidates.Length > 1)
     {
         state.Log.LogSyntaxError(
             signature,
             Quotation.QuoteEvenInBold(
                 "type ",
                 FeedbackHelpers.Print(parentType),
                 " defines more than one " + memberKind + " ",
                 FeedbackHelpers.Print(signature),
                 "."));
         return(null);
     }
     else
     {
         return(candidates[0]);
     }
 }
Example #16
0
        /// <summary>
        /// Decodes an LNode as a simple name. Logs an error if the decoding
        /// process fails.
        /// </summary>
        /// <param name="node">A node to decode as a simple name.</param>
        /// <param name="name">The name described by <paramref name="node"/>.</param>
        /// <returns>
        /// <c>true</c> if <paramref name="node"/> can be decoded as a simple
        /// name; otherwise, <c>false</c>.
        /// </returns>
        public bool AssertDecodeSimpleName(LNode node, out SimpleName name)
        {
            if (node.IsId)
            {
                name = new SimpleName(node.Name.Name);
                return(true);
            }
            else if (node.IsCall)
            {
                var nameNode = node.Target;
                int arity;
                if (!FeedbackHelpers.AssertIsId(nameNode, Log) ||
                    !FeedbackHelpers.AssertArgCount(node, 1, Log) ||
                    !AssertDecodeInt32(node.Args[0], out arity))
                {
                    name = null;
                    return(false);
                }

                name = new SimpleName(nameNode.Name.Name, arity);
                return(true);
            }
            else
            {
                FeedbackHelpers.LogSyntaxError(
                    Log,
                    node,
                    FeedbackHelpers.QuoteEven(
                        "expected a simple name, which can either be a simple id (e.g., ",
                        "Name",
                        ") or a call to an id that specifies the number of generic parameters (e.g., ",
                        "Name(2)",
                        ")."));
                name = null;
                return(false);
            }
        }
Example #17
0
 /// <summary>
 /// Decodes an LNode as a qualified name. Logs an error if the decoding
 /// process fails.
 /// </summary>
 /// <param name="node">A node to decode as a qualified name.</param>
 /// <param name="name">The name described by <paramref name="node"/>.</param>
 /// <returns>
 /// <c>true</c> if <paramref name="node"/> can be decoded as a
 /// qualified name; otherwise, <c>false</c>.
 /// </returns>
 public bool AssertDecodeQualifiedName(
     LNode node,
     out QualifiedName name)
 {
     if (node.Calls(CodeSymbols.ColonColon))
     {
         QualifiedName prefix;
         SimpleName    suffix;
         if (FeedbackHelpers.AssertArgCount(node, 2, Log) &&
             AssertDecodeQualifiedName(node.Args[0], out prefix) &&
             AssertDecodeSimpleName(node.Args[1], out suffix))
         {
             name = suffix.Qualify(prefix);
             return(true);
         }
         else
         {
             name = default(QualifiedName);
             return(false);
         }
     }
     else
     {
         SimpleName simple;
         if (AssertDecodeSimpleName(node, out simple))
         {
             name = simple.Qualify();
             return(true);
         }
         else
         {
             name = default(QualifiedName);
             return(false);
         }
     }
 }
Example #18
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);
            }
        }
Example #19
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);
            }
        }
Example #20
0
        /// <summary>
        /// Decodes a control-flow graph as a method body.
        /// </summary>
        /// <param name="node">An encoded control-flow graph.</param>
        /// <returns>
        /// A new method body that includes the decoded control-flow graph.
        /// </returns>
        public FlowGraph DecodeFlowGraph(LNode node)
        {
            // A CFG consists of a list of basic blocks and a specially
            // marked entry point block.

            var graph = new FlowGraphBuilder();

            var blocks           = new Dictionary <Symbol, BasicBlockBuilder>();
            var valueTags        = new Dictionary <Symbol, ValueTag>();
            var parsedEntryPoint = false;

            // Do a quick pass through all blocks for determinism: we want
            // to define the blocks in the same order as the original IR.
            foreach (var blockNode in node.Args)
            {
                if (!FeedbackHelpers.AssertArgCount(blockNode, 4, Log))
                {
                    // Log the error and return an empty flow graph.
                    return(new FlowGraph());
                }

                var name = FeedbackHelpers.AssertIsId(blockNode.Args[0], Log)
                    ? blockNode.Args[0].Name
                    : GSymbol.Empty;

                // Define the basic block for determinism.
                GetBasicBlock(name, graph, blocks);
            }

            foreach (var blockNode in node.Args)
            {
                // Parse the basic block.
                var blockBuilder = DecodeBasicBlock(blockNode, graph, blocks, valueTags);

                // Entry points get special treatment.
                if (blockNode.Calls(EncoderState.entryPointBlockSymbol))
                {
                    if (parsedEntryPoint)
                    {
                        Log.LogSyntaxError(
                            blockNode,
                            "there can be only one entry point block in a control-flow graph.");
                    }

                    parsedEntryPoint = true;

                    // Update the graph's entry point.
                    var oldEntryPointTag = graph.EntryPointTag;
                    graph.EntryPointTag = blockBuilder.Tag;
                    graph.RemoveBasicBlock(oldEntryPointTag);
                }
            }

            if (!parsedEntryPoint)
            {
                Log.LogSyntaxError(
                    node,
                    "all control-flow graphs must define exactly one " +
                    "entry point, but this one doesn't.");
            }

            return(graph.ToImmutable());
        }
Example #21
0
        /// <summary>
        /// Decodes an id node using a symbol-to-value mapping.
        /// An error is reported if the node cannot be decoded.
        /// </summary>
        /// <param name="node">A node to decode.</param>
        /// <param name="decodeMap">
        /// A mapping of symbols to values that is used for
        /// decoding the node.
        /// </param>
        /// <param name="enumDescription">
        /// A short description of the type of value that is being
        /// decoded, e.g., "method lookup strategy".
        /// </param>
        /// <param name="result">
        /// The decoded value, if any.
        /// </param>
        /// <returns>
        /// <c>true</c> if the node could be decoded; otherwise, <c>false</c>.
        /// </returns>
        public bool AssertDecodeEnum <T>(
            LNode node,
            IReadOnlyDictionary <Symbol, T> decodeMap,
            string enumDescription,
            out T result)
        {
            if (!node.IsId)
            {
                Log.LogSyntaxError(
                    node,
                    FeedbackHelpers.QuoteEven(
                        "expected " + enumDescription + " (",
                        FeedbackHelpers.SpellNodeKind(LNodeKind.Id),
                        " node) but got ",
                        FeedbackHelpers.SpellNodeKind(node),
                        " node."));
                result = default(T);
                return(false);
            }

            if (decodeMap.TryGetValue(node.Name, out result))
            {
                return(true);
            }
            else
            {
                // Create a sorted list of all admissible values.
                var sortedKeys = new List <string>();
                foreach (var item in decodeMap.Keys)
                {
                    sortedKeys.Add(item.Name);
                }
                sortedKeys.Sort();

                // Generate a lengthy message that details exactly what
                // is admissible.
                var message = new List <MarkupNode>();
                message.Add("unknown " + enumDescription + " ");
                message.Add(node.Name.Name);
                message.Add("; expected ");
                for (int i = 0; i < sortedKeys.Count - 1; i++)
                {
                    message.Add(sortedKeys[i]);
                    if (i < sortedKeys.Count - 2)
                    {
                        message.Add(", ");
                    }
                    else
                    {
                        message.Add(" or ");
                    }
                }
                message.Add(sortedKeys[sortedKeys.Count - 1]);
                message.Add(".");

                Log.LogSyntaxError(
                    node,
                    FeedbackHelpers.QuoteEven(message.ToArray()));

                return(false);
            }
        }
Example #22
0
        /// <inheritdoc/>
        public override IType Decode(LNode data, DecoderState state)
        {
            if (data.Calls(pointerSymbol))
            {
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log))
                {
                    return(ErrorType.Instance);
                }

                var         elemType = state.DecodeType(data.Args[0]);
                PointerKind kind;
                if (AssertDecodePointerKind(data.Args[1], state, out kind))
                {
                    return(elemType.MakePointerType(kind));
                }
                else
                {
                    return(ErrorType.Instance);
                }
            }
            else if (data.Calls(genericParameterSymbol))
            {
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log))
                {
                    return(ErrorType.Instance);
                }

                IGenericMember parent;
                SimpleName     name;

                if (state.AssertDecodeGenericMember(data.Args[0], out parent) &&
                    state.AssertDecodeSimpleName(data.Args[1], out name))
                {
                    var types = state.TypeResolver.ResolveGenericParameters(parent, name);
                    if (AssertSingleChildType(types, data, state, "generic declaration"))
                    {
                        return(types[0]);
                    }
                }
                return(ErrorType.Instance);
            }
            else if (data.Calls(CodeSymbols.Of))
            {
                if (!FeedbackHelpers.AssertMinArgCount(data, 2, state.Log))
                {
                    return(ErrorType.Instance);
                }

                var genericDecl = state.DecodeType(data.Args[0]);
                var genericArgs = data.Args.Slice(1).EagerSelect <LNode, IType>(state.DecodeType);

                int count = genericDecl.GenericParameters.Count;
                if (count != genericArgs.Count)
                {
                    FeedbackHelpers.LogSyntaxError(
                        state.Log,
                        data,
                        FeedbackHelpers.QuoteEven(
                            "type ",
                            FeedbackHelpers.Print(data.Args[0]),
                            " is instantiated with ",
                            genericArgs.Count.ToString(),
                            " arguments but has only ",
                            count.ToString(),
                            " parameters."));
                    return(ErrorType.Instance);
                }

                return(genericDecl.MakeGenericType(genericArgs));
            }
            else if (data.Calls(CodeSymbols.Dot))
            {
                if (!FeedbackHelpers.AssertArgCount(data, 2, state.Log))
                {
                    return(ErrorType.Instance);
                }

                SimpleName childName;
                if (!state.AssertDecodeSimpleName(data.Args[1], out childName))
                {
                    return(ErrorType.Instance);
                }

                var parentType = state.DecodeType(data.Args[0]);
                if (parentType == ErrorType.Instance)
                {
                    // Make sure that we don't log an additional error
                    // just because the parent type was wrong.
                    return(ErrorType.Instance);
                }

                var childTypes = state.TypeResolver.ResolveNestedTypes(parentType, childName);
                if (AssertSingleChildType(childTypes, data, state, "type"))
                {
                    return(childTypes[0]);
                }
                else
                {
                    return(ErrorType.Instance);
                }
            }
            else
            {
                QualifiedName fullName;
                if (state.AssertDecodeQualifiedName(data, out fullName))
                {
                    var types = state.TypeResolver.ResolveTypes(fullName);
                    if (AssertSingleGlobalType(types, data, state))
                    {
                        return(types[0]);
                    }
                    else
                    {
                        return(ErrorType.Instance);
                    }
                }
                else
                {
                    return(ErrorType.Instance);
                }
            }
        }
Example #23
0
        /// <summary>
        /// Decodes an LNode as a constant value.
        /// </summary>
        /// <param name="node">The node to decode.</param>
        /// <param name="state">The decoder state to use.</param>
        /// <returns>A decoded constant.</returns>
        public override Constant Decode(LNode node, DecoderState state)
        {
            // Default-value constants.
            if (node.IsIdNamed(CodeSymbols.Default))
            {
                return(DefaultConstant.Instance);
            }

            // Type/field/method token constants.
            if (node.Calls(CodeSymbols.Typeof, 1))
            {
                return(new TypeTokenConstant(state.DecodeType(node.Args[0])));
            }
            else if (node.Calls(fieldofSymbol, 1))
            {
                return(new FieldTokenConstant(state.DecodeField(node.Args[0])));
            }
            else if (node.Calls(methodofSymbol, 1))
            {
                return(new MethodTokenConstant(state.DecodeMethod(node.Args[0])));
            }

            if (!FeedbackHelpers.AssertIsLiteral(node, state.Log))
            {
                return(null);
            }

            object value;
            Symbol typeMarker;

            // Custom literals.
            if (TryDecomposeCustomLiteral(node, out value, out typeMarker))
            {
                // Arbitrary-width integer literals.
                IntegerSpec spec;
                if (IntegerSpec.TryParse(typeMarker.Name, out spec))
                {
                    BigInteger integerVal;
                    if (BigInteger.TryParse(value.ToString(), out integerVal))
                    {
                        return(new IntegerConstant(integerVal, spec));
                    }
                    else
                    {
                        FeedbackHelpers.LogSyntaxError(
                            state.Log,
                            node,
                            FeedbackHelpers.QuoteEven(
                                "cannot parse ",
                                value.ToString(),
                                " as an integer."));
                        return(null);
                    }
                }
                else
                {
                    FeedbackHelpers.LogSyntaxError(
                        state.Log,
                        node,
                        FeedbackHelpers.QuoteEven(
                            "unknown custom literal type ",
                            typeMarker.Name,
                            "."));
                    return(null);
                }
            }

            value = node.Value;

            // Miscellaneous constants: null, strings, Booleans.
            if (value == null)
            {
                return(NullConstant.Instance);
            }
            else if (value is string)
            {
                return(new StringConstant((string)value));
            }
            else if (value is bool)
            {
                return(BooleanConstant.Create((bool)value));
            }
            // Floating-point numbers.
            else if (value is float)
            {
                return(new Float32Constant((float)value));
            }
            else if (value is double)
            {
                return(new Float64Constant((double)value));
            }
            // Fixed-width integer constants and characters.
            else if (value is char)
            {
                return(new IntegerConstant((char)value));
            }
            else if (value is sbyte)
            {
                return(new IntegerConstant((sbyte)value));
            }
            else if (value is short)
            {
                return(new IntegerConstant((short)value));
            }
            else if (value is int)
            {
                return(new IntegerConstant((int)value));
            }
            else if (value is long)
            {
                return(new IntegerConstant((long)value));
            }
            else if (value is byte)
            {
                return(new IntegerConstant((byte)value));
            }
            else if (value is ushort)
            {
                return(new IntegerConstant((ushort)value));
            }
            else if (value is uint)
            {
                return(new IntegerConstant((uint)value));
            }
            else if (value is ulong)
            {
                return(new IntegerConstant((ulong)value));
            }

            FeedbackHelpers.LogSyntaxError(
                state.Log,
                node,
                new Text("unknown literal type."));
            return(null);
        }
Example #24
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);
            }
        }