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