/// <summary> /// Creates a pure wrapper for function with 2 and more arguments. /// </summary> private void createPureWrapperMany(MethodEntity wrapper, string pureName) { var args = wrapper.GetArgumentTypes(Context); var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name); var tupleType = FunctionalHelper.CreateTupleType(args); var fieldType = typeof(Dictionary <,>).MakeGenericType(tupleType, wrapper.ReturnType); CreateField(fieldName, fieldType, true); var argGetters = wrapper.Arguments.Select(a => (NodeBase)Expr.Get(a)).ToArray(); var tupleName = "<args>"; wrapper.Body = Expr.Block( ScopeKind.FunctionRoot, // $tmp = new Tuple<...> $arg1 $arg2 ... Expr.Let(tupleName, Expr.New(tupleType, argGetters)), // if ($dict == null) $dict = new Dictionary<$tupleType, $valueType> () Expr.If( Expr.Equal( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Null() ), Expr.Block( Expr.SetMember( EntityNames.MainTypeName, fieldName, Expr.New(fieldType) ) ) ), // if(not $dict.ContainsKey key) $dict.Add ($internal arg) Expr.If( Expr.Not( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "ContainsKey", Expr.Get(tupleName) ) ), Expr.Block( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "Add", Expr.Get(tupleName), Expr.Invoke(EntityNames.MainTypeName, pureName, argGetters) ) ) ), // $dict[arg] Expr.GetIdx( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Get(tupleName) ) ); }
/// <summary> /// Creates a method without setting argument type info. /// </summary> private MethodEntity CreateMethodCore(string name, bool isStatic, bool isVirtual, bool prepare, Action <MethodEntity> extraInit = null) { var me = new MethodEntity(this) { Name = name, IsStatic = isStatic, IsVirtual = isVirtual, }; Context.UnprocessedMethods.Add(me); extraInit?.Invoke(me); if (prepare) { me.PrepareSelf(); CheckMethod(me); } else { Context.UnpreparedTypeContents.Add(me); } return(me); }
public override void ProcessClosures(Context ctx) { if (MustInferArgTypes) { var name = Arguments.First(a => a.Type == typeof (UnspecifiedType)).Name; error(CompilerMessages.LambdaArgTypeUnknown, name); } // get evaluated return type var retType = _InferredReturnType ?? Body.Resolve(ctx); if (retType == typeof(NullType)) error(CompilerMessages.LambdaReturnTypeUnknown); if (retType.IsVoid()) retType = typeof (void); _Method = ctx.Scope.CreateClosureMethod(ctx, Arguments, retType); _Method.Body = Body; var outerMethod = ctx.CurrentMethod; ctx.CurrentMethod = _Method; _Method.Body.ProcessClosures(ctx); ctx.CurrentMethod = outerMethod; }
/// <summary> /// Creates a wrapper for the pure method that contains the value cache. /// </summary> private void CreatePureWrapper(MethodEntity method) { if (method.ReturnType.IsVoid()) { Context.Error(CompilerMessages.PureFunctionReturnUnit, method.Name); } var pureName = string.Format(EntityNames.PureMethodNameTemplate, method.Name); var pure = CreateMethod(pureName, method.ReturnTypeSignature, method.Arguments.Values, true); pure.Body = method.Body; var argCount = method.Arguments != null ? method.Arguments.Count : method.ArgumentTypes.Length; if (argCount >= 8) { Context.Error(CompilerMessages.PureFunctionTooManyArgs, method.Name); } if (argCount == 0) { CreatePureWrapper0(method, pureName); } else if (argCount == 1) { CreatePureWrapper1(method, pureName); } else { CreatePureWrapperMany(method, pureName); } }
/// <summary> /// Invokes generation of FieldBuilder, MethodBuilder and ConstructorBuilder objects for type members. /// </summary> public void CheckMethod(MethodEntity method) { try { // exception is good ResolveMethod(method.Name, method.GetArgumentTypes(Context), true); if (this == Context.MainType) { Context.Error(CompilerMessages.FunctionRedefinition, method.Name); } else { Context.Error(CompilerMessages.MethodRedefinition, method.Name, Name); } } catch (KeyNotFoundException) { if (!_methods.ContainsKey(method.Name)) { _methods.Add(method.Name, new List <MethodEntity> { method }); } else { _methods[method.Name].Add(method); } } }
/// <summary> /// Creates a pure wrapper for parameterless function. /// </summary> private void CreatePureWrapper0(MethodEntity wrapper, string pureName) { var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name); var flagName = string.Format(EntityNames.PureMethodCacheFlagNameTemplate, wrapper.Name); CreateField(fieldName, wrapper.ReturnTypeSignature, true); CreateField(flagName, typeof(bool), true); wrapper.Body = Expr.Block( ScopeKind.FunctionRoot, // if (not $flag) $cache = $internal (); $flag = true Expr.If( Expr.Not(Expr.GetMember(EntityNames.MainTypeName, flagName)), Expr.Block( Expr.SetMember( EntityNames.MainTypeName, fieldName, Expr.Invoke(EntityNames.MainTypeName, pureName) ), Expr.SetMember(EntityNames.MainTypeName, flagName, Expr.True()) ) ), // $cache Expr.GetMember(EntityNames.MainTypeName, fieldName) ); }
/// <summary> /// Creates a pure wrapper for function with 1 argument. /// </summary> private void CreatePureWrapper1(MethodEntity wrapper, string pureName) { var args = wrapper.GetArgumentTypes(Context); var argName = wrapper.Arguments[0].Name; var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name); var fieldType = typeof(Dictionary <,>).MakeGenericType(args[0], wrapper.ReturnType); CreateField(fieldName, fieldType, true); wrapper.Body = Expr.Block( ScopeKind.FunctionRoot, // if ($dict == null) $dict = new Dictionary<$argType, $valueType> () Expr.If( Expr.Equal( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Null() ), Expr.Block( Expr.SetMember( EntityNames.MainTypeName, fieldName, Expr.New(fieldType) ) ) ), // if(not $dict.ContainsKey key) $dict.Add ($internal arg) Expr.If( Expr.Not( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "ContainsKey", Expr.Get(argName) ) ), Expr.Block( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "Add", Expr.Get(argName), Expr.Invoke(EntityNames.MainTypeName, pureName, Expr.Get(argName)) ) ) ), // $dict[arg] Expr.GetIdx( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Get(argName) ) ); }
/// <summary> /// Invokes generation of FieldBuilder, MethodBuilder and ConstructorBuilder objects for type members. /// </summary> public void CheckMethod(MethodEntity method) { try { // exception is good ResolveMethod(method.Name, method.GetArgumentTypes(Context), true); if (this == Context.MainType) Context.Error(CompilerMessages.FunctionRedefinition, method.Name); else Context.Error(CompilerMessages.MethodRedefinition, method.Name, Name); } catch (KeyNotFoundException) { if (!_Methods.ContainsKey(method.Name)) _Methods.Add(method.Name, new List<MethodEntity> { method }); else _Methods[method.Name].Add(method); } }
/// <summary> /// Imports a new method to the given type. /// </summary> internal void ImportMethod(string name, MethodInfo mi, bool check) { if (!mi.IsStatic || !mi.IsPublic) { Context.Error(CompilerMessages.ImportUnsupportedMethod); } var args = mi.GetParameters().Select(p => new FunctionArgument(p.Name, p.ParameterType, p.ParameterType.IsByRef)); var me = new MethodEntity(this) { Name = name, IsImported = true, IsStatic = true, IsVirtual = false, IsVariadic = ReflectionHelper.IsVariadic(mi), MethodInfo = mi, ReturnType = mi.ReturnType, Arguments = new HashList <FunctionArgument>(args, arg => arg.Name) }; if (check) { CheckMethod(me); } else { if (_methods.ContainsKey(name)) { _methods[name].Add(me); } else { _methods.Add(name, new List <MethodEntity> { me }); } } }
public override void ProcessClosures(Context ctx) { _Method = ctx.CurrentScope.CreateClosureMethod(ctx, Arguments); _Method.Body = Body; var methodBackup = ctx.CurrentMethod; ctx.CurrentMethod = _Method; var scope = _Method.Scope; scope.InitializeScope(ctx); base.ProcessClosures(ctx); // get evaluated return type var retType = Body.GetExpressionType(ctx); if(retType == typeof(NullType)) Error(CompilerMessages.LambdaReturnTypeUnknown); _Method.ReturnType = retType.IsVoid() ? typeof(void) : retType; _Method.PrepareSelf(); scope.FinalizeScope(ctx); ctx.CurrentMethod = methodBackup; }
/// <summary> /// Imports a new method to the given type. /// </summary> internal void ImportMethod(string name, MethodInfo mi, bool check) { if(!mi.IsStatic || !mi.IsPublic) Context.Error(CompilerMessages.ImportUnsupportedMethod); var args = mi.GetParameters().Select(p => new FunctionArgument(p.Name, p.ParameterType, p.ParameterType.IsByRef)); var me = new MethodEntity { Name = name, IsImported = true, IsStatic = true, IsVirtual = false, ContainerType = this, MethodInfo = mi, ReturnType = mi.ReturnType, Arguments = new HashList<FunctionArgument>(args, arg => arg.Name) }; if (check) { _MethodList.Add(me); } else { if(_Methods.ContainsKey(name)) _Methods[name].Add(me); else _Methods.Add(name, new List<MethodEntity> { me }); } }
/// <summary> /// Creates a method without setting argument type info. /// </summary> private MethodEntity createMethodCore(string name, bool isStatic, bool isVirtual, bool prepare, Action<MethodEntity> extraInit = null) { var me = new MethodEntity(this) { Name = name, IsStatic = isStatic, IsVirtual = isVirtual, }; Context.UnprocessedMethods.Add(me); if (extraInit != null) extraInit(me); if (prepare) { me.PrepareSelf(); CheckMethod(me); } else { Context.UnpreparedTypeContents.Add(me); } return me; }
protected override Type resolve(Context ctx, bool mustReturn) { if(Identifier == "_") error(CompilerMessages.UnderscoreNameUsed); // local variable var local = Local ?? ctx.Scope.FindLocal(Identifier); if (local != null) { // only local constants are cached // because mutable variables could be closured later on if (local.IsConstant && local.IsImmutable && ctx.Options.UnrollConstants) _LocalConstant = local; return local.Type; } // static function declared in the script try { var methods = ctx.MainType.ResolveMethodGroup(Identifier); if (methods.Length > 1) error(CompilerMessages.FunctionInvocationAmbiguous, Identifier); _Method = methods[0]; return FunctionalHelper.CreateFuncType(_Method.ReturnType, _Method.GetArgumentTypes(ctx)); } catch (KeyNotFoundException) { } // algebraic type without a constructor var type = ctx.FindType(Identifier); if (type != null && type.Kind == TypeEntityKind.TypeLabel) { try { type.ResolveConstructor(new Type[0]); _Type = type; return _Type.TypeInfo; } catch (KeyNotFoundException) { } } // global property try { _Property = ctx.ResolveGlobalProperty(Identifier); return _Property.PropertyType; } catch (KeyNotFoundException) { error(CompilerMessages.IdentifierNotFound, Identifier); } return typeof (UnitType); }
/// <summary> /// Creates a pure wrapper for function with 2 and more arguments. /// </summary> private void createPureWrapperMany(MethodEntity wrapper, string pureName) { var args = wrapper.GetArgumentTypes(Context); var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name); var tupleType = FunctionalHelper.CreateTupleType(args); var fieldType = typeof(Dictionary<,>).MakeGenericType(tupleType, wrapper.ReturnType); CreateField(fieldName, fieldType, true); var argGetters = wrapper.Arguments.Select(a => (NodeBase)Expr.Get(a)).ToArray(); var tupleName = "<args>"; wrapper.Body = Expr.Block( ScopeKind.FunctionRoot, // $tmp = new Tuple<...> $arg1 $arg2 ... Expr.Let(tupleName, Expr.New(tupleType, argGetters)), // if ($dict == null) $dict = new Dictionary<$tupleType, $valueType> () Expr.If( Expr.Equal( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Null() ), Expr.Block( Expr.SetMember( EntityNames.MainTypeName, fieldName, Expr.New(fieldType) ) ) ), // if(not $dict.ContainsKey key) $dict.Add ($internal arg) Expr.If( Expr.Not( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "ContainsKey", Expr.Get(tupleName) ) ), Expr.Block( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "Add", Expr.Get(tupleName), Expr.Invoke(EntityNames.MainTypeName, pureName, argGetters) ) ) ), // $dict[arg] Expr.GetIdx( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Get(tupleName) ) ); }
/// <summary> /// Creates a pure wrapper for function with 1 argument. /// </summary> private void createPureWrapper1(MethodEntity wrapper, string pureName) { var args = wrapper.GetArgumentTypes(Context); var argName = wrapper.Arguments[0].Name; var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name); var fieldType = typeof(Dictionary<,>).MakeGenericType(args[0], wrapper.ReturnType); CreateField(fieldName, fieldType, true); wrapper.Body = Expr.Block( ScopeKind.FunctionRoot, // if ($dict == null) $dict = new Dictionary<$argType, $valueType> () Expr.If( Expr.Equal( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Null() ), Expr.Block( Expr.SetMember( EntityNames.MainTypeName, fieldName, Expr.New(fieldType) ) ) ), // if(not $dict.ContainsKey key) $dict.Add ($internal arg) Expr.If( Expr.Not( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "ContainsKey", Expr.Get(argName) ) ), Expr.Block( Expr.Invoke( Expr.GetMember(EntityNames.MainTypeName, fieldName), "Add", Expr.Get(argName), Expr.Invoke(EntityNames.MainTypeName, pureName, Expr.Get(argName)) ) ) ), // $dict[arg] Expr.GetIdx( Expr.GetMember(EntityNames.MainTypeName, fieldName), Expr.Get(argName) ) ); }
/// <summary> /// Creates a wrapper for the pure method that contains the value cache. /// </summary> private void createPureWrapper(MethodEntity method) { if (method.ReturnType.IsVoid()) Context.Error(CompilerMessages.PureFunctionReturnUnit, method.Name); var pureName = string.Format(EntityNames.PureMethodNameTemplate, method.Name); var pure = CreateMethod(pureName, method.ReturnTypeSignature, method.Arguments.Values, true); pure.Body = method.Body; var argCount = method.Arguments != null ? method.Arguments.Count : method.ArgumentTypes.Length; if (argCount >= 8) Context.Error(CompilerMessages.PureFunctionTooManyArgs, method.Name); if (argCount == 0) createPureWrapper0(method, pureName); else if (argCount == 1) createPureWrapper1(method, pureName); else createPureWrapperMany(method, pureName); }
protected override Type resolveExpressionType(Context ctx, bool mustReturn = true) { var local = LocalName ?? ctx.CurrentScope.FindName(Identifier); if (local != null) { // only local constants are cached // because mutable variables could be closured later on if (local.IsConstant && local.IsImmutable && ctx.Options.UnrollConstants) m_LocalConstant = local; return local.Type; } try { var methods = ctx.MainType.ResolveMethodGroup(Identifier); if (methods.Length > 1) Error(CompilerMessages.FunctionInvocationAmbiguous, Identifier); m_Method = methods[0]; return FunctionalHelper.CreateFuncType(m_Method.ReturnType, m_Method.GetArgumentTypes(ctx)); } catch (KeyNotFoundException) { } try { m_Property = ctx.ResolveGlobalProperty(Identifier); return m_Property.PropertyType; } catch (KeyNotFoundException) { Error(CompilerMessages.IdentifierNotFound, Identifier); } return typeof (Unit); }
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; } }
/// <summary> /// Creates a method without setting argument type info. /// </summary> private MethodEntity createMethodCore(string name, bool isStatic, bool isVirtual, bool prepare) { var me = new MethodEntity { Name = name, IsStatic = isStatic, IsVirtual = isVirtual, ContainerType = this, }; _MethodList.Add(me); if(prepare) me.PrepareSelf(); return me; }
/// <summary> /// Creates a wrapper from a method entity. /// </summary> private MethodWrapper wrapMethod(MethodEntity method, bool isPartial = false) { return new MethodWrapper { Name = method.Name, Type = method.ContainerType.TypeInfo, IsStatic = method.IsStatic, IsVirtual = method.IsVirtual, IsPartiallyApplied = isPartial, IsVariadic = method.IsVariadic, MethodInfo = method.MethodInfo, ArgumentTypes = method.GetArgumentTypes(this), ReturnType = method.ReturnType }; }
/// <summary> /// Creates a pure wrapper for parameterless function. /// </summary> private void createPureWrapper0(MethodEntity wrapper, string pureName) { var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name); var flagName = string.Format(EntityNames.PureMethodCacheFlagNameTemplate, wrapper.Name); CreateField(fieldName, wrapper.ReturnTypeSignature, true); CreateField(flagName, typeof(bool), true); wrapper.Body = Expr.Block( ScopeKind.FunctionRoot, // if (not $flag) $cache = $internal (); $flag = true Expr.If( Expr.Not(Expr.GetMember(EntityNames.MainTypeName, flagName)), Expr.Block( Expr.SetMember( EntityNames.MainTypeName, fieldName, Expr.Invoke(EntityNames.MainTypeName, pureName) ), Expr.SetMember(EntityNames.MainTypeName, flagName, Expr.True()) ) ), // $cache Expr.GetMember(EntityNames.MainTypeName, fieldName) ); }