internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(Ast.Block(Transform(gen), AstUtils.Constant(null))); }
private DynamicMetaObject /*!*/ MakeSelfCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args) { BindingRestrictions selfRestrict = Restrictions.Merge( BindingRestrictionsHelpers.GetRuntimeTypeRestriction( Expression, LimitType ) ).Merge( BindingRestrictions.GetExpressionRestriction( Value.MakeBoundFunctionTest( AstUtils.Convert(Expression, typeof(BuiltinFunction)) ) ) ); Expression instance = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.GetBuiltinFunctionSelf)), AstUtils.Convert( Expression, typeof(BuiltinFunction) ) ); DynamicMetaObject self = GetInstance(instance, CompilerHelpers.GetType(Value.BindingSelf)); return(Value.MakeBuiltinFunctionCall( call, codeContext, this, ArrayUtils.Insert(self, args), true, // has self selfRestrict, (newArgs) => { CallSignature signature = BindingHelpers.GetCallSignature(call); DynamicMetaObject res; PythonContext state = PythonContext.GetPythonContext(call); BindingTarget target; PythonOverloadResolver resolver; if (Value.IsReversedOperator) { resolver = new PythonOverloadResolver( state.Binder, newArgs, GetReversedSignature(signature), codeContext ); } else { resolver = new PythonOverloadResolver( state.Binder, self, args, signature, codeContext ); } res = state.Binder.CallMethod( resolver, Value.Targets, self.Restrictions, Value.Name, NarrowingLevel.None, Value.IsBinaryOperator ? PythonNarrowing.BinaryOperator : NarrowingLevel.All, out target ); return BindingHelpers.CheckLightThrow(call, res, target); } )); }
internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen) { return(AstUtils.Constant(gen.Encoding)); }
public override DynamicMetaObject GetValue(OverloadResolverFactory resolverFactory, ActionBinder binder, Type type) { return(new DynamicMetaObject(AstUtils.Constant(GetSlot(), typeof(PythonTypeSlot)), BindingRestrictions.Empty)); }
internal override void BuildMethodMissingCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { var globalScope = args.TargetClass.GlobalScope; var context = globalScope.Context; if (name.LastCharacter() == '=') { var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 1, 1); if (!metaBuilder.Error) { var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); var interopSetter = context.MetaBinderFactory.InteropSetMember(name.Substring(0, name.Length - 1)); metaBuilder.SetMetaResult( interopSetter.Bind( new DynamicMetaObject( scopeVar, BindingRestrictions.Empty, globalScope.Scope ), new[] { normalizedArgs[0] } ), true ); } } else { RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); Expression errorExpr = metaBuilder.Error ? Ast.Throw(metaBuilder.Result, typeof(object)) : null; var scopeVar = metaBuilder.GetTemporary(typeof(Scope), "#scope"); var scopeLookupResultVar = metaBuilder.GetTemporary(typeof(object), "#result"); metaBuilder.AddInitialization( Ast.Assign(scopeVar, Methods.GetGlobalScopeFromScope.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)))) ); Expression scopeLookupResultExpr = errorExpr ?? scopeLookupResultVar; Expression fallbackExp; if (name == "scope") { fallbackExp = errorExpr ?? args.TargetExpression; } else { // super(methodName, ...args...) - ignore argument error: args.InsertMethodName(name); fallbackExp = AstUtils.LightDynamic( context.MetaBinderFactory.Call(Symbols.MethodMissing, new RubyCallSignature( args.Signature.ArgumentCount + 1, args.Signature.Flags | RubyCallFlags.HasImplicitSelf | RubyCallFlags.IsSuperCall ) ), typeof(object), args.GetCallSiteArguments(args.TargetExpression) ); } var scopeLookup = Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(RubyMetaBinderFactory.InteropTryGetMemberExact(name), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ); string unmanagled = RubyUtils.TryUnmangleMethodName(name); if (unmanagled != null) { scopeLookup = Ast.OrElse( scopeLookup, Ast.NotEqual( Ast.Assign(scopeLookupResultVar, AstUtils.LightDynamic(RubyMetaBinderFactory.InteropTryGetMemberExact(unmanagled), typeof(object), scopeVar)), Expression.Constant(OperationFailed.Value) ) ); } metaBuilder.Result = Ast.Condition( scopeLookup, scopeLookupResultExpr, fallbackExp ); } }
public override MSAst.Expression Reduce() { MSAst.Expression destination = _dest; if (_expressions.Length == 0) { MSAst.Expression result; if (destination != null) { result = Ast.Call( AstMethods.PrintNewlineWithDest, Parent.LocalContext, destination ); } else { result = Ast.Call( AstMethods.PrintNewline, Parent.LocalContext ); } return(GlobalParent.AddDebugInfo(result, Span)); } else { // Create list for the individual statements ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(); // Store destination in a temp, if we have one MSAst.ParameterExpression temp = null; if (destination != null) { temp = Ast.Variable(typeof(object), "destination"); statements.Add(MakeAssignment(temp, destination)); destination = temp; } for (int i = 0; i < _expressions.Length; i++) { bool withComma = (i < _expressions.Length - 1 || _trailingComma);// ? "PrintComma" : "Print"; Expression current = _expressions[i]; MSAst.MethodCallExpression mce; if (destination != null) { mce = Ast.Call( withComma ? AstMethods.PrintCommaWithDest : AstMethods.PrintWithDest, Parent.LocalContext, destination, AstUtils.Convert(current, typeof(object)) ); } else { mce = Ast.Call( withComma ? AstMethods.PrintComma : AstMethods.Print, Parent.LocalContext, AstUtils.Convert(current, typeof(object)) ); } statements.Add(mce); } statements.Add(AstUtils.Empty()); MSAst.Expression res; if (temp != null) { res = Ast.Block(new[] { temp }, statements.ToReadOnlyCollection()); } else { res = Ast.Block(statements.ToReadOnlyCollection()); } return(GlobalParent.AddDebugInfo(res, Span)); } }
private DynamicMetaObject TryToCharConversion(DynamicMetaObject /*!*/ self) { DynamicMetaObject res; // we have an implicit conversion to char if the // string length == 1, but we can only represent // this is implicit via a rule. string strVal = self.Value as string; Expression strExpr = self.Expression; if (strVal == null) { Extensible <string> extstr = self.Value as Extensible <string>; if (extstr != null) { strVal = extstr.Value; strExpr = Ast.Property( AstUtils.Convert( strExpr, typeof(Extensible <string>) ), typeof(Extensible <string>).GetProperty("Value") ); } } // we can only produce a conversion if we have a string value... if (strVal != null) { self = self.Restrict(self.GetRuntimeType()); Expression getLen = Ast.Property( AstUtils.Convert( strExpr, typeof(string) ), typeof(string).GetProperty("Length") ); if (strVal.Length == 1) { res = new DynamicMetaObject( Ast.Call( AstUtils.Convert(strExpr, typeof(string)), typeof(string).GetMethod("get_Chars"), AstUtils.Constant(0) ), self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.Equal(getLen, AstUtils.Constant(1)))) ); } else { res = new DynamicMetaObject( this.Throw( Ast.Call( typeof(PythonOps).GetMethod("TypeError"), AstUtils.Constant("expected string of length 1 when converting to char, got '{0}'"), Ast.NewArrayInit(typeof(object), self.Expression) ), ReturnType ), self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.NotEqual(getLen, AstUtils.Constant(1)))) ); } } else { // let the base class produce the rule res = null; } return(res); }
internal MSA.Expression DebugMarker(string /*!*/ marker) { return(_debugCompiler ? Methods.X.OpCall(AstUtils.Constant(marker)) : null); }
internal MSA.Expression /*!*/ DebugMark(MSA.Expression /*!*/ expression, string /*!*/ marker) { return(_debugCompiler ? Ast.Block(Methods.X.OpCall(AstUtils.Constant(marker)), expression) : expression); }
internal MSA.Expression /*!*/ TransformStatements(MSA.Expression prologue, Statements /*!*/ statements, MSA.Expression epilogue, ResultOperation resultOperation) { Assert.NotNull(statements); int count = statements.Count + (prologue != null ? 1 : 0) + (epilogue != null ? 1 : 0); if (count == 0) { if (resultOperation.IsIgnore) { return(AstUtils.Empty()); } else if (resultOperation.Variable != null) { return(Ast.Assign(resultOperation.Variable, AstUtils.Constant(null, resultOperation.Variable.Type))); } else { return(Ast.Return(CurrentFrame.ReturnLabel, AstUtils.Constant(null))); } } else if (count == 1) { if (prologue != null) { return(prologue); } if (epilogue != null) { return(epilogue); } if (resultOperation.IsIgnore) { return(statements.First.Transform(this)); } else { return(statements.First.TransformResult(this, resultOperation)); } } else { var result = new AstBlock(); if (prologue != null) { result.Add(prologue); } // transform all but the last statement if it is an expression stmt: foreach (var statement in statements.AllButLast) { result.Add(statement.Transform(this)); } if (statements.Count > 0) { if (resultOperation.IsIgnore) { result.Add(statements.Last.Transform(this)); } else { result.Add(statements.Last.TransformResult(this, resultOperation)); } } if (epilogue != null) { result.Add(epilogue); } result.Add(AstUtils.Empty()); return(result); } }
internal MSA.Expression /*!*/ MakeHashOpCall(IEnumerable <MSA.Expression> /*!*/ expressions) { return(Methods.MakeHash.OpCall(CurrentScopeVariable, AstUtils.NewArrayHelper(typeof(object), expressions))); }
private DynamicMetaObject /*!*/ MakeConvertRuleForCall(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, string name, string returner, Func <DynamicMetaObject> fallback, Func <Expression, Expression> resultConverter) { PythonType pt = ((IPythonObject)self.Value).PythonType; PythonTypeSlot pts; CodeContext context = PythonContext.GetPythonContext(convertToAction).SharedContext; ValidationInfo valInfo = BindingHelpers.GetValidationInfo(this, pt); if (pt.TryResolveSlot(context, name, out pts) && !IsBuiltinConversion(context, pts, name, pt)) { ParameterExpression tmp = Ast.Variable(typeof(object), "func"); Expression callExpr = resultConverter( Ast.Call( PythonOps.GetConversionHelper(returner, GetResultKind(convertToAction)), Ast.Dynamic( PythonContext.GetPythonContext(convertToAction).InvokeNone, typeof(object), PythonContext.GetCodeContext(convertToAction), tmp ) ) ); if (typeof(Extensible <>).MakeGenericType(toType).IsAssignableFrom(self.GetLimitType())) { // if we're doing a conversion to the underlying type and we're an // Extensible<T> of that type: // if an extensible type returns it's self in a conversion, then we need // to actually return the underlying value. If an extensible just keeps // returning more instances of it's self a stack overflow occurs - both // behaviors match CPython. callExpr = AstUtils.Convert(AddExtensibleSelfCheck(convertToAction, toType, self, callExpr), typeof(object)); } return(BindingHelpers.AddDynamicTestAndDefer( convertToAction, new DynamicMetaObject( Ast.Condition( MakeTryGetTypeMember( PythonContext.GetPythonContext(convertToAction), pts, self.Expression, tmp ), callExpr, AstUtils.Convert( ConversionFallback(convertToAction), typeof(object) ) ), self.Restrict(self.GetRuntimeType()).Restrictions ), new DynamicMetaObject[] { this }, valInfo, tmp )); } return(fallback()); }
internal override MSA.Expression /*!*/ MakeDefinitionExpression(AstGenerator /*!*/ gen) { MSA.Expression transformedQualifier; MSA.Expression name = QualifiedName.TransformName(gen); MSA.Expression transformedSuper = (_superClass != null) ? AstUtils.Box(_superClass.TransformRead(gen)) : AstUtils.Constant(null); switch (QualifiedName.TransformQualifier(gen, out transformedQualifier)) { case StaticScopeKind.Global: return(Methods.DefineGlobalClass.OpCall(gen.CurrentScopeVariable, name, transformedSuper)); case StaticScopeKind.EnclosingModule: return(Methods.DefineNestedClass.OpCall(gen.CurrentScopeVariable, name, transformedSuper)); case StaticScopeKind.Explicit: return(Methods.DefineClass.OpCall(gen.CurrentScopeVariable, transformedQualifier, name, transformedSuper)); } throw Assert.Unreachable; }
internal static Expression AddPythonBoxing(Expression res) { return(AstUtils.Convert(res, typeof(object))); }
internal static DynamicMetaObject TranslateArguments(DynamicMetaObjectBinder call, Expression codeContext, DynamicMetaObject function, DynamicMetaObject /*!*/[] args, bool hasSelf, string name) { if (hasSelf) { args = ArrayUtils.RemoveFirst(args); } CallSignature sig = BindingHelpers.GetCallSignature(call); if (sig.HasDictionaryArgument()) { int index = sig.IndexOf(ArgumentType.Dictionary); DynamicMetaObject dict = args[index]; if (!(dict.Value is IDictionary) && dict.Value != null) { // The DefaultBinder only handles types that implement IDictionary. Here we have an // arbitrary user-defined mapping type. We'll convert it into a PythonDictionary // and then have an embedded dynamic site pass that dictionary through to the default // binder. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args); dynamicArgs[index + 1] = new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.UserMappingToPythonDictionary)), codeContext, args[index].Expression, AstUtils.Constant(name) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType()), PythonOps.UserMappingToPythonDictionary(PythonContext.GetPythonContext(call).SharedContext, dict.Value, name) ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return(new DynamicMetaObject( DynamicExpression.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), BindingRestrictions.Combine(dynamicArgs).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(dict.Expression, dict.GetLimitType())) )); } } if (sig.HasListArgument()) { int index = sig.IndexOf(ArgumentType.List); DynamicMetaObject list = args[index]; if (!(list.Value is IList <object>) && list.Value != null) { // The DefaultBinder only handles types that implement IList<object>. Here we have a // arbitrary user-defined sequence type. We'll convert it into a tuple and then have // an embedded dynamic site pass that tuple through to the default binder. DynamicMetaObject[] dynamicArgs = ArrayUtils.Insert(function, args); dynamicArgs[index + 1] = new DynamicMetaObject( Expression.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.UserMappingToPythonTuple)), codeContext, args[index].Expression, AstUtils.Constant(name) ), BindingRestrictions.Empty ); if (call is IPythonSite) { dynamicArgs = ArrayUtils.Insert( new DynamicMetaObject(codeContext, BindingRestrictions.Empty), dynamicArgs ); } return(new DynamicMetaObject( DynamicExpression.Dynamic( call, typeof(object), DynamicUtils.GetExpressions(dynamicArgs) ), function.Restrictions.Merge( BindingRestrictions.Combine(args).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(list.Expression, list.GetLimitType())) ) )); } } return(null); }
private DynamicMetaObject /*!*/ MakeGetMember(DynamicMetaObjectBinder /*!*/ member, DynamicMetaObject codeContext) { PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass GetMember"); PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass GetMember"); DynamicMetaObject self = Restrict(typeof(OldClass)); Expression target; string memberName = GetGetMemberName(member); switch (memberName) { case "__dict__": target = Ast.Block( Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldClassDictionaryIsPublic)), self.Expression ), Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldClassGetDictionary)), self.Expression ) ); break; case "__bases__": target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldClassGetBaseClasses)), self.Expression ); break; case "__name__": target = Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldClassGetName)), self.Expression ); break; default: ParameterExpression tmp = Ast.Variable(typeof(object), "lookupVal"); return(new DynamicMetaObject( Ast.Block( new ParameterExpression[] { tmp }, Ast.Condition( Expression.Not( Expression.TypeIs( Expression.Assign( tmp, Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.OldClassTryLookupValue)), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(memberName) ) ), typeof(OperationFailed) ) ), tmp, AstUtils.Convert( GetMemberFallback(this, member, codeContext).Expression, typeof(object) ) ) ), self.Restrictions )); } return(new DynamicMetaObject( target, self.Restrictions )); }
protected override Expression VisitGoto(GotoExpression node) { BranchLabel label; var target = node.Target; var value = Visit(node.Value); // TODO: Is it possible for an inner reducible node of the loop to rely on nodes produced by reducing outer reducible nodes? // Unknown label => must be within the loop: if (!_labelMapping.TryGetValue(target, out label)) { return(node.Update(target, value)); } // Known label within the loop: if (label.TargetIndex >= _loopStartInstructionIndex && label.TargetIndex < _loopEndInstructionIndex) { return(node.Update(target, value)); } return(Expression.Return(_returnLabel, (value != null) ? Expression.Call(_frameVar, InterpretedFrame.GotoMethod, Expression.Constant(label.LabelIndex), AstUtils.Box(value)) : Expression.Call(_frameVar, InterpretedFrame.VoidGotoMethod, Expression.Constant(label.LabelIndex)), node.Type )); }
public override DynamicMetaObject /*!*/ BindInvoke(InvokeBinder /*!*/ call, params DynamicMetaObject /*!*/[] /*!*/ args) { return(MakeCallRule(call, AstUtils.Constant(PythonContext.GetPythonContext(call).SharedContext), args)); }
internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion) { Type type = Type; DynamicMetaObject res = null; switch (type.GetTypeCode()) { case TypeCode.Boolean: res = MakeToBoolConversion(self); break; case TypeCode.Char: res = TryToCharConversion(self); break; case TypeCode.String: var limitType = self.GetLimitType(); if ((limitType == typeof(Bytes) || limitType == typeof(PythonBuffer) || limitType == typeof(ByteArray)) && !_context.PythonOptions.Python30) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeString"), AstUtils.Convert(self.Expression, typeof(IList <byte>)) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, limitType) ); } break; case TypeCode.Object: // !!! Deferral? if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1) { res = MakeToArrayConversion(self, type); } else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value))) { Type genTo = type.GetGenericTypeDefinition(); // Interface conversion helpers... if (genTo == typeof(IList <>)) { if (self.LimitType == typeof(string)) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeByteArray"), AstUtils.Convert(self.Expression, typeof(string)) ), BindingRestrictions.GetTypeRestriction( self.Expression, typeof(string) ) ); } else { res = TryToGenericInterfaceConversion(self, type, typeof(IList <object>), typeof(ListGenericWrapper <>)); } } else if (genTo == typeof(IDictionary <,>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>)); } else if (genTo == typeof(IEnumerable <>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>)); } } else if (type == typeof(IEnumerable)) { if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType())) { res = ConvertToIEnumerable(this, self.Restrict(self.GetLimitType())); } } else if (type == typeof(IEnumerator)) { if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) && !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType())) { res = ConvertToIEnumerator(this, self.Restrict(self.GetLimitType())); } } break; } if (type.IsEnum() && Enum.GetUnderlyingType(type) == self.GetLimitType()) { // numeric type to enum, this is ok if the value is zero object value = Activator.CreateInstance(type); return(new DynamicMetaObject( Ast.Condition( Ast.Equal( AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)), AstUtils.Constant(Activator.CreateInstance(self.GetLimitType())) ), AstUtils.Constant(value), Ast.Call( typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type), AstUtils.Convert(self.Expression, typeof(object)) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())), value )); } return(res ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion))); }
public override DynamicMetaObject /*!*/ BindCreateInstance(CreateInstanceBinder /*!*/ create, params DynamicMetaObject /*!*/[] /*!*/ args) { return(MakeCallRule(create, AstUtils.Constant(PythonContext.GetPythonContext(create).SharedContext), args)); }
public override DynamicMetaObject GetValue(OverloadResolverFactory factory, ActionBinder binder, Type instanceType) { return(GetBoundValue(factory, binder, instanceType, new DynamicMetaObject(AstUtils.Constant(null), BindingRestrictions.Empty))); }
protected virtual void _Generate(AstNodeStmSwitch Switch) { var allCaseValues = Switch.Cases.Select(Case => Case.CaseValue); var caseValues = allCaseValues as IList <object> ?? allCaseValues.ToList(); if (caseValues.Count != caseValues.Distinct().Count()) { throw new Exception("Repeated case in switch!"); } // Check types and unique values. var endCasesLabel = AstLabel.CreateLabel("EndCasesLabel"); var defaultLabel = AstLabel.CreateLabel("DefaultLabel"); if (Switch.Cases.Length > 0) { var commonType = Switch.Cases.First().CaseValue.GetType(); if (Switch.Cases.Any(Case => Case.CaseValue.GetType() != commonType)) { throw new Exception("All cases should have the same type"); } var doneSpecialized = false; // Specialized constant-time integer switch (if possible) if (AstUtils.IsIntegerType(commonType)) { var commonMin = Switch.Cases.Min(Case => AstUtils.CastType <long>(Case.CaseValue)); var commonMax = Switch.Cases.Max(Case => AstUtils.CastType <long>(Case.CaseValue)); var casesLength = commonMax - commonMin + 1; // No processing tables greater than 4096 elements. if (casesLength <= 4096) { var labels = new AstLabel[casesLength]; for (var n = 0; n < casesLength; n++) { labels[n] = defaultLabel; } foreach (var Case in Switch.Cases) { var realValue = AstUtils.CastType <long>(Case.CaseValue); var offset = realValue - commonMin; labels[offset] = AstLabel.CreateLabel("Case_" + realValue); } /* * //var SwitchVarLocal = AstLocal.Create(AllCaseValues.First().GetType(), "SwitchVarLocal" + SwitchVarCount++); * //Generate(new AstNodeStmAssign(new AstNodeExprLocal(SwitchVarLocal), Switch.SwitchValue - new AstNodeExprCast(CommonType, CommonMin))); * //Generate(new AstNodeStmIfElse(new AstNodeExprBinop(new AstNodeExprLocal(SwitchVarLocal), "<", 0), new AstNodeStmGotoAlways(DefaultLabel))); * //Generate(new AstNodeStmIfElse(new AstNodeExprBinop(new AstNodeExprLocal(SwitchVarLocal), ">=", CasesLength), new AstNodeStmGotoAlways(DefaultLabel))); * //Generate(new AstNodeExprLocal(SwitchVarLocal)); */ Generate(Switch.SwitchValue - new AstNodeExprCast(commonType, commonMin)); Emit(OpCodes.Switch, labels); Generate(new AstNodeStmGotoAlways(defaultLabel)); foreach (var Case in Switch.Cases) { var realValue = AstUtils.CastType <long>(Case.CaseValue); var offset = realValue - commonMin; Generate(new AstNodeStmLabel(labels[offset])); { Generate(Case.Code); } Generate(new AstNodeStmGotoAlways(endCasesLabel)); } doneSpecialized = true; } else { // TODO: find a common shift and masks for all the values to reduce CasesLength. // TODO: On too large test cases, split them recursively in: // if (Var < Half) { switch(Var - LowerPartMin) { ... } } else { switch(Var - Half - UpperPartMin) { ... } } } } // Specialized switch for strings (checking length, then hash, then contents) else if (commonType == typeof(string)) { // TODO! } // Generic if/else if (!doneSpecialized) { var switchVarLocal = AstLocal.Create(caseValues.First().GetType(), "SwitchVarLocal" + _switchVarCount++); Generate(new AstNodeStmAssign(new AstNodeExprLocal(switchVarLocal), Switch.SwitchValue)); //Switch.Cases foreach (var Case in Switch.Cases) { var labelSkipThisCase = AstLabel.CreateLabel("LabelCase" + Case.CaseValue); Generate(new AstNodeStmGotoIfFalse(labelSkipThisCase, new AstNodeExprBinop(new AstNodeExprLocal(switchVarLocal), "==", new AstNodeExprImm(Case.CaseValue)))); Generate(Case.Code); Generate(new AstNodeStmGotoAlways(endCasesLabel)); Generate(new AstNodeStmLabel(labelSkipThisCase)); } } } Generate(new AstNodeStmLabel(defaultLabel)); if (Switch.CaseDefault != null) { Generate(Switch.CaseDefault.Code); } Generate(new AstNodeStmLabel(endCasesLabel)); }
public override DynamicMetaObject SetValue(OverloadResolverFactory resolverFactory, ActionBinder binder, Type type, DynamicMetaObject value) { return(SetBoundValue(resolverFactory, binder, type, value, new DynamicMetaObject(AstUtils.Constant(null), BindingRestrictions.Empty))); }
protected virtual void _Generate(AstNodeExprImm item) { var itemType = AstUtils.GetSignedType(item.Type); var itemValue = item.Value; if (itemType.IsEnum) { itemType = itemType.GetEnumUnderlyingType(); itemValue = AstUtils.CastType(itemValue, itemType); } if ( itemType == typeof(int) || itemType == typeof(sbyte) || itemType == typeof(short) || itemType == typeof(bool) ) { var value = (int)Convert.ToInt64(itemValue); switch (value) { case -1: Emit(OpCodes.Ldc_I4_M1); break; case 0: Emit(OpCodes.Ldc_I4_0); break; case 1: Emit(OpCodes.Ldc_I4_1); break; case 2: Emit(OpCodes.Ldc_I4_2); break; case 3: Emit(OpCodes.Ldc_I4_3); break; case 4: Emit(OpCodes.Ldc_I4_4); break; case 5: Emit(OpCodes.Ldc_I4_5); break; case 6: Emit(OpCodes.Ldc_I4_6); break; case 7: Emit(OpCodes.Ldc_I4_7); break; case 8: Emit(OpCodes.Ldc_I4_8); break; default: Emit(OpCodes.Ldc_I4, value); break; } } else if (itemType == typeof(long) || itemType == typeof(ulong)) { Emit(OpCodes.Ldc_I8, Convert.ToInt64(itemValue)); } else if (itemType == typeof(IntPtr)) { #if false Emit(OpCodes.Ldc_I8, ((IntPtr)Item.Value).ToInt64()); Emit(OpCodes.Conv_I); #else if (Environment.Is64BitProcess) { Emit(OpCodes.Ldc_I8, ((IntPtr)item.Value).ToInt64()); Emit(OpCodes.Conv_I); } else { Emit(OpCodes.Ldc_I4, ((IntPtr)item.Value).ToInt32()); Emit(OpCodes.Conv_I); } #endif } else if (itemType == typeof(float)) { Emit(OpCodes.Ldc_R4, (float)item.Value); } else if (item.Value == null) { Emit(OpCodes.Ldnull); } else if (itemType == typeof(string)) { Emit(OpCodes.Ldstr, (string)item.Value); } else if (itemType == typeof(Type)) { Emit(OpCodes.Ldtoken, (Type)item.Value); Emit(OpCodes.Call, ((Func <RuntimeTypeHandle, Type>)Type.GetTypeFromHandle).Method); //IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) } else { throw new NotImplementedException($"Can't handle immediate type {itemType}"); } }
private DynamicMetaObject /*!*/ MakeSelflessCall(DynamicMetaObjectBinder /*!*/ call, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] /*!*/ args) { // just check if it's the same built-in function. Because built-in functions are // immutable the identity check will suffice. Because built-in functions are uncollectible // anyway we don't use the typical InstanceRestriction. BindingRestrictions selfRestrict = BindingRestrictions.GetExpressionRestriction(Ast.Equal(Expression, AstUtils.Constant(Value))).Merge(Restrictions); return(Value.MakeBuiltinFunctionCall( call, codeContext, this, args, false, // no self selfRestrict, (newArgs) => { BindingTarget target; var binder = PythonContext.GetPythonContext(call).Binder; DynamicMetaObject res = binder.CallMethod( new PythonOverloadResolver( binder, newArgs, BindingHelpers.GetCallSignature(call), codeContext ), Value.Targets, selfRestrict, Value.Name, PythonNarrowing.None, Value.IsBinaryOperator ? PythonNarrowing.BinaryOperator : NarrowingLevel.All, out target ); return BindingHelpers.CheckLightThrow(call, res, target); } )); }
// @TODO: Rewrite using C# 7 features protected virtual void _Generate(AstNodeStmAssign assign) { //Assign.Local.LocalBuilder.LocalIndex var astNodeExprLocal = assign.LeftValue as AstNodeExprLocal; var astNodeExprArgument = assign.LeftValue as AstNodeExprArgument; var astNodeExprFieldAccess = assign.LeftValue as AstNodeExprFieldAccess; var astNodeExprStaticFieldAccess = assign.LeftValue as AstNodeExprStaticFieldAccess; var astNodeExprIndirect = assign.LeftValue as AstNodeExprIndirect; var astNodeExprArrayAccess = assign.LeftValue as AstNodeExprArrayAccess; var astNodeExprPropertyAccess = assign.LeftValue as AstNodeExprPropertyAccess; var astNodeExprSetGetLValue = assign.LeftValue as AstNodeExprSetGetLValue; if (astNodeExprLocal != null) { Generate(assign.Value); Emit(OpCodes.Stloc, _GetLocalBuilderFromAstLocal(astNodeExprLocal.AstLocal)); } else if (astNodeExprArgument != null) { Generate(assign.Value); Emit(OpCodes.Starg, astNodeExprArgument.AstArgument.Index); } else if (astNodeExprFieldAccess != null) { Generate(astNodeExprFieldAccess.Instance); Generate(assign.Value); Emit(OpCodes.Stfld, astNodeExprFieldAccess.Field); } else if (astNodeExprStaticFieldAccess != null) { Generate(assign.Value); Emit(OpCodes.Stsfld, astNodeExprStaticFieldAccess.Field); } else if (astNodeExprArrayAccess != null) { Generate(astNodeExprArrayAccess.ArrayInstance); Generate(astNodeExprArrayAccess.Index); Generate(assign.Value); Emit(OpCodes.Stelem, astNodeExprArrayAccess.ArrayInstance.Type.GetElementType()); } else if (astNodeExprIndirect != null) { var pointerType = AstUtils.GetSignedType(astNodeExprIndirect.PointerExpression.Type.GetElementType()); Generate(astNodeExprIndirect.PointerExpression); Generate(assign.Value); if (pointerType == typeof(sbyte)) { Emit(OpCodes.Stind_I1); } else if (pointerType == typeof(short)) { Emit(OpCodes.Stind_I2); } else if (pointerType == typeof(int)) { Emit(OpCodes.Stind_I4); } else if (pointerType == typeof(long)) { Emit(OpCodes.Stind_I8); } else if (pointerType == typeof(float)) { Emit(OpCodes.Stind_R4); } else if (pointerType == typeof(double)) { Emit(OpCodes.Stind_R8); } else if (pointerType == typeof(bool)) { Emit(OpCodes.Stind_I1); } else { throw new NotImplementedException("Can't store indirect value"); } } else if (astNodeExprPropertyAccess != null) { Generate(astNodeExprPropertyAccess.Instance); Generate(assign.Value); Emit(OpCodes.Callvirt, astNodeExprPropertyAccess.Property.SetMethod); } else if (astNodeExprSetGetLValue != null) { _placeholderStack.Push(assign.Value); Generate(astNodeExprSetGetLValue.SetExpression); if (astNodeExprSetGetLValue.SetExpression.Type != typeof(void)) { Emit(OpCodes.Pop); } } else { throw new NotImplementedException("Not implemented AstNodeStmAssign LValue: " + assign.LeftValue.GetType()); } //Assign.Local }
private DynamicMetaObject /*!*/ GetInstance(Expression /*!*/ instance, Type /*!*/ testType) { Assert.NotNull(instance, testType); object instanceValue = Value.BindingSelf; BindingRestrictions restrictions = BindingRestrictionsHelpers.GetRuntimeTypeRestriction(instance, testType); // cast the instance to the correct type if (CompilerHelpers.IsStrongBox(instanceValue)) { instance = ReadStrongBoxValue(instance); instanceValue = ((IStrongBox)instanceValue).Value; } else if (!testType.IsEnum()) { // We need to deal w/ wierd types like MarshalByRefObject. // We could have an MBRO whos DeclaringType is completely different. // Therefore we special case it here and cast to the declaring type Type selfType = CompilerHelpers.GetType(Value.BindingSelf); selfType = CompilerHelpers.GetVisibleType(selfType); if (selfType == typeof(object) && Value.DeclaringType.IsInterface()) { selfType = Value.DeclaringType; Type genericTypeDefinition = null; // the behavior is different on Mono, it sets FullName for the DeclaringType if (Value.DeclaringType.IsGenericType() && (ClrModule.IsMono || Value.DeclaringType.FullName == null) && Value.DeclaringType.ContainsGenericParameters() && !Value.DeclaringType.IsGenericTypeDefinition()) { // from MSDN: If the current type contains generic type parameters that have not been replaced by // specific types (that is, the ContainsGenericParameters property returns true), but the type // is not a generic type definition (that is, the IsGenericTypeDefinition property returns false), // this property returns Nothing. For example, consider the classes Base and Derived in the following code. // if this type is completely generic (no type arguments specified) then we'll go ahead and get the // generic type definition for the this parameter - that'll let us successfully type infer on it later. var genericArgs = Value.DeclaringType.GetGenericArguments(); bool hasOnlyGenerics = genericArgs.Length > 0; foreach (var genericParam in genericArgs) { if (!genericParam.IsGenericParameter) { hasOnlyGenerics = false; break; } } if (hasOnlyGenerics) { genericTypeDefinition = Value.DeclaringType.GetGenericTypeDefinition(); } } else if (Value.DeclaringType.IsGenericTypeDefinition()) { genericTypeDefinition = Value.DeclaringType; } if (genericTypeDefinition != null) { // we're a generic interface method on a non-public type. // We need to see if we can match any types implemented on // the concrete selfType. var interfaces = CompilerHelpers.GetType(Value.BindingSelf).GetInterfaces(); foreach (var iface in interfaces) { if (iface.IsGenericType() && iface.GetGenericTypeDefinition() == genericTypeDefinition) { selfType = iface; break; } } } } if (Value.DeclaringType.IsInterface() && selfType.IsValueType()) { // explicit interface implementation dispatch on a value type, don't // unbox the value type before the dispatch. instance = AstUtils.Convert(instance, Value.DeclaringType); } else if (selfType.IsValueType()) { // We might be calling a a mutating method (like // Rectangle.Intersect). If so, we want it to mutate // the boxed value directly instance = Ast.Unbox(instance, selfType); } else { #if FEATURE_REMOTING Type convType = selfType == typeof(MarshalByRefObject) ? CompilerHelpers.GetVisibleType(Value.DeclaringType) : selfType; instance = AstUtils.Convert(instance, convType); #else instance = AstUtils.Convert(instance, selfType); #endif } } else { // we don't want to cast the enum to its real type, it will unbox it // and turn it into its underlying type. We presumably want to call // a method on the Enum class though - so we cast to Enum instead. instance = AstUtils.Convert(instance, typeof(Enum)); } return(new DynamicMetaObject( instance, restrictions, instanceValue )); }
protected virtual void _Generate(AstNodeExprBinop item) { var leftType = item.LeftNode.Type; //var rightType = item.RightNode.Type; //if (LeftType != RightType) throw(new Exception(String.Format("BinaryOp Type mismatch ({0}) != ({1})", LeftType, RightType))); //Item.GetType().GenericTypeArguments[0] Generate(item.LeftNode); Generate(item.RightNode); //switch (Item.Operator) //{ // case "||": // case "&&": // if (LeftType != typeof(bool) || RightType != typeof(bool)) // { // throw(new InvalidOperationException(String.Format("Operator '{0}' requires boolean types but found {1}, {2}", Item.Operator, LeftType, RightType))); // } // break; //} switch (item.Operator) { case "+": Emit(OpCodes.Add); break; case "-": Emit(OpCodes.Sub); break; case "*": Emit(OpCodes.Mul); break; case "/": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Div : OpCodes.Div_Un); break; case "%": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Rem : OpCodes.Rem_Un); break; case "==": Emit(OpCodes.Ceq); break; case "!=": Emit(OpCodes.Ceq); Emit(OpCodes.Ldc_I4_0); Emit(OpCodes.Ceq); break; case "<": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Clt : OpCodes.Clt_Un); break; case ">": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Cgt : OpCodes.Cgt_Un); break; case "<=": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Cgt : OpCodes.Cgt_Un); Emit(OpCodes.Ldc_I4_0); Emit(OpCodes.Ceq); break; case ">=": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Clt : OpCodes.Clt_Un); Emit(OpCodes.Ldc_I4_0); Emit(OpCodes.Ceq); break; case "&": case "&&": Emit(OpCodes.And); break; case "|": case "||": Emit(OpCodes.Or); break; case "^": Emit(OpCodes.Xor); break; case "<<": Emit(OpCodes.Shl); break; case ">>": Emit(AstUtils.IsTypeSigned(leftType) ? OpCodes.Shr : OpCodes.Shr_Un); break; default: throw new NotImplementedException($"Not implemented operator '{item.Operator}'"); } }
// see Ruby Language.doc/Runtime/Control Flow Implementation/Return internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen) { MSA.Expression transformedReturnValue = TransformReturnValue(gen); // eval: if (gen.CompilerOptions.IsEval) { return(gen.Return(Methods.EvalReturn.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)))); } // block: if (gen.CurrentBlock != null) { return(gen.Return(Methods.BlockReturn.OpCall(gen.CurrentBlock.BfcVariable, AstUtils.Box(transformedReturnValue)))); } // method: return(gen.Return(transformedReturnValue)); }
private DynamicMetaObject /*!*/ MakeSetMember(SetMemberBinder /*!*/ member, DynamicMetaObject /*!*/ value) { PythonContext state = PythonContext.GetPythonContext(member); DynamicMetaObject self = Restrict(Value.GetType()); if (Value.GetType() != typeof(PythonType) && DynamicHelpers.GetPythonType(Value).IsSystemType) { // built-in subclass of .NET type. Usually __setattr__ is handled by MetaUserObject // but we can have a built-in subtype that's not a user type. PythonTypeSlot pts; if (Value.TryGetCustomSetAttr(state.SharedContext, out pts)) { Debug.Assert(pts.GetAlwaysSucceeds); ParameterExpression tmp = Ast.Variable(typeof(object), "boundVal"); return(BindingHelpers.AddDynamicTestAndDefer( member, new DynamicMetaObject( Ast.Block( new[] { tmp }, DynamicExpression.Dynamic( state.Invoke(new CallSignature(2)), typeof(object), AstUtils.Constant(state.SharedContext), Ast.Block( Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.SlotTryGetValue)), AstUtils.Constant(state.SharedContext), AstUtils.Convert(AstUtils.WeakConstant(pts), typeof(PythonTypeSlot)), AstUtils.Convert(Expression, typeof(object)), AstUtils.Convert(AstUtils.WeakConstant(DynamicHelpers.GetPythonType(Value)), typeof(PythonType)), tmp ), tmp ), Ast.Constant(member.Name), value.Expression ) ), self.Restrictions ), new DynamicMetaObject[] { this, value }, TestUserType() )); } } return(BindingHelpers.AddDynamicTestAndDefer( member, new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("PythonTypeSetCustomMember"), AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext), self.Expression, AstUtils.Constant(member.Name), AstUtils.Convert( value.Expression, typeof(object) ) ), self.Restrictions.Merge(value.Restrictions) ), new DynamicMetaObject[] { this, value }, TestUserType() )); }