static void setBoxing(CompilerContext context, TypeInfo targetType, ExpressionNode expression) { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null || targetType == null) { return; } var type = getType(context, expression); if (type == targetType) { return; } if (isAssignable(context, targetType, expression)) { if (targetType.IsPrimitive) { if (!type.IsPrimitive) { info.BoxingKind = BoxingKind.Unbox; var unboxinMethod = context.TypeSystem.getUnboxingMethod(type); info.BoxingMethod = unboxinMethod; info.OriginalType = info.Type; info.Type = unboxinMethod.ReturnType; } } else if (type.IsPrimitive) { info.BoxingKind = BoxingKind.Box; var boxingMethod = context.TypeSystem.getBoxingMethod((targetType.IsObject) ? type : targetType); info.BoxingMethod = boxingMethod; info.OriginalType = info.Type; info.Type = boxingMethod.ReturnType; } else if (targetType.IsNumeric && type.IsNumeric) { info.BoxingKind = BoxingKind.Unbox; info.BoxingMethod = context.TypeSystem.getUnboxingMethod(type); } } }
static bool isMethod(ExpressionNode argNode) { var info = argNode.getUserData(typeof(ExpressionInfo)); if (info == null || info.Type != null) { return false; } else if (info.IsConstant) { return false; } else if (info.Members != null) { foreach (var member in info.Members) { if (member.MemberKind != MemberKind.Method) { return false; } } } return true; }
private ExpressionNode parseBinaryExpression(int precedence, ExpressionNode leftExpression) { for (;;) { var prec = 0; var doParseType = false; var op = BinaryOperator.Add; var restorePoint = this.createRestorePoint(); switch (lexicalUnit) { case Multiply: prec = 1; op = BinaryOperator.Multiply; break; case Divide: prec = 1; op = BinaryOperator.Divide; break; case Percent: prec = 1; op = BinaryOperator.Modulo; break; case Plus: prec = 2; op = BinaryOperator.Add; break; case Minus: prec = 2; op = BinaryOperator.Subtract; break; case LeftShift: prec = 3; op = BinaryOperator.LeftShift; break; case GreaterThan: switch (scanner.nextLexicalUnit()) { case GreaterThan: restorePoint = createRestorePoint(); switch (scanner.nextLexicalUnit()) { case GreaterThan: prec = 3; op = BinaryOperator.UnsignedRightShift; break; default: this.restore(restorePoint); prec = 3; op = BinaryOperator.RightShift; break; case GreaterThanOrEqual: this.restore(restorePoint); return leftExpression; } break; default: this.restore(restorePoint); prec = 4; op = BinaryOperator.GreaterThan; break; case GreaterThanOrEqual: this.restore(restorePoint); return leftExpression; } break; case LessThan: prec = 4; op = BinaryOperator.LessThan; break; case LessThanOrEqual: prec = 4; op = BinaryOperator.LessThanOrEqual; break; case GreaterThanOrEqual: prec = 4; op = BinaryOperator.GreaterThanOrEqual; break; case Keyword: switch (scanner.Keyword) { case As: prec = 4; doParseType = true; op = BinaryOperator.As; break; case Instanceof: prec = 4; doParseType = true; op = BinaryOperator.Instanceof; break; default: return leftExpression; } break; case Equal: prec = 5; op = BinaryOperator.Equal; break; case NotEqual: prec = 5; op = BinaryOperator.NotEqual; break; case LogicalAnd: prec = 6; op = BinaryOperator.LogicalAnd; break; case Xor: prec = 7; op = BinaryOperator.Xor; break; case LogicalOr: prec = 8; op = BinaryOperator.LogicalOr; break; case And: prec = 9; op = BinaryOperator.And; break; case Or: prec = 10; op = BinaryOperator.Or; break; case NullCoalescing: prec = 11; op = BinaryOperator.NullCoalescing; break; default: return leftExpression; } if (prec > precedence) { if (op == BinaryOperator.RightShift) { this.restore(restorePoint); } return leftExpression; } nextLexicalUnit(true); var binary = new BinaryExpressionNode { Operator = op, LeftOperand = leftExpression }; copyScannerState(leftExpression, binary); if (doParseType) { var type = new TypeExpressionNode { TypeReference = parseType(true) }; copyScannerState(type.TypeReference, type); type.EndPosition = type.TypeReference.EndPosition; binary.RightOperand = type; } else { binary.RightOperand = parseBinaryExpression(prec - 1, parseUnaryExpression()); } binary.EndPosition = binary.RightOperand.EndPosition; leftExpression = binary; } }
static TypeInfo getType(CompilerContext context, ExpressionNode expression) { if (ValidationHelper.isMethod(expression)) { throw context.error(CompileErrorId.UnexpectedMethodReference, expression); } var info = expression.getUserData(typeof(ExpressionInfo)); if (info.Type != null) { return info.Type; } else if (info.IsConstant) { context.ConstantBuilder.buildConstant(expression); return info.Type; } else if (info.Members != null) { foreach (var member in info.Members) { switch (member.MemberKind) { case Field: var field = member.Field; if (field.Value != null) { info.IsConstant = true; info.Value = field.Value; } info.Member = member; info.Type = member.Type; if (!isInDeprecatedContext(context)) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, field)) { context.addWarning(CompileErrorId.DeprecatedField, expression, BytecodeHelper.getDisplayName(field.DeclaringType), field.Name); } } if (context.CodeValidationContext.IsInMethod && context.CodeValidationContext.IsInLambda) { if (!member.IsStatic && expression.ExpressionKind == ExpressionKind.SimpleName) { var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod]; if (typeBuilder.getField("this$0") == null) { typeBuilder.defineField("this$0", context.CurrentType); } } } return member.Type; case Type: info.Member = member; info.Type = member.Type; if (!isInDeprecatedContext(context)) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, info.Type)) { context.addWarning(CompileErrorId.DeprecatedType, expression, BytecodeHelper.getDisplayName(info.Type)); } } return member.Type; case Indexer: case Property: info.Member = member; info.Type = member.Type; if (!isInDeprecatedContext(context)) { if (member.GetAccessor != null) { if (member.SetAccessor == null) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.GetAccessor)) { context.addWarning(CompileErrorId.DeprecatedProperty, expression, BytecodeHelper.getDisplayName(member.DeclaringType), member.Name); } } else { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.GetAccessor) && BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.SetAccessor)) { context.addWarning(CompileErrorId.DeprecatedProperty, expression, BytecodeHelper.getDisplayName(member.DeclaringType), member.Name); } } } else if (member.SetAccessor != null) { if (BytecodeHelper.isDeprecated(context.AnnotatedTypeSystem, member.SetAccessor)) { context.addWarning(CompileErrorId.DeprecatedProperty, expression, BytecodeHelper.getDisplayName(member.DeclaringType), member.Name); } } } if (context.CodeValidationContext.IsInMethod && context.CodeValidationContext.IsInLambda) { if (!member.IsStatic && expression.ExpressionKind == ExpressionKind.SimpleName) { var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod]; if (typeBuilder.getField("this$0") == null) { typeBuilder.defineField("this$0", context.CurrentType); } } } return member.Type; case Local: if (context.CodeValidationContext.IsInMethod) { var currentMethod = context.CodeValidationContext.CurrentMethod; var currentType = (TypeBuilder)currentMethod.DeclaringType; if (currentType.FullName.indexOf('#') == -1 && context.CodeValidationContext.IsInLambda) { if (currentMethod != member.Method) { member.IsUsedFromLambda = true; var typeBuilder = context.LambdaScopes[context.CodeValidationContext.RootMethod]; context.getLocalField(typeBuilder, (LocalMemberInfo)member); } } } info.Member = member; info.Type = member.Type; return member.Type; default: break; } } if (info.ExtensionMethods != null && info.ExtensionMethods.any()) { return info.Type = info.ExtensionMethods.first().Parameters.first().Type; } } throw new Exception("Internal error line " + (expression.getLine() + 1)); }
private String expressionToString(ExpressionNode expression) { var sb = new StringBuilder(); var first = false; switch (expression.ExpressionKind) { case Literal: var literal = (LiteralExpressionNode)expression; sb.append("Literal("); sb.append(literal.LiteralKind); sb.append(", ["); sb.append(new String(text, literal.ValueOffset, literal.ValueLength)); sb.append("])"); break; case MemberAccess: var member = (MemberAccessExpressionNode)expression; sb.append("("); sb.append(expressionToString(member.TargetObject)); sb.append(")."); sb.append(new String(text, member.Member.NameOffset, member.Member.NameLength)); break; case NullSafeMemberAccess: var nsmember = (NullSafeMemberAccessExpressionNode)expression; sb.append("("); sb.append(expressionToString(nsmember.TargetObject)); sb.append(")?."); sb.append(new String(text, nsmember.Member.NameOffset, nsmember.Member.NameLength)); break; case Type: var type = (TypeExpressionNode)expression; sb.append("Type("); sb.append(typeReferenceToString(type.TypeReference)); sb.append(")"); break; case SimpleName: var name = (SimpleNameExpressionNode)expression; sb.append("Name("); sb.append(new String(text, name.NameOffset, name.NameLength)); formatTypeArguments(name.TypeArguments, sb); sb.append(")"); break; case ThisAccess: sb.append("this"); break; case SuperAccess: sb.append("base"); break; case ObjectCreation: var objectCreation = (ObjectCreationExpressionNode)expression; sb.append("new "); sb.append(typeReferenceToString(objectCreation.Type)); if (objectCreation.Arguments.size() > 0 || objectCreation.Initializer == null) { sb.append("("); first = true; foreach (var arg in objectCreation.Arguments) { if (first) { first = false; } else { sb.append(", "); } sb.append(expressionToString(arg)); } sb.append(")"); } if (objectCreation.Initializer != null) { sb.append(expressionToString(objectCreation.Initializer)); } break; case ObjectInitializer: var objectInit = (ObjectInitializerExpressionNode)expression; sb.append("{"); first = true; foreach (var mi in objectInit.MemberInitializers) { if (first) { first = false; } else { sb.append(", "); } sb.append(new String(text, mi.NameOffset, mi.NameLength)); sb.append("="); sb.append(expressionToString(mi.Value)); } sb.append("}"); break; case CollectionInitializer: var collectionInit = (CollectionInitializerExpressionNode)expression; sb.append("{"); first = true; foreach (var v in collectionInit.Values) { if (first) { first = false; } else { sb.append(", "); } sb.append("{"); var f = true; foreach (var exp in v) { if (f) { f = false; } else { sb.append(", "); } sb.append(expressionToString(exp)); } sb.append("}"); } sb.append("}"); break; case AnonymousObjectCreation: var anonymousCreation = (AnonymousObjectCreationExpressionNode)expression; sb.append("new{"); first = true; foreach (var decl in anonymousCreation.MemberDeclarators) { if (first) { first = false; } else { sb.append(", "); } if (decl.NameLength > 0) { sb.append(new String(text, decl.NameOffset, decl.NameLength)); sb.append("="); } sb.append(expressionToString(decl.Value)); } sb.append("}"); break; case ArrayCreation: var arrayCreation = (ArrayCreationExpressionNode)expression; sb.append("new"); if (arrayCreation.Type != null) { sb.append(" "); sb.append(typeReferenceToString(arrayCreation.Type)); } if (arrayCreation.DimensionExpressions.size() > 0) { sb.append("["); first = true; foreach (var exp in arrayCreation.DimensionExpressions) { if (first) { first = false; } else { sb.append(", "); } sb.append(expressionToString(exp)); } sb.append("]"); } if (arrayCreation.Dimensions > 0) { sb.append("["); for (int i = 1; i < arrayCreation.Dimensions; i++) { sb.append(","); } sb.append("]"); } if (arrayCreation.Initializer != null) { sb.append(expressionToString(arrayCreation.Initializer)); } break; case ArrayInitializer: var arrayInit = (ArrayInitializerExpressionNode)expression; sb.append("{"); first = true; foreach (var v in arrayInit.Values) { if (first) { first = false; } else { sb.append(", "); } sb.append(expressionToString(v)); } sb.append("}"); break; case ElementAccess: var elementAccess = (ElementAccessExpressionNode)expression; sb.append("("); sb.append(expressionToString(elementAccess.TargetObject)); sb.append(")["); first = true; foreach (var index in elementAccess.Indexes) { if (first) { first = false; } else { sb.append(", "); } sb.append(expressionToString(index)); } sb.append("]"); break; case Invocation: var invocation = (InvocationExpressionNode)expression; sb.append(expressionToString(invocation.TargetObject)); sb.append("("); first = true; foreach (var arg in invocation.Arguments) { if (first) { first = false; } else { sb.append(", "); } sb.append(expressionToString(arg)); } sb.append(")"); break; case Unary: var unary = (UnaryExpressionNode)expression; sb.append("("); sb.append(unary.Operator.toString()); sb.append(" "); sb.append(expressionToString(unary.Operand)); sb.append(")"); break; case Binary: var binary = (BinaryExpressionNode)expression; sb.append("("); sb.append(expressionToString(binary.LeftOperand)); sb.append(" "); sb.append(binary.Operator.toString()); sb.append(" "); sb.append(expressionToString(binary.RightOperand)); sb.append(")"); break; case Cast: var cast = (CastExpressionNode)expression; sb.append("Cast<"); sb.append(typeReferenceToString(cast.TargetType)); sb.append(">("); sb.append(expressionToString(cast.Expression)); sb.append(")"); break; case Assign: var assign = (AssignExpressionNode)expression; sb.append("Assign("); sb.append(expressionToString(assign.Left)); sb.append(" "); sb.append(assign.Operator.toString()); sb.append(" "); sb.append(expressionToString(assign.Right)); sb.append(")"); break; case Lambda: var lambda = (LambdaExpressionNode)expression; sb.append("Lambda("); first = true; foreach (var par in lambda.Parameters) { if (first) { first = false; } else { sb.append(", "); } if (par.Modifier != ParameterModifier.None) { sb.append(par.Modifier.toString().toLowerCase()); sb.append(" "); } if (par.Type != null) { sb.append(typeReferenceToString(par.Type)); sb.append(" "); } sb.append(new String(text, par.NameOffset, par.NameLength)); } sb.append(" => "); sb.append(statementToString(lambda.Body)); sb.append(")"); break; case Conditional: var conditional = (ConditionalExpressionNode)expression; sb.append(expressionToString(conditional.Condition)); sb.append("?"); sb.append(expressionToString(conditional.IfTrue)); sb.append(":"); sb.append(expressionToString(conditional.IfFalse)); break; case Typeof: var tpof = (TypeofExpressionNode)expression; sb.append("typeof("); sb.append(typeReferenceToString(tpof.Type)); sb.append(")"); break; case Query: var query = (QueryExpressionNode)expression; sb.append("from "); if (query.From.Type != null) { sb.append(typeReferenceToString(query.From.Type)); sb.append(" "); } sb.append(new String(text, query.From.NameOffset, query.From.NameLength)); sb.append(" in "); sb.append(expressionToString(query.From.Origin)); sb.append("\r\n"); formatQueryBody(query.Body, sb); break; default: throw new RuntimeException("Unhandled expression type: " + expression.ExpressionKind); } return sb.toString(); }
static bool isAssignable(CompilerContext context, TypeInfo type, ExpressionNode expression) { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return !type.IsPrimitive; } var right = getType(context, expression); if (type.isAssignableFrom(right)) { return true; } if (expression.ExpressionKind == ExpressionKind.ArrayInitializer) { if (!type.IsArray) { return false; } foreach (var e in ((ArrayInitializerExpressionNode)expression).Values) { if (!isAssignable(context, type.ElementType, e)) { return false; } } return true; } if (type.IsNumeric && info.IsConstant) { switch (type.NumericTypeKind) { case Byte: { long value; switch (right.TypeKind) { case Char: value = ((Character)info.Value).charValue(); break; case Int: case Long: case Short: value = ((Number)info.Value).longValue(); break; default: return false; } return Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE; } case Char: { long value; switch (right.TypeKind) { case Byte: case Int: case Long: case Short: value = ((Number)info.Value).longValue(); break; default: return false; } return Character.MIN_VALUE <= value && value <= Character.MAX_VALUE; } case Short: { long value; switch (right.TypeKind) { case Byte: return true; case Char: value = ((Character)info.Value).charValue(); break; case Int: case Long: value = ((Number)info.Value).longValue(); break; default: return false; } return Short.MIN_VALUE <= value && value <= Short.MAX_VALUE; } case Int: { long value; switch (right.getTypeKind()) { case Char: value = ((Character)info.Value).charValue(); break; case Byte: case Short: return true; case Long: value = ((Number)info.getValue()).longValue(); break; default: return false; } return Integer.MIN_VALUE <= value && value <= Integer.MAX_VALUE; } } } return false; }
private void makeOutputTypeInference(ExpressionNode expression, TypeInfo toType, HashMap<TypeInfo, TypeVariableInfo> typeVariables) { if (expression.ExpressionKind == ExpressionKind.Lambda || BytecodeHelper.isDelegateType(toType) || BytecodeHelper.isExpressionTreeType(toType)) { MethodInfo method = getInvokeMethod(toType); if (method == null) { return; } if (expression.ExpressionKind == ExpressionKind.Lambda) { var lambda = (LambdaExpressionNode)expression; if (lambda.Parameters.size() != method.Parameters.count()) { return; } } var paramTypes = new ArrayList<TypeInfo>(); foreach (var p in method.Parameters) { TypeVariableInfo pinfo = typeVariables[p.Type]; if (pinfo != null) { if (pinfo.fixedType != null) { paramTypes.add(pinfo.fixedType); } else { return; } } else { var t = bindGenericParameters(typeVariables, p.Type); if (t == null) { return; } else { paramTypes.add(t); } } } if (expression.ExpressionKind == ExpressionKind.Lambda) { context.CodeValidationContext.pushLambdaParameters(paramTypes); var success = expressionValidator.handleExpressionNoError(expression, null, true); context.CodeValidationContext.popLambdaParameters(); var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } expression.removeUserData(typeof(ExpressionInfo)); if (success) { makeLowerBoundInference(context.CodeValidationContext.LambdaReturnType, method.ReturnType, typeVariables); } } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } var meth = resolveMethodGroup(info, method, paramTypes); if (meth == null) { makeLowerBoundInference(ValidationHelper.getType(context, expression), toType, typeVariables); } else { makeLowerBoundInference(meth.ReturnType, method.ReturnType, typeVariables); } } } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } makeLowerBoundInference(info.Type, toType, typeVariables); } }
private void print(ExpressionNode expression, StringBuilder sb) { if (expression.Parenthesized) { sb.append("("); } switch (expression.ExpressionKind) { case Literal: var literal = (LiteralExpressionNode)expression; sb.append(new String(text, literal.ValueOffset, literal.ValueLength)); break; case SimpleName: var name = (SimpleNameExpressionNode)expression; sb.append(name.Name ?? new String(text, name.NameOffset, name.NameLength)); if (name.TypeArguments.size() > 0) { print(name.TypeArguments, sb); } break; case Invocation: var invocation = (InvocationExpressionNode)expression; print(invocation.TargetObject, sb); sb.append("("); var first = true; foreach (var arg in invocation.getArguments()) { if (first) { first = false; } else { sb.append(", "); } print(arg, sb); } sb.append(")"); break; case MemberAccess: var access = (MemberAccessExpressionNode)expression; print(access.TargetObject, sb); sb.append("."); sb.append(access.Member.Name ?? new String(text, access.Member.NameOffset, access.Member.NameLength)); if (access.Member.TypeArguments.size() > 0) { print(access.Member.TypeArguments, sb); } break; case NullSafeMemberAccess: var nsaccess = (NullSafeMemberAccessExpressionNode)expression; print(nsaccess.TargetObject, sb); sb.append("?."); sb.append(nsaccess.Member.Name ?? new String(text, nsaccess.Member.NameOffset, nsaccess.Member.NameLength)); if (nsaccess.Member.TypeArguments.size() > 0) { print(nsaccess.Member.TypeArguments, sb); } break; case Assign: var assign = (AssignExpressionNode)expression; print(assign.Left, sb); switch (assign.Operator) { case Assign: sb.append(" = "); break; case Or: sb.append(" |= "); break; case Add: sb.append(" += "); break; case Multiply: sb.append(" *= "); break; default: throw new RuntimeException("Assignment not supported: " + assign.getOperator()); } print(assign.Right, sb); break; case ElementAccess: var elementAccess = (ElementAccessExpressionNode)expression; print(elementAccess.TargetObject, sb); sb.append("["); first = true; foreach (var i in elementAccess.Indexes) { if (first) { first = false; } else { sb.append(", "); } print(i, sb); } sb.append("]"); break; case Unary: var unary = (UnaryExpressionNode)expression; switch (unary.Operator) { case PostIncrement: case PostDecrement: break; case Plus: sb.append("+"); break; case Minus: sb.append("-"); break; case Not: sb.append("!"); break; case Complement: sb.append("~"); break; case PreIncrement: sb.append("++"); break; case PreDecrement: sb.append("--"); break; default: throw new RuntimeException("Unary operator not supported: " + unary.getOperator()); } print(unary.Operand, sb); switch (unary.Operator) { case PostIncrement: sb.append("++"); break; case PostDecrement: sb.append("--"); break; } break; case Binary: var binary = (BinaryExpressionNode)expression; print(binary.LeftOperand, sb); switch (binary.Operator) { case Add: sb.append(" + "); break; case Subtract: sb.append(" - "); break; case Multiply: sb.append(" * "); break; case Modulo: sb.append(" % "); break; case Divide: sb.append(" / "); break; case Equal: sb.append(" == "); break; case NotEqual: sb.append(" != "); break; case LessThan: sb.append(" < "); break; case LessThanOrEqual: sb.append(" <= "); break; case GreaterThan: sb.append(" > "); break; case GreaterThanOrEqual: sb.append(" >= "); break; case LeftShift: sb.append(" << "); break; case RightShift: sb.append(" >> "); break; case UnsignedRightShift: sb.append(" >>> "); break; case LogicalAnd: sb.append(" && "); break; case LogicalOr: sb.append(" || "); break; case And: sb.append(" & "); break; case Or: sb.append(" | "); break; case NullCoalescing: sb.append(" ?? "); break; case Instanceof: sb.append(" is "); break; case As: sb.append(" as "); break; default: throw new RuntimeException("Binary operator not supported: " + binary.getOperator()); } print(binary.RightOperand, sb); break; case ObjectCreation: var objectCreation = (ObjectCreationExpressionNode)expression; sb.append("new "); print(objectCreation.Type, sb); if (objectCreation.Arguments.size() > 0 || objectCreation.Initializer == null) { sb.append("("); first = true; foreach (var arg in objectCreation.Arguments) { if (first) { first = false; } else { sb.append(", "); } print(arg, sb); } sb.append(")"); } if (objectCreation.Initializer != null) { print(objectCreation.Initializer, sb); } break; case ObjectInitializer: var objectInit = (ObjectInitializerExpressionNode)expression; sb.append("{ "); first = true; foreach (var mi in objectInit.getMemberInitializers()) { if (first) { first = false; } else { sb.append(", "); } sb.append(new String(text, mi.NameOffset, mi.NameLength)); sb.append(" = "); print(mi.Value, sb); } sb.append(" }"); break; case ArrayCreation: var arrayCreation = (ArrayCreationExpressionNode)expression; sb.append("new"); if (arrayCreation.Type != null) { sb.append(" "); print(arrayCreation.Type, sb); } if (arrayCreation.DimensionExpressions.size() > 0) { sb.append("["); first = true; foreach (var exp in arrayCreation.DimensionExpressions) { if (first) { first = false; } else { sb.append(", "); } print(exp, sb); } sb.append("]"); } if (arrayCreation.Dimensions > 0) { sb.append("["); for (int i = 1; i < arrayCreation.Dimensions; i++) { sb.append(","); } sb.append("]"); } if (arrayCreation.Initializer != null) { print(arrayCreation.Initializer, sb); } break; case ArrayInitializer: var arrayInit = (ArrayInitializerExpressionNode)expression; sb.append("{ "); first = true; foreach (var v in arrayInit.Values) { if (first) { first = false; } else { sb.append(", "); } print(v, sb); } sb.append(" }"); break; case CollectionInitializer: var collInit = (CollectionInitializerExpressionNode)expression; sb.append("{ "); first = true; foreach (var v in collInit.Values) { if (first) { first = false; } else { sb.append(", "); } sb.append("{ "); var firstExp = true; foreach (var exp in v) { if (firstExp) { firstExp = false; } else { sb.append(", "); } print(exp, sb); } sb.append(" }"); } sb.append(" }"); break; case Lambda: var lambda = (LambdaExpressionNode)expression; if (lambda.Parameters.size() == 1 && lambda.Parameters[0].Type == null) { sb.append(lambda.Parameters[0].Name ?? new String(text, lambda.Parameters[0].NameOffset, lambda.Parameters[0].NameLength)); } else { sb.append("("); first = true; foreach (var p in lambda.Parameters) { if (first) { first = false; } else { sb.append(", "); } if (p.Type != null) { print(p.Type, sb); sb.append(" "); } sb.append(p.Name ?? new String(text, p.NameOffset, p.NameLength)); } sb.append(")"); } sb.append(" => "); print(lambda.Body, 0, false, sb); break; case Typeof: var typeofExp = (TypeofExpressionNode)expression; sb.append("typeof("); print(typeofExp.Type, sb); sb.append(")"); break; case AnonymousObjectCreation: var anonymous = (AnonymousObjectCreationExpressionNode)expression; sb.append("new { "); first = true; foreach (var decl in anonymous.MemberDeclarators) { if (first) { first = false; } else { sb.append(", "); } if (decl.NameLength > 0) { sb.append(new String(text, decl.NameOffset, decl.NameLength)); sb.append(" = "); } print(decl.Value, sb); } sb.append(" }"); break; default: throw new RuntimeException("Expression not supported: " + expression.getExpressionKind()); } if (expression.Parenthesized) { sb.append(")"); } }
private void makeExplicitParameterTypeInference(ExpressionNode expression, TypeInfo toType, HashMap<TypeInfo, TypeVariableInfo> typeVariableInfos) { var method = getInvokeMethod(toType); if (method == null) { return; } if (expression.ExpressionKind == ExpressionKind.Lambda) { var lambda = (LambdaExpressionNode)expression; if (lambda.Parameters.size() != method.Parameters.count()) { return; } } var rinfo = typeVariableInfos[method.ReturnType]; if (rinfo != null) { foreach (var p in method.Parameters) { if (p.Type == method.ReturnType) { continue; } var pinfo = typeVariableInfos[p.Type]; if (pinfo != null) { rinfo.dependencies.add(pinfo.genericParameterType); } } } if (expression.ExpressionKind == ExpressionKind.Lambda) { var lambda = (LambdaExpressionNode)expression; var fromTypes = new ArrayList<TypeInfo>(); var pit = method.Parameters.iterator(); foreach (var p in lambda.Parameters) { var ptype = pit.next().Type; if (p.Type == null) { if (ptype.IsClosed) { fromTypes.add(ptype); } else { return; } } else { fromTypes.add(CompilerHelper.resolveTypeReference(context, context.CurrentType.PackageName, p.Type)); } } context.CodeValidationContext.pushLambdaParameters(fromTypes); bool success = expressionValidator.handleExpressionNoError(expression, null, true); context.CodeValidationContext.popLambdaParameters(); var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } expression.removeUserData(typeof(ExpressionInfo)); if (!success) { return; } var mit = method.Parameters.iterator(); var fit = fromTypes.iterator(); while (mit.hasNext()) { makeExactInference(fit.next(), mit.next().Type, typeVariableInfos); } makeExactInference(context.CodeValidationContext.LambdaReturnType, method.ReturnType, typeVariableInfos); } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return; } var paramTypes = new ArrayList<TypeInfo>(); foreach (var p in method.Parameters) { paramTypes.add(p.Type); } var meth = resolveMethodGroup(info, method, paramTypes); if (meth == null) { return; } var mit = method.Parameters.iterator(); var cit = meth.Parameters.iterator(); while (mit.hasNext()) { makeExactInference(cit.next().Type, mit.next().Type, typeVariableInfos); } makeExactInference(meth.ReturnType, method.ReturnType, typeVariableInfos); } }
private VarargCompatible isVarargCompatible(ExpressionNode argNode, TypeInfo paramType, bool first) { var ainfo = argNode.getUserData(typeof(ExpressionInfo)); if (ainfo == null) { if (!expressionValidator.handleExpressionNoError(argNode, paramType, true)) { return VarargCompatible.False; } ainfo = argNode.getUserData(typeof(ExpressionInfo)); } if (ainfo == null) { if (paramType.IsPrimitive) { return VarargCompatible.False; } } else if (BytecodeHelper.isDelegateType(paramType)) { if (!resolveDelegate(paramType, argNode, null, null)) { return VarargCompatible.False; } } else if (ValidationHelper.isMethod(argNode)) { return VarargCompatible.False; } else if (paramType != ValidationHelper.getType(context, argNode)) { if (!ValidationHelper.isAssignable(context, paramType, argNode)) { if (first) { if (ValidationHelper.isAssignable(context, paramType.ArrayType, argNode)) { return VarargCompatible.True; } } return VarargCompatible.False; } } return VarargCompatible.TrueExpanded; }
private bool isArgumentCompatible(ExpressionNode argNode, TypeInfo paramType) { var ainfo = argNode.getUserData(typeof(ExpressionInfo)); var cleanInfo = false; if (ainfo == null && argNode.ExpressionKind == ExpressionKind.Lambda) { if (!expressionValidator.handleExpressionNoError(argNode, paramType, true)) { argNode.removeUserData(typeof(ExpressionInfo)); return false; } ainfo = argNode.getUserData(typeof(ExpressionInfo)); cleanInfo = true; } if (ainfo == null) { return !paramType.IsPrimitive; } if (BytecodeHelper.isDelegateType(paramType)) { if (!resolveDelegate(paramType, argNode, null, null)) { if (cleanInfo) { argNode.removeUserData(typeof(ExpressionInfo)); } return false; } } else if (ValidationHelper.isMethod(argNode)) { return false; } else if (paramType != ValidationHelper.getType(context, argNode)) { if (!ValidationHelper.isAssignable(context, paramType, argNode)) { if (cleanInfo) { argNode.removeUserData(typeof(ExpressionInfo)); } return false; } } if (cleanInfo) { argNode.removeUserData(typeof(ExpressionInfo)); } return true; }
bool resolveDelegate(TypeInfo type, ExpressionNode arg, ExpressionInfo targetInfo, SyntaxNode node) { var invokeMethod = getInvokeMethod(type); int nparams = invokeMethod.Parameters.count(); var ainfo = arg.getUserData(typeof(ExpressionInfo)); if (ainfo.Members == null) { return true; } MemberInfo foundMember = null; foreach (var member in ainfo.Members) { switch (member.MemberKind) { case Method: var meth = member.Method; if (meth.Parameters.count() != nparams || meth.IsVarargs != invokeMethod.IsVarargs) { continue; } if (nparams == 0) { if (foundMember != null) { if (node != null) { throw context.error(CompileErrorId.AmbiguousMembers, node, BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method), BytecodeHelper.getDisplayName(foundMember.DeclaringType) + "." + BytecodeHelper.getDisplayName(foundMember.Method)); } else { return false; } } foundMember = member; ainfo.Member = member; if (meth.IsExcludedFromCompilation || CompilerHelper.shouldIgnoreCalls(context, meth)) { if (node != null) { throw context.error(CompileErrorId.NotGeneratedMethodUsage, node, BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method)); } else { return false; } } if (targetInfo != null) { targetInfo.Type = type; targetInfo.Method = meth; } continue; } var it1 = meth.Parameters.iterator(); var it2 = invokeMethod.Parameters.iterator(); var sameParams = true; while (it1.hasNext()) { if (it1.next().Type != it2.next().Type) { sameParams = false; break; } } if (sameParams) { if (foundMember != null) { if (node != null) { throw context.error(CompileErrorId.AmbiguousMembers, node, BytecodeHelper.getDisplayName(member.DeclaringType) + "." + BytecodeHelper.getDisplayName(member.Method), BytecodeHelper.getDisplayName(foundMember.DeclaringType) + "." + foundMember.Name); } else { return false; } } foundMember = member; ainfo.Member = member; if (targetInfo != null) { targetInfo.Type = type; targetInfo.Method = meth; } continue; } break; case Local: ainfo.Member = member; return true; case Field: case Property: foundMember = member; ainfo.Member = member; break; } } if (foundMember != null) { return true; } if (node != null) { throw context.error(CompileErrorId.NoEligibleOverload, node, ainfo.Members.first().Name); } else { return false; } }
private BetterConversionResult getBetterConversionFromExpression(TypeInfo leftType, TypeInfo rightType, ExpressionNode expression) { if (leftType == rightType) { return BetterConversionResult.Neither; } if (expression.ExpressionKind == ExpressionKind.Lambda) { var leftMethod = getInvokeMethod(leftType); var rightMethod = getInvokeMethod(rightType); var leftReturnType = leftMethod.ReturnType; var rightReturnType = rightMethod.ReturnType; var lit = leftMethod.Parameters.iterator(); var rit = rightMethod.Parameters.iterator(); List<TypeInfo> paramTypes = null; while (lit.hasNext()) { var lt = lit.next().Type; var rt = rit.next().Type; if (lt != rt) { return BetterConversionResult.Neither; } if (paramTypes == null) { paramTypes = new ArrayList<TypeInfo>(); } paramTypes.add(lt); } if (paramTypes != null) { context.CodeValidationContext.pushLambdaParameters(paramTypes); } else { context.CodeValidationContext.pushLambdaParameters(Collections.emptyList<TypeInfo>()); } expressionValidator.handleExpressionNoError(expression, null, true); context.CodeValidationContext.popLambdaParameters(); var info = expression.getUserData(typeof(ExpressionInfo)); expression.removeUserData(typeof(ExpressionInfo)); if (info != null) { if (leftReturnType == context.TypeSystem.VoidType) { return BetterConversionResult.RightIsBetter; } if (rightReturnType == context.TypeSystem.VoidType) { return BetterConversionResult.LeftIsBetter; } return getBetterConversionFromType(leftReturnType, rightReturnType, context.CodeValidationContext.LambdaReturnType); } return BetterConversionResult.Neither; } else { var info = expression.getUserData(typeof(ExpressionInfo)); if (info == null) { return BetterConversionResult.Neither; } return getBetterConversionFromType(leftType, rightType, ValidationHelper.getType(context, expression)); } }