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); } }
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)); }
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); } }
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); } }
/// <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); } }