private static ResolvableType CreateUnapplyReturnType(IEnumerable<string> typeNames) { IEnumerable<string> names = typeNames as IList<string> ?? typeNames.ToList(); if (!names.Any()) { return ResolvableType.BooleanTy; } if (names.Count() == 1) { RTypeName optionType = new RTypeName("Option"); optionType.AddGenericArgument(new RTypeName(names.First())); return new ResolvableType(optionType); } else { RTypeName optionType = new RTypeName("Option"); RTypeName tuppleType = CreateTupleType(names); optionType.AddGenericArgument(tuppleType); return new ResolvableType(optionType); } }
// Consume follow is needed to handle pattern matching case: // case x: Foo => x.length // without consumeFollow false it will parse and closure type (Foo => x) which is incorrect public bool ParseType(out RTypeName type, bool consumeFollow = true) { if (Require(RppLexer.Id)) { IToken typeNameToken = _lastToken; if (Require(RppLexer.OP_LBracket)) { RTypeName genericType = new RTypeName(typeNameToken); type = genericType; RTypeName subType; if (!ParseType(out subType)) { RaiseSyntaxError("Type is expected"); } genericType.AddGenericArgument(subType); while (true) { if (Require(RppLexer.OP_RBracket)) { break; } if (Require(RppLexer.OP_Comma)) { if (!ParseType(out subType)) { RaiseSyntaxError("Type is expected"); } genericType.AddGenericArgument(subType); } else { RaiseSyntaxError("Expected comma"); } } return true; } // A => B if (consumeFollow && Require(RppLexer.OP_Follow)) { RTypeName returnType; if (!ParseType(out returnType)) { RaiseSyntaxError("Type is expected"); } type = CreateClosureTypeName(new List<RTypeName> {new RTypeName(typeNameToken)}, returnType); return true; } type = new RTypeName(typeNameToken); return true; } // (A, B) => C // (A => B) if (Require(RppLexer.OP_LParen)) { bool closingParenRequired = true; RTypeName returnType; IList<RTypeName> paramTypes = new List<RTypeName>(); while (true) { if (Require(RppLexer.OP_RParen)) { closingParenRequired = false; break; } if (Peek(RppLexer.OP_Follow)) { break; } if (paramTypes.Count > 0) { Expect(RppLexer.OP_Comma); } RTypeName paramType; if (ParseType(out paramType)) { paramTypes.Add(paramType); } else { RaiseSyntaxError("Type is expected"); } } if (!Require(RppLexer.OP_Follow)) { // (A => A) if (paramTypes.Count == 1) { type = paramTypes[0]; return true; } // (A, B, C) type = CreateTupleTypeName(paramTypes); return true; } if (!ParseType(out returnType)) { RaiseSyntaxError("Type is expected"); } if (closingParenRequired) { Expect(RppLexer.OP_RParen); } type = CreateClosureTypeName(paramTypes, returnType); return true; } type = null; return false; }
/// <summary> /// Creates Function[paramCount] type name if return type is not Unit. /// If it's Unit then it creates Action[paramCount]. /// </summary> private static RTypeName CreateClosureTypeName(ICollection<RTypeName> paramTypes, RTypeName returnType) { bool isAction = IsAction(returnType); string baseTypeName = isAction ? "Action" : "Function"; RTypeName closureType = new RTypeName(baseTypeName + paramTypes.Count); paramTypes.ForEach(closureType.AddGenericArgument); if (!isAction) { closureType.AddGenericArgument(returnType); } return closureType; }
private static RTypeName Reconstruct(RType type) { RTypeName typeName = new RTypeName(type.Name); type.GenericArguments.ForEach(ga => typeName.AddGenericArgument(Reconstruct(ga))); return typeName; }