public CompiledKontrolConstant(string name, string description, TO2Type type, FieldInfo runtimeField) { Name = name; Description = description; Type = type; RuntimeField = runtimeField; }
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)); }
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)); } }
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)); }
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); } }
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}")); } }