public CompiledKontrolConstant(string name, string description, TO2Type type, FieldInfo runtimeField)
 {
     Name         = name;
     Description  = description;
     Type         = type;
     RuntimeField = runtimeField;
 }
Beispiel #2
0
        public static CompiledKontrolConstant BindConstant(Type type, string fieldName, string description)
        {
            string    name      = BindingGenerator.ToSnakeCase(fieldName).ToUpperInvariant();
            FieldInfo fieldInfo = type.GetField(fieldName);
            TO2Type   to2Type   = BindingGenerator.MapNativeType(fieldInfo.FieldType);

            return(new CompiledKontrolConstant(name, description, to2Type, fieldInfo));
        }
Beispiel #3
0
        static MethodInfo GenerateMethod(Expression expression, TO2Type returnType)
        {
            Context       context       = new Context(KontrolRegistry.CreateCore());
            ModuleContext moduleContext = context.CreateModuleContext("DynamicExpression");
            IBlockContext methodContext = moduleContext.CreateMethodContext(FunctionModifier.Public, false, "Exec",
                                                                            returnType, Enumerable.Empty <FunctionParameter>());

            expression.EmitCode(methodContext, false);
            Assert.False(methodContext.HasErrors);
            methodContext.IL.EmitReturn(methodContext.MethodBuilder.ReturnType);

            Type dynamicType = moduleContext.CreateType();

            return(dynamicType.GetMethod("Exec"));
        }
        public static IDefaultValue ForParameter(IBlockContext context, FunctionParameter parameter)
        {
            if (parameter.defaultValue == null)
            {
                return(null);
            }
            switch (parameter.defaultValue)
            {
            case LiteralBool b when parameter.type == BuiltinType.Bool: return(new BoolDefaultValue(b.value));

            case LiteralInt i when parameter.type == BuiltinType.Int: return(new IntDefaultValue(i.value));

            case LiteralInt i when parameter.type == BuiltinType.Float: return(new FloatDefaultValue(i.value));

            case LiteralFloat f when parameter.type == BuiltinType.Float: return(new FloatDefaultValue(f.value));

            case LiteralString s when parameter.type == BuiltinType.String: return(new StringDefaultValue(s.value));

            default:
                IBlockContext defaultContext = new SyncBlockContext(context.ModuleContext, FunctionModifier.Public,
                                                                    false, $"default_{context.MethodBuilder.Name}_{parameter.name}", parameter.type,
                                                                    new List <FunctionParameter>());
                TO2Type resultType = parameter.defaultValue.ResultType(defaultContext);

                if (!parameter.type.IsAssignableFrom(context.ModuleContext, resultType))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.IncompatibleTypes,
                                         $"Default value of parameter {parameter.name} has to be of type {parameter.type}, found {resultType}",
                                         parameter.Start,
                                         parameter.End
                                         ));
                    return(null);
                }

                parameter.defaultValue.EmitCode(defaultContext, false);
                parameter.type.AssignFrom(context.ModuleContext, resultType).EmitConvert(context);
                defaultContext.IL.EmitReturn(parameter.type.GeneratedType(context.ModuleContext));

                foreach (StructuralError error in defaultContext.AllErrors)
                {
                    context.AddError(error);
                }

                return(new DefaultValueFactoryFunction(defaultContext.MethodBuilder));
            }
        }
Beispiel #5
0
        public TO2Type FindVariableLocal(IBlockContext context, string name)
        {
            int idx = parameters.FindIndex(p => p.name == name);

            if (idx < 0 || idx >= parameters.Count)
            {
                return(null);
            }

            TO2Type parameterType = parameters[idx].type;

            if (parameterType != null)
            {
                return(parameterType);
            }
            if (resolvedType == null || idx >= resolvedType.parameterTypes.Count)
            {
                return(null);
            }

            return(resolvedType.parameterTypes[idx]);
        }
        public static CompiledKontrolModule CompileModule(DeclaredKontrolModule declaredModule)
        {
            ModuleContext moduleContext = declaredModule.moduleContext;

            List <StructuralError>         errors            = new List <StructuralError>();
            List <CompiledKontrolConstant> compiledConstants = new List <CompiledKontrolConstant>();
            SyncBlockContext constructorContext = new SyncBlockContext(moduleContext);

            foreach (DeclaredKontrolConstant constant in declaredModule.declaredConstants.Values)
            {
                TO2Type expressionType = constant.to2Constant.expression.ResultType(constructorContext);

                if (!constant.Type.IsAssignableFrom(constructorContext.ModuleContext, expressionType))
                {
                    errors.Add(new StructuralError(
                                   StructuralError.ErrorType.InvalidType,
                                   $"Constant {constant.Name} can not be initialized with type {expressionType}",
                                   constant.to2Constant.Start,
                                   constant.to2Constant.End
                                   ));
                    continue;
                }

                constant.to2Constant.expression.EmitCode(constructorContext, false);
                constant.Type.AssignFrom(constructorContext.ModuleContext, expressionType)
                .EmitConvert(constructorContext);
                if (constructorContext.HasErrors)
                {
                    errors.AddRange(constructorContext.AllErrors);
                }
                else
                {
                    constructorContext.IL.Emit(OpCodes.Stsfld, constant.runtimeField);
                }

                if (constant.IsPublic)
                {
                    compiledConstants.Add(new CompiledKontrolConstant(constant.Name, constant.Description,
                                                                      constant.Type, constant.runtimeField));
                }
            }

            foreach (DeclaredKontrolFunction function in declaredModule.declaredFunctions)
            {
                IBlockContext methodContext = function.methodContext;

                function.to2Function.EmitCode(methodContext);
                errors.AddRange(methodContext.AllErrors);
            }

            if (errors.Any())
            {
                throw new CompilationErrorException(errors);
            }

            Type runtimeType = moduleContext.CreateType();

            List <CompiledKontrolFunction> compiledFunctions = new List <CompiledKontrolFunction>();
            List <CompiledKontrolFunction> testFunctions     = new List <CompiledKontrolFunction>();

            foreach (DeclaredKontrolFunction function in declaredModule.declaredFunctions)
            {
                if (function.to2Function.modifier == FunctionModifier.Private)
                {
                    continue;
                }
                MethodBuilder methodBuilder = function.methodContext.MethodBuilder;
                MethodInfo    methodInfo    = runtimeType.GetMethod(methodBuilder.Name,
                                                                    methodBuilder.GetParameters().Select(p => p.ParameterType).ToArray());
                CompiledKontrolFunction compiledFunction = new CompiledKontrolFunction(function.Name,
                                                                                       function.Description, function.IsAsync, function.Parameters, function.ReturnType, methodInfo);

                if (function.to2Function.modifier == FunctionModifier.Test)
                {
                    testFunctions.Add(compiledFunction);
                }
                else
                {
                    compiledFunctions.Add(compiledFunction);
                }
            }

            return(new CompiledKontrolModule(declaredModule.Name,
                                             declaredModule.Description,
                                             moduleContext.exportedTypes.Select(t => (t.alias, t.type.UnderlyingType(moduleContext))),
                                             compiledConstants,
                                             compiledFunctions,
                                             testFunctions));
        }
Beispiel #7
0
        public static CompiledKontrolModule BindModule(Type moduleType)
        {
            lock (BoundModules) {
                if (BoundModules.ContainsKey(moduleType))
                {
                    return(BoundModules[moduleType]);
                }

                KSModule ksModule = moduleType.GetCustomAttribute <KSModule>();

                if (ksModule == null)
                {
                    throw new ArgumentException($"Type {moduleType} must have a kSClass attribute");
                }

                Type runtimeType = moduleType;
                List <CompiledKontrolFunction> functions = new List <CompiledKontrolFunction>();
                List <BoundType> types = new List <BoundType>();
                List <CompiledKontrolConstant> constants = new List <CompiledKontrolConstant>();

                while (runtimeType != null && runtimeType != typeof(object))
                {
                    foreach (Type nested in runtimeType.GetNestedTypes(BindingFlags.Public))
                    {
                        if (nested.GetCustomAttribute <KSClass>() != null)
                        {
                            types.Add(BindType(ksModule.Name, nested));
                        }
                    }

                    foreach (BoundType type in types)
                    {
                        LinkType(type);
                    }

                    foreach (FieldInfo field in runtimeType.GetFields(BindingFlags.Public | BindingFlags.Static))
                    {
                        KSConstant ksConstant = field.GetCustomAttribute <KSConstant>();
                        if (ksConstant == null)
                        {
                            continue;
                        }

                        TO2Type to2Type = BindingGenerator.MapNativeType(field.FieldType);

                        constants.Add(new CompiledKontrolConstant(
                                          ksConstant.Name ?? ToSnakeCase(field.Name).ToUpperInvariant(),
                                          NormalizeDescription(ksConstant.Description), to2Type, field));
                    }

                    foreach (MethodInfo method in runtimeType.GetMethods(BindingFlags.Public | BindingFlags.Static))
                    {
                        KSFunction ksFunction = method.GetCustomAttribute <KSFunction>();
                        if (ksFunction == null)
                        {
                            continue;
                        }

                        List <RealizedParameter> parameters = method.GetParameters().Select(p =>
                                                                                            new RealizedParameter(p.Name, MapNativeType(p.ParameterType),
                                                                                                                  BoundDefaultValue.DefaultValueFor(p))).ToList();
                        if (method.ReturnType.IsGenericType &&
                            method.ReturnType.GetGenericTypeDefinition() == typeof(Future <>))
                        {
                            Type         typeArg    = method.ReturnType.GetGenericArguments()[0];
                            RealizedType resultType =
                                typeArg == typeof(object) ? BuiltinType.Unit : MapNativeType(typeArg);
                            functions.Add(new CompiledKontrolFunction(ksFunction.Name ?? ToSnakeCase(method.Name),
                                                                      NormalizeDescription(ksFunction.Description), true, parameters, resultType, method));
                        }
                        else
                        {
                            RealizedType resultType = MapNativeType(method.ReturnType);
                            functions.Add(new CompiledKontrolFunction(ksFunction.Name ?? ToSnakeCase(method.Name),
                                                                      NormalizeDescription(ksFunction.Description), false, parameters, resultType, method));
                        }
                    }

                    runtimeType = runtimeType.BaseType;
                }

                CompiledKontrolModule module = new CompiledKontrolModule(ksModule.Name,
                                                                         NormalizeDescription(ksModule.Description), types.Select(t => (t.localName, t as RealizedType)),
                                                                         constants, functions, new List <CompiledKontrolFunction>());
                BoundModules.Add(moduleType, module);
                return(module);
            }
        }
Beispiel #8
0
        internal static RealizedType MapNativeType(Type type)
        {
            lock (TypeMappings) {
                if (type.IsGenericParameter)
                {
                    return(new GenericParameter(type.Name));
                }
                if (type.IsGenericType)
                {
                    Type   baseType = type.GetGenericTypeDefinition();
                    Type[] typeArgs = type.GetGenericArguments();

                    if (baseType == typeof(Option <>))
                    {
                        TO2Type innerType = typeArgs[0] == typeof(object)
                            ? BuiltinType.Unit
                            : MapNativeType(typeArgs[0]);

                        return(new OptionType(innerType));
                    }

                    if (baseType == typeof(Result <,>))
                    {
                        TO2Type successType = typeArgs[0] == typeof(object)
                            ? BuiltinType.Unit
                            : MapNativeType(typeArgs[0]);
                        TO2Type errorType = typeArgs[1] == typeof(object)
                            ? BuiltinType.Unit
                            : MapNativeType(typeArgs[1]);

                        return(new ResultType(successType, errorType));
                    }

                    if (baseType.FullName !.StartsWith("System.Func"))
                    {
                        List <TO2Type> parameterTypes = typeArgs.Take(typeArgs.Length - 1)
                                                        .Select(t => MapNativeType(t) as TO2Type).ToList();
                        TO2Type returnType = MapNativeType(typeArgs[typeArgs.Length - 1]);
                        return(new FunctionType(false, parameterTypes, returnType));
                    }

                    if (baseType.FullName.StartsWith("System.Action"))
                    {
                        List <TO2Type> parameterTypes = typeArgs.Select(t => MapNativeType(t) as TO2Type).ToList();
                        return(new FunctionType(false, parameterTypes, BuiltinType.Unit));
                    }

                    RealizedType to2BaseType = TypeMappings.Get(baseType);
                    if (to2BaseType != null)
                    {
                        List <TO2Type> typeArguments = typeArgs.Select(MapNativeType).Cast <TO2Type>().ToList();
                        return(new DirectTypeReference(to2BaseType, typeArguments));
                    }
                }
                else if (type.IsArray)
                {
                    TO2Type elementType = MapNativeType(type.GetElementType());

                    return(new ArrayType(elementType));
                }

                return(TypeMappings.Get(type) ?? throw new ArgumentException($"No mapping for {type}"));
            }
        }