protected override Type resolveExpressionType(Context ctx, bool mustReturn = true) { var leftType = LeftOperand.GetExpressionType(ctx); var rightType = RightOperand.GetExpressionType(ctx); var result = resolveOperatorType(ctx, leftType, rightType); if (result != null) return result; if (IsNumericOperator) { if (leftType.IsNumericType() && rightType.IsNumericType()) return resolveNumericType(ctx); } if (OverloadedMethodName != null) { try { m_OverloadedMethod = ctx.ResolveMethod(leftType, OverloadedMethodName, new[] { leftType, rightType }); // cannot be generic if (m_OverloadedMethod != null) return m_OverloadedMethod.ReturnType; } catch { } } Error(this, CompilerMessages.OperatorBinaryTypesMismatch, OperatorRepresentation, leftType, rightType); return null; }
/// <summary> /// Resolves the method as a global function, imported property or a local variable with a delegate. /// </summary> private void resolveGetIdentifier(Context ctx, GetIdentifierNode node) { var nameInfo = ctx.Scope.FindLocal(node.Identifier); if (nameInfo != null) { resolveExpression(ctx, node); return; } try { _Method = ctx.ResolveMethod( ctx.MainType.TypeInfo, node.Identifier, _ArgTypes, resolver: (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types) ); if (_Method == null) throw new KeyNotFoundException(); if(_ArgTypes.Length == 0 && node.Identifier.IsAnyOf(EntityNames.RunMethodName, EntityNames.EntryPointMethodName)) error(CompilerMessages.ReservedFunctionInvocation, node.Identifier); } catch (KeyNotFoundException) { error(CompilerMessages.FunctionNotFound, node.Identifier); } catch (AmbiguousMatchException) { error(CompilerMessages.FunctionInvocationAmbiguous, node.Identifier); } }
/// <summary> /// Resolves the method if the expression was a member getter (obj.field or type::field). /// </summary> private void resolveGetMember(Context ctx, GetMemberNode node) { _InvocationSource = node.Expression; var type = _InvocationSource != null ? _InvocationSource.Resolve(ctx) : ctx.ResolveType(node.StaticType); checkTypeInSafeMode(ctx, type); if (node.TypeHints != null && node.TypeHints.Count > 0) _TypeHints = node.TypeHints.Select(x => ctx.ResolveType(x, true)).ToArray(); try { // resolve a normal method try { _Method = ctx.ResolveMethod( type, node.MemberName, _ArgTypes, _TypeHints, (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types) ); if (_Method.IsStatic) _InvocationSource = null; return; } catch (KeyNotFoundException) { if (_InvocationSource == null) throw; } // resolve a callable field try { ctx.ResolveField(type, node.MemberName); resolveExpression(ctx, node); return; } catch (KeyNotFoundException) { } // resolve a callable property try { ctx.ResolveProperty(type, node.MemberName); resolveExpression(ctx, node); return; } catch (KeyNotFoundException) { } Arguments = (Arguments[0] is UnitNode) ? new List<NodeBase> {_InvocationSource} : new[] {_InvocationSource}.Union(Arguments).ToList(); var oldArgTypes = _ArgTypes; _ArgTypes = Arguments.Select(a => a.Resolve(ctx)).ToArray(); _InvocationSource = null; try { // resolve a local function that is implicitly used as an extension method _Method = ctx.ResolveMethod( ctx.MainType.TypeInfo, node.MemberName, _ArgTypes, resolver: (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types) ); return; } catch (KeyNotFoundException) { } // resolve a declared extension method // most time-consuming operation, therefore is last checked try { if(!ctx.Options.AllowExtensionMethods) throw new KeyNotFoundException(); _Method = ctx.ResolveExtensionMethod( type, node.MemberName, oldArgTypes, _TypeHints, (idx, types) => ctx.ResolveLambda(Arguments[idx] as LambdaNode, types) ); } catch (KeyNotFoundException) { var msg = node.StaticType != null ? CompilerMessages.TypeStaticMethodNotFound : CompilerMessages.TypeMethodNotFound; error(msg, type, node.MemberName); } } catch (AmbiguousMatchException) { error(CompilerMessages.TypeMethodInvocationAmbiguous, type, node.MemberName); } }
private void castDelegate(Context ctx, Type from, Type to) { var gen = ctx.CurrentILGenerator; var toCtor = ctx.ResolveConstructor(to, new[] {typeof (object), typeof (IntPtr)}); var fromMethod = ctx.ResolveMethod(from, "Invoke"); var toMethod = ctx.ResolveMethod(to, "Invoke"); var fromArgs = fromMethod.ArgumentTypes; var toArgs = toMethod.ArgumentTypes; if(fromArgs.Length != toArgs.Length || toArgs.Select((ta, id) => !ta.IsExtendablyAssignableFrom(fromArgs[id], true)).Any(x => x)) Error(CompilerMessages.CastDelegateArgTypesMismatch, from, to); if(!toMethod.ReturnType.IsExtendablyAssignableFrom(fromMethod.ReturnType, true)) Error(CompilerMessages.CastDelegateReturnTypesMismatch, from, to); if (fromMethod.IsStatic) gen.EmitNull(); else Expression.Compile(ctx, true); if (from.IsGenericType && to.IsGenericType && from.GetGenericTypeDefinition() == to.GetGenericTypeDefinition()) return; gen.EmitLoadFunctionPointer(fromMethod.MethodInfo); gen.EmitCreateObject(toCtor.ConstructorInfo); }
/// <summary> /// Resolves a method from the expression, considering it an instance of a delegate type. /// </summary> private void resolveExpression(Context ctx, NodeBase node) { var exprType = node.Resolve(ctx); if (!exprType.IsCallableType()) error(CompilerMessages.TypeNotCallable, exprType); try { // argtypes are required for partial application _Method = ctx.ResolveMethod(exprType, "Invoke", _ArgTypes); } catch (KeyNotFoundException) { // delegate argument types are mismatched: // infer whatever method there is and detect actual error _Method = ctx.ResolveMethod(exprType, "Invoke"); var argTypes = _Method.ArgumentTypes; if (argTypes.Length != _ArgTypes.Length) error(CompilerMessages.DelegateArgumentsCountMismatch, exprType, argTypes.Length, _ArgTypes.Length); for (var idx = 0; idx < argTypes.Length; idx++) { var fromType = _ArgTypes[idx]; var toType = argTypes[idx]; if (!toType.IsExtendablyAssignableFrom(fromType)) error(Arguments[idx], CompilerMessages.ArgumentTypeMismatch, fromType, toType); } } _InvocationSource = node; }
protected override Type resolve(Context ctx, bool mustReturn) { var type = Operand.Resolve(ctx); var result = resolveOperatorType(ctx); if (result != null) return result; if (OverloadedMethodName != null) { try { _OverloadedMethod = ctx.ResolveMethod(type, OverloadedMethodName, new[] { type }); // cannot be generic if (_OverloadedMethod != null) return _OverloadedMethod.ReturnType; } catch { } } error(CompilerMessages.OperatorUnaryTypeMismatch, OperatorRepresentation, type); return null; }
/// <summary> /// Emits code for equality and inequality comparison. /// </summary> private void compileEquality(Context ctx, Type left, Type right) { var gen = ctx.CurrentILGenerator; // compare two strings if (left == typeof (string) && right == typeof (string)) { LeftOperand.Compile(ctx, true); RightOperand.Compile(ctx, true); var method = typeof (string).GetMethod("Equals", new[] {typeof (string), typeof (string)}); gen.EmitCall(method); if (Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } // compare two numerics if (left.IsNumericType() && right.IsNumericType()) { loadAndConvertNumerics(ctx); gen.EmitCompareEqual(); if(Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } // compare nullable against another nullable, it's base type or null if (left.IsNullableType()) { if(left == right || Nullable.GetUnderlyingType(left) == right) compileNullable(ctx, LeftOperand, RightOperand); else if(right == typeof(NullType)) compileHasValue(ctx, LeftOperand); return; } if (right.IsNullableType()) { if (Nullable.GetUnderlyingType(right) == left) compileNullable(ctx, RightOperand, LeftOperand); else if (left == typeof(NullType)) compileHasValue(ctx, RightOperand); return; } // compare a reftype against a null if (left == typeof(NullType) || right == typeof(NullType)) { LeftOperand.Compile(ctx, true); RightOperand.Compile(ctx, true); gen.EmitCompareEqual(); if (Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } if (left is TypeBuilder && left == right) { var equals = ctx.ResolveMethod(left, "Equals", new [] { typeof (object) }); LeftOperand.Compile(ctx, true); RightOperand.Compile(ctx, true); gen.EmitCall(equals.MethodInfo); if (Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } }
protected override Type resolve(Context ctx, bool mustReturn) { var leftType = LeftOperand.Resolve(ctx); var rightType = RightOperand.Resolve(ctx); var result = resolveOperatorType(ctx, leftType, rightType); if (result != null) return result; if (OverloadedMethodName != null) { try { _OverloadedMethod = ctx.ResolveMethod(leftType, OverloadedMethodName, new[] { leftType, rightType }); } catch { try { _OverloadedMethod = ctx.ResolveMethod(rightType, OverloadedMethodName, new[] { leftType, rightType }); } catch { } } // cannot be generic if (_OverloadedMethod != null) return _OverloadedMethod.ReturnType; } if (IsNumericOperator) { if (leftType.IsNullableType() || rightType.IsNullableType()) { var leftNullable = leftType.IsNullableType() ? leftType.GetGenericArguments()[0] : leftType; var rightNullable = rightType.IsNullableType() ? rightType.GetGenericArguments()[0] : rightType; var commonNumericType = TypeExtensions.GetNumericOperationType(leftNullable, rightNullable); if (commonNumericType == null) error(CompilerMessages.OperatorTypesSignednessMismatch); return typeof(Nullable<>).MakeGenericType(commonNumericType); } if (leftType.IsNumericType() && rightType.IsNumericType()) { var commonNumericType = TypeExtensions.GetNumericOperationType(leftType, rightType); if (commonNumericType == null) error(CompilerMessages.OperatorTypesSignednessMismatch); return commonNumericType; } } error(this, CompilerMessages.OperatorBinaryTypesMismatch, OperatorRepresentation, leftType, rightType); return null; }
private void detectEnumerableType(Context ctx) { var seqType = IterableExpression.GetExpressionType(ctx); if (seqType.IsArray) { m_VariableType = seqType.GetElementType(); return; } var ifaces = GenericHelper.GetInterfaces(seqType); if(!ifaces.Any(i => i == typeof(IEnumerable) || (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))) Error(IterableExpression, CompilerMessages.TypeNotIterable, seqType); var enumerator = ctx.ResolveMethod(seqType, "GetEnumerator"); m_EnumeratorType = enumerator.ReturnType; m_CurrentProperty = ctx.ResolveProperty(m_EnumeratorType, "Current"); m_VariableType = m_CurrentProperty.PropertyType; }
public override void ProcessClosures(Context ctx) { if(LeftOperand is LambdaNode) LeftOperand.ProcessClosures(ctx); if (RightOperand is LambdaNode) RightOperand.ProcessClosures(ctx); var leftType = LeftOperand.GetExpressionType(ctx); var rightGetter = RightOperand as GetMemberNode; if (!IsLeft && leftType.IsCallableType() && rightGetter != null) { if (rightGetter.TypeHints.IsEmpty()) { var returnType = ctx.ResolveMethod(leftType, "Invoke").ReturnType; rightGetter.TypeHints = new List<TypeSignature> {TypeSignature.Parse(returnType.FullName)}; } } var rightType = RightOperand.GetExpressionType(ctx); if (rightGetter != null) rightGetter.TypeHints.Clear(); if (!IsLeft && leftType.IsCallableType() && rightType.IsCallableType()) { if (!ctx.CanCombineDelegates(leftType, rightType)) Error(Translations.CompilerMessages.DelegatesNotCombinable, leftType, rightType); var argTypes = ctx.WrapDelegate(leftType).ArgumentTypes; var argGetters = argTypes.Select((a, id) => Expr.GetArg(id)).Cast<NodeBase>().ToArray(); if (LeftOperand is GetMemberNode) (LeftOperand as GetMemberNode).TypeHints.Clear(); _Method = ctx.CurrentScope.CreateClosureMethod(ctx, argTypes, ctx.WrapDelegate(rightType).ReturnType); _Method.Body = Expr.Block( Expr.Invoke( RightOperand, Expr.Invoke( LeftOperand, argGetters ) ) ); var methodBackup = ctx.CurrentMethod; ctx.CurrentMethod = _Method; var scope = _Method.Scope; scope.InitializeScope(ctx); _Method.Body.ProcessClosures(ctx); _Method.PrepareSelf(); scope.FinalizeScope(ctx); ctx.CurrentMethod = methodBackup; } }
private void resolveGetMember(Context ctx, GetMemberNode node) { m_InvocationSource = node.Expression; var type = m_InvocationSource != null ? m_InvocationSource.GetExpressionType(ctx) : ctx.ResolveType(node.StaticType); SafeModeCheckType(ctx, type); if (node.TypeHints.Any()) m_TypeHints = node.TypeHints.Select(x => x.FullSignature == "_" ? null : ctx.ResolveType(x)).ToArray(); try { // resolve a normal method try { m_Method = ctx.ResolveMethod(type, node.MemberName, m_ArgTypes, m_TypeHints); if (m_Method.IsStatic) m_InvocationSource = null; return; } catch (KeyNotFoundException) { if (m_InvocationSource == null) throw; } // resolve a callable field try { ctx.ResolveField(type, node.MemberName); resolveExpression(ctx, node); return; } catch (KeyNotFoundException) { } // resolve a callable field try { ctx.ResolveProperty(type, node.MemberName); resolveExpression(ctx, node); return; } catch (KeyNotFoundException) { } // resolve a local function that is implicitly used as an extension method // move invocation source to arguments if (Arguments[0] is UnitNode) Arguments[0] = m_InvocationSource; else Arguments.Insert(0, m_InvocationSource); var oldArgTypes = m_ArgTypes; m_ArgTypes = Arguments.Select(a => a.GetExpressionType(ctx)).ToArray(); m_InvocationSource = null; try { m_Method = ctx.ResolveMethod(ctx.MainType.TypeInfo, node.MemberName, m_ArgTypes); } catch (KeyNotFoundException) { // resolve a declared extension method // most time-consuming operation, therefore is last checked if(ctx.Options.AllowExtensionMethods) m_Method = ctx.ResolveExtensionMethod(type, node.MemberName, oldArgTypes, m_TypeHints); } } catch (AmbiguousMatchException) { Error(CompilerMessages.TypeMethodInvocationAmbiguous, type, node.MemberName); } catch (KeyNotFoundException) { var msg = node.StaticType != null ? CompilerMessages.TypeStaticMethodNotFound : CompilerMessages.TypeMethodNotFound; Error(msg, type, node.MemberName); } }
private void resolveGetIdentifier(Context ctx, GetIdentifierNode node) { var nameInfo = ctx.CurrentScope.FindName(node.Identifier); if (nameInfo != null) { resolveExpression(ctx, node); return; } try { m_Method = ctx.ResolveMethod(ctx.MainType.TypeInfo, node.Identifier, m_ArgTypes); if (m_Method == null) throw new KeyNotFoundException(); if(m_ArgTypes.Length == 0 && EnumerableExtensions.IsAnyOf(node.Identifier, EntityNames.RunMethodName, EntityNames.EntryPointMethodName)) Error(CompilerMessages.ReservedFunctionInvocation, node.Identifier); } catch (KeyNotFoundException) { Error(CompilerMessages.FunctionNotFound, node.Identifier); } catch (AmbiguousMatchException) { Error(CompilerMessages.FunctionInvocationAmbiguous, node.Identifier); } }
private void resolveExpression(Context ctx, NodeBase node) { var exprType = node.GetExpressionType(ctx); if (!exprType.IsCallableType()) Error(CompilerMessages.TypeNotCallable, exprType); m_Method = ctx.ResolveMethod(exprType, "Invoke"); var argTypes = m_Method.ArgumentTypes; if (argTypes.Length != m_ArgTypes.Length) Error(CompilerMessages.DelegateArgumentsCountMismatch, exprType, argTypes.Length, m_ArgTypes.Length); for (var idx = 0; idx < argTypes.Length; idx++) { var fromType = m_ArgTypes[idx]; var toType = argTypes[idx]; if (!toType.IsExtendablyAssignableFrom(fromType)) Error(Arguments[idx], CompilerMessages.ArgumentTypeMismatch, fromType, toType); } m_InvocationSource = node; }
/// <summary> /// Emits code for equality and inequality comparison. /// </summary> private void emitEqualityComparison(Context ctx, Type left, Type right) { var gen = ctx.CurrentMethod.Generator; // compare two strings if (left == right && left == typeof (string)) { LeftOperand.Emit(ctx, true); RightOperand.Emit(ctx, true); var method = typeof (string).GetMethod("Equals", new[] {typeof (string), typeof (string)}); gen.EmitCall(method); if (Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } // compare primitive types if ((left.IsNumericType() && right.IsNumericType()) || (left == right && left == typeof(bool))) { if (left == typeof (bool)) { LeftOperand.Emit(ctx, true); RightOperand.Emit(ctx, true); } else { loadAndConvertNumerics(ctx); } gen.EmitCompareEqual(); if(Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } // compare nullable against another nullable, it's base type or null if (left.IsNullableType()) { if(left == right || Nullable.GetUnderlyingType(left) == right) emitNullableComparison(ctx, LeftOperand, RightOperand); else if(right == typeof(NullType)) emitHasValueCheck(ctx, LeftOperand); return; } if (right.IsNullableType()) { if (Nullable.GetUnderlyingType(right) == left) emitNullableComparison(ctx, RightOperand, LeftOperand); else if (left == typeof(NullType)) emitHasValueCheck(ctx, RightOperand); return; } // compare a reftype against a null if (left == typeof(NullType) || right == typeof(NullType)) { LeftOperand.Emit(ctx, true); RightOperand.Emit(ctx, true); gen.EmitCompareEqual(); if (Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } if (left is TypeBuilder && left == right) { var equals = ctx.ResolveMethod(left, "Equals", new [] { typeof (object) }); LeftOperand.Emit(ctx, true); RightOperand.Emit(ctx, true); gen.EmitCall(equals.MethodInfo); if (Kind == ComparisonOperatorKind.NotEquals) emitInversion(gen); return; } throw new ArgumentException("Unknown types to compare!"); }