protected override Void handleIf(IfStatementNode ifStatement, Void source) { var condition = ifStatement.Condition; this.ExpressionValidator.handleExpression(condition, context.TypeSystem.BooleanType, true); ValidationHelper.setBoxing(context, context.TypeSystem.BooleanType, condition); var cinfo = condition.getUserData(typeof(ExpressionInfo)); if (cinfo == null || ValidationHelper.getType(context, condition) != context.TypeSystem.BooleanType) { throw context.error(CompileErrorId.NoImplicitConversion, condition, BytecodeHelper.getDisplayName(cinfo == null ? null : cinfo.Type), BytecodeHelper.getDisplayName(context.TypeSystem.BooleanType)); } try { context.MemberResolver.enterScope(); handleStatement(ifStatement.IfTrue, null); } finally { context.MemberResolver.leaveScope(); } if (ifStatement.IfFalse != null) { try { context.MemberResolver.enterScope(); handleStatement(ifStatement.IfFalse, null); } finally { context.MemberResolver.leaveScope(); } } return(null); }
protected override Void handleYield(YieldStatementNode yieldStatement, Void source) { var returnType = context.CodeValidationContext.CurrentMethod.ReturnType; var value = yieldStatement.Value; if (returnType == null) { if (value != null) { this.ExpressionValidator.handleExpression(value, returnType, true); } } else { var elementType = BytecodeHelper.getIterableOrIteratorElementType(returnType); if (elementType == null) { throw context.error(CompileErrorId.YieldOutsideIterator, yieldStatement); } if (value != null) { this.ExpressionValidator.handleExpression(value, elementType, true); ValidationHelper.setBoxing(context, elementType, value); if (!ValidationHelper.isAssignable(context, elementType, value)) { throw context.error(CompileErrorId.NoImplicitConversion, value, BytecodeHelper.getDisplayName(ValidationHelper.getType(context, value)), BytecodeHelper.getDisplayName(elementType)); } } } if (context.Iterables[context.CodeValidationContext.CurrentMethod] == null) { var prefix = "_" + context.CodeValidationContext.CurrentMethod.Name + "_Iterable"; int n = context.CurrentType.NestedTypes.count(p => p.Name.startsWith(prefix)); var typeBuilder = ((TypeBuilder)context.CurrentType).defineNestedType(prefix + n); typeBuilder.setSourceFile(PathHelper.getFileName(yieldStatement.Filename)); typeBuilder.setSynthetic(true); typeBuilder.setSuper(true); context.Iterables[context.CodeValidationContext.CurrentMethod] = typeBuilder; context.TypeBuilders.add(typeBuilder); typeBuilder.setBaseType(context.TypeSystem.ObjectType); } return(null); }
protected override Void handleReturn(ReturnStatementNode returnStatement, Void source) { var returnType = context.CodeValidationContext.CurrentMethod.ReturnType; if (returnType == null) { if (returnStatement.Value != null) { this.ExpressionValidator.handleExpression(returnStatement.Value, null, true); var rinfo = returnStatement.Value.getUserData(typeof(ExpressionInfo)); if (rinfo == null) { context.CodeValidationContext.LambdaReturnTypes.add(null); } else { context.CodeValidationContext.LambdaReturnTypes.add(ValidationHelper.getType(context, returnStatement.Value)); } } } else if (returnType == context.TypeSystem.VoidType) { if (returnStatement.Value != null) { context.addError(CompileErrorId.ReturnVoid, returnStatement); } } else if (returnStatement.Value == null) { context.addError(CompileErrorId.ReturnNotVoid, returnStatement); } else { this.ExpressionValidator.handleExpression(returnStatement.Value, returnType, true); ValidationHelper.setBoxing(context, returnType, returnStatement.Value); if (!ValidationHelper.isAssignable(context, returnType, returnStatement.Value)) { var vinfo = returnStatement.Value.getUserData(typeof(ExpressionInfo)); context.addError(CompileErrorId.NoImplicitConversion, returnStatement.Value, BytecodeHelper.getDisplayName((vinfo == null) ? null : vinfo.Type), BytecodeHelper.getDisplayName(returnType)); } } return(null); }
protected override Void handleForeach(ForeachStatementNode foreachStatement, Void src) { try { context.MemberResolver.enterScope(); var source = foreachStatement.Source; this.ExpressionValidator.handleExpression(source, null, true); var sinfo = source.getUserData(typeof(ExpressionInfo)); if (sinfo == null) { throw context.error(CompileErrorId.NoImplicitConversion, source, "<null>", BytecodeHelper.getDisplayName(context.TypeSystem.getType("java/lang/Iterable"))); } var sourceType = ValidationHelper.getType(context, source); TypeInfo elementType; if (sourceType.IsArray) { elementType = sourceType.ElementType; } else { var iterableType = BytecodeHelper.getImplementedIterable(sourceType); if (iterableType == null) { throw context.error(CompileErrorId.NoImplicitConversion, source, BytecodeHelper.getDisplayName(sourceType), BytecodeHelper.getDisplayName(context.TypeSystem.getType("java/lang/Iterable"))); } foreachStatement.addOrReplaceUserData(iterableType); elementType = BytecodeHelper.getIterableOrIteratorElementType(iterableType); } var localName = context.getIdentifier(foreachStatement.NameOffset, foreachStatement.NameLength); if (context.MemberResolver.hasLocal(localName)) { context.addError(CompileErrorId.VariableRedefinition, foreachStatement, localName); } var local = context.MemberResolver.defineLocal(localName, ValidationHelper.getVariableType(context, elementType), context.CodeValidationContext.CurrentMethod); foreachStatement.addOrReplaceUserData(local); handleStatement(foreachStatement.Statement, null); } finally { context.MemberResolver.leaveScope(); } return(null); }
protected override Void handleUsing(UsingStatementNode usingStatement, Void source) { try { context.MemberResolver.enterScope(); var resource = usingStatement.ResourceAcquisition; handleStatement(resource, null); if (resource.StatementKind == StatementKind.Expression) { var expr = ((ExpressionStatementNode)resource).Expression; var einfo = expr.getUserData(typeof(ExpressionInfo)); if (einfo == null || BytecodeHelper.getDisposeMethod(context.AnnotatedTypeSystem, ValidationHelper.getType(context, expr)) == null) { context.addError(CompileErrorId.NoDisposeMethod, expr, BytecodeHelper.getDisplayName(einfo == null ? null : einfo.Type)); } } else { foreach (var decl in ((LocalDeclarationStatementNode)resource).Declarators) { if (decl.Value == null) { context.addError(CompileErrorId.UsingVariableUninitialized, decl); } else { var vinfo = decl.Value.getUserData(typeof(ExpressionInfo)); if (vinfo == null || BytecodeHelper.getDisposeMethod(context.AnnotatedTypeSystem, ValidationHelper.getType(context, decl.Value)) == null) { context.addError(CompileErrorId.NoDisposeMethod, decl.Value, BytecodeHelper.getDisplayName(vinfo == null ? null : vinfo.Type)); } } } } handleStatement(usingStatement.Statement, null); } finally { context.MemberResolver.leaveScope(); } return(null); }
protected override Void handleThrow(ThrowStatementNode throwStatement, Void source) { var exception = throwStatement.Exception; if (exception != null) { this.ExpressionValidator.handleExpression(exception, null, true); var einfo = exception.getUserData(typeof(ExpressionInfo)); if (einfo != null) { if (!context.TypeSystem.getType("java/lang/Throwable").isAssignableFrom(ValidationHelper.getType(context, exception))) { throw context.error(CompileErrorId.NoImplicitConversion, exception, BytecodeHelper.getDisplayName(einfo.Type), "java.lang.Throwable"); } } } return(null); }
protected override Void handleTry(TryStatementNode tryStatement, Void source) { handleStatement(tryStatement.Block, source); foreach (var node in tryStatement.CatchClauses) { try { context.MemberResolver.enterScope(); if (node.ExceptionType != null) { var etype = CompilerHelper.resolveTypeReference(context, context.CurrentType.PackageName, node.ExceptionType); node.addOrReplaceUserData(etype); if (etype.IsGenericParameter) { throw context.error(CompileErrorId.GenericParameterInCatch, node.ExceptionType, BytecodeHelper.getDisplayName(etype)); } if (!context.TypeSystem.getType("java/lang/Throwable").isAssignableFrom(etype)) { throw context.error(CompileErrorId.NoImplicitConversion, node.ExceptionType, BytecodeHelper.getDisplayName(etype), "java.lang.Throwable"); } if (node.NameLength > 0) { var local = context.MemberResolver.defineLocal(context.getIdentifier(node.NameOffset, node.NameLength), etype, context.CodeValidationContext.CurrentMethod); node.addOrReplaceUserData(local); } } foreach (var s in node.Block.Statements) { handleStatement(s, source); } } finally { context.MemberResolver.leaveScope(); } } if (tryStatement.Finally != null) { handleStatement(tryStatement.Finally, source); } return(null); }
protected override Void handleFor(ForStatementNode forStatement, Void source) { try { context.MemberResolver.enterScope(); foreach (var s in forStatement.Initializer) { handleStatement(s, null); } var condition = forStatement.Condition; if (condition != null) { this.ExpressionValidator.handleExpression(condition, null, true); ValidationHelper.setBoxing(context, context.TypeSystem.BooleanType, condition); var info = condition.getUserData(typeof(ExpressionInfo)); if (info == null || ValidationHelper.getType(context, condition) != context.TypeSystem.BooleanType) { throw context.error(CompileErrorId.NoImplicitConversion, condition, BytecodeHelper.getDisplayName(info == null ? null : info.Type), BytecodeHelper.getDisplayName(context.TypeSystem.BooleanType)); } } try { context.MemberResolver.enterScope(); handleStatement(forStatement.Statement, source); } finally { context.MemberResolver.leaveScope(); } foreach (var s in forStatement.Iterator) { handleStatement(s, source); } } finally { context.MemberResolver.leaveScope(); } return(null); }
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)); }
protected override Void handleSwitch(SwitchStatementNode switchStatement, Void source) { this.ExpressionValidator.handleExpression(switchStatement.Selector, null, true); var sinfo = switchStatement.Selector.getUserData(typeof(ExpressionInfo)); if (sinfo == null) { throw context.error(CompileErrorId.IntegerStringOrEnumExpected, switchStatement.Selector); } var type = ValidationHelper.getType(context, switchStatement.getSelector()); if (!type.IsNumeric && !type.IsEnum && type != context.TypeSystem.StringType) { throw context.error(CompileErrorId.IntegerStringOrEnumExpected, switchStatement.Selector); } var isString = false; switch (type.NumericTypeKind) { case Long: case Float: case Double: throw context.error(CompileErrorId.IntegerStringOrEnumExpected, switchStatement.Selector); default: ValidationHelper.setBoxing(context, context.TypeSystem.IntType, switchStatement.getSelector()); break; case None: isString = !type.IsEnum; break; } var hasDefault = false; HashMap <String, Integer> enumOrdinals = null; HashSet <String> cases = null; if (type.IsEnum) { enumOrdinals = new HashMap <String, Integer>(); cases = new HashSet <String>(); int i = 0; foreach (var f in type.Fields) { if (f.IsEnum) { enumOrdinals[f.Name] = Integer.valueOf(i++); } } } try { context.MemberResolver.enterScope(); foreach (var section in switchStatement.Sections) { if (section.CaseExpression == null) { if (hasDefault) { throw context.error(CompileErrorId.DuplicateCase, section); } hasDefault = true; } else { if (type.IsEnum) { if (section.CaseExpression.ExpressionKind != ExpressionKind.SimpleName) { throw context.error(CompileErrorId.EnumCaseNotIdentifier, section); } var name = (SimpleNameExpressionNode)section.CaseExpression; var text = context.getIdentifier(name.NameOffset, name.NameLength); if (!cases.add(text)) { throw context.error(CompileErrorId.DuplicateCase, section); } if (!enumOrdinals.containsKey(text)) { throw context.error(CompileErrorId.UnknownEnumMember, section, text, BytecodeHelper.getDisplayName(type)); } name.addOrReplaceUserData(enumOrdinals.get(text)); } else { this.ExpressionValidator.handleExpression(section.CaseExpression, type, true); ValidationHelper.getType(context, section.CaseExpression); var cinfo = section.CaseExpression.getUserData(typeof(ExpressionInfo)); if (cinfo == null) { if (!isString) { throw context.error(CompileErrorId.UnexpectedNull, switchStatement); } } else { if (!cinfo.IsConstant) { throw context.error(CompileErrorId.ConstantValueExpected, section); } if (!type.isAssignableFrom(ValidationHelper.getType(context, section.CaseExpression))) { context.addError(CompileErrorId.NoImplicitConversion, section.CaseExpression, BytecodeHelper.getDisplayName(cinfo.Type), BytecodeHelper.getDisplayName(type)); } } } } foreach (var s in section.Statements) { handleStatement(s, null); } } } finally { context.MemberResolver.leaveScope(); } return(null); }
protected override Void handleLocalDeclaration(LocalDeclarationStatementNode localDeclaration, Void source) { if (localDeclaration.Type == null) { if (localDeclaration.Declarators.size() > 1) { context.addError(CompileErrorId.MultipleImplicitVariableDeclarators, localDeclaration); } var decl = localDeclaration.Declarators[0]; if (decl.Value == null) { throw context.error(CompileErrorId.MissingImplicitVariableInitializer, localDeclaration); } if (decl.Value.ExpressionKind == ExpressionKind.ArrayInitializer) { throw context.error(CompileErrorId.ImplicitVariableWithArrayInitializer, localDeclaration); } this.ExpressionValidator.handleExpression(decl.Value, null, true); var info = decl.Value.getUserData(typeof(ExpressionInfo)); if (info == null) { throw context.error(CompileErrorId.NullImplicitVariableInitializer, localDeclaration); } localDeclaration.addOrReplaceUserData(new ExpressionInfo(ValidationHelper.getType(context, decl.Value))); var name = context.getIdentifier(decl.NameOffset, decl.NameLength); if (context.MemberResolver.hasLocal(name)) { context.addError(CompileErrorId.VariableRedefinition, decl, name); } var local = context.MemberResolver.defineLocal(name, ValidationHelper.getVariableType(context, info.Type), context.CodeValidationContext.CurrentMethod); decl.addOrReplaceUserData(local); } else { var type = CompilerHelper.resolveTypeReference(context, context.CurrentType.PackageName, localDeclaration.Type); localDeclaration.addOrReplaceUserData(new ExpressionInfo(type)); foreach (var decl in localDeclaration.Declarators) { var name = context.getIdentifier(decl.NameOffset, decl.NameLength); if (decl.Value != null) { var isArrayInit = decl.Value.ExpressionKind == ExpressionKind.ArrayInitializer; if (isArrayInit && !type.IsArray) { throw context.error(CompileErrorId.ArrayTypeExpected, decl); } this.ExpressionValidator.handleExpression(decl.Value, type, true); ValidationHelper.setBoxing(context, type, decl.Value); if (!ValidationHelper.isAssignable(context, type, decl.Value)) { var vinfo = decl.Value.getUserData(typeof(ExpressionInfo)); var vtype = (vinfo == null) ? null : vinfo.Type; context.addError(CompileErrorId.NoImplicitConversion, decl.Value, BytecodeHelper.getDisplayName(vtype), BytecodeHelper.getDisplayName(type)); } if (isArrayInit) { ValidationHelper.setArrayInitializerTypes((ArrayInitializerExpressionNode)decl.Value, type); } } if (context.MemberResolver.hasLocal(name)) { context.addError(CompileErrorId.VariableRedefinition, decl, name); } var local = context.MemberResolver.defineLocal(name, ValidationHelper.getVariableType(context, type), context.CodeValidationContext.CurrentMethod); decl.addOrReplaceUserData(local); } } return(null); }