private ElfClass LoadClass(ClassDef classDef) { // so far we assume a single global namespace for class names var rtimpl = VM.Classes.SingleOrDefault(c => c.Name == classDef.Rtimpl); if (rtimpl == null) { var exception = new ErroneousScriptLoaderException(Script, classDef, ElfExceptionType.ClassRtimplNotFound); exception.ToString(); throw exception; } var @class = new ElfClass(classDef, classDef.Name, rtimpl); var funcs = new Dictionary<String, NativeMethod>(); foreach (var funcDef in classDef.Funcs) { var func = LoadNativeFunc(@class, funcDef); if (funcs.ContainsKey(func.Name)) { throw new ErroneousScriptLoaderException(Script, funcDef, ElfExceptionType.DuplicateFuncLoaded); } else { funcs.Add(func.Name, func); } } @class.Methods.AddRange(funcs.Values.Cast<ElfMethod>()); return @class; }
protected ElfMethod(AstNode elfNode, ElfClass declaringType, string name, String[] args, bool varargs) : base(elfNode) { DeclaringType = declaringType; Name = name; Args = args; IsVarargs = varargs; }
public static ElfMethod Resolve(VirtualMachine vm, String name, ElfClass thisClass, params ElfClass[] argClasses) { var firstArgClass = argClasses.Length == 0 ? new ElfClass(null, "aux", typeof(object)) : argClasses[0]; Func<ElfMethod, int> isStaticOrCtor = m => { if (!(m is ClrMethod)) return 0; if (m.DeclaringType != null && m.DeclaringType.Ctors.Contains((ClrMethod)m)) return 1; if (((ClrMethod)m).Rtimpl.IsStatic) return 1; return 0; }; Func<ElfMethod, bool> argcOk = m => { var sigArgs = m.DeclaringType == thisClass ? argClasses.Length : argClasses.Length + isStaticOrCtor(m) - 1; return m.IsVarargs ? m.Argc <= sigArgs : m.Argc == sigArgs; }; var methodsOfThis = thisClass.Methods.Where(m => m.Name == name && argcOk(m)).ToArray(); var ctorsOfName = vm.Classes.Where(c => c.Name == name).Select(c => c.Ctors.Where(m => argcOk(m))).Flatten().ToArray(); var methodsOfFirstArg = firstArgClass.Methods.Where(m => m.Name == name && argcOk(m)).ToArray(); var helperMethods = vm.HelperMethods.Where(m => m.Name == name && argcOk(m)).ToArray(); if (methodsOfThis.Length != 0) { return methodsOfThis.Single(); } else if (ctorsOfName.Length != 0) { return ctorsOfName.Single(); } else if (methodsOfFirstArg.Length != 0) { return methodsOfFirstArg.Single(); } else if (helperMethods.Length != 0) { return helperMethods.Single(); } else { return null; } }
public ElfClass(AstNode elfNode, String name, ElfClass rtimpl) : this(elfNode, name, rtimpl.ClrType) { Rtimpl = rtimpl; }
public ElfScriptDefinedClassInstance(ElfClass elfClass, Object clrInstance) { _type = elfClass; ClrObject = clrInstance; }
public void Load() { try { var classes = new Dictionary<String, ElfClass>(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies() .Where(asm => asm.IsDefined(typeof(ElfDiscoverableAttribute), false))) { // n0te. this is useful for debugging so I didn't remove it // var aname = String.Format("{0} at {1}", assembly.FullName, assembly.Location); // Trace.WriteLine("======= asm: " + aname + "======="); // var oldKeys = classes.Keys.ToArray(); foreach (var type in assembly.GetTypes()) { if (type.IsRtimpl()) { if (type.IsOpenGeneric()) { throw new UnexpectedLoaderException(String.Format( "Fatal error loading RTIMPL type '{0}'. Reason: type is an open generic.", type)); } // so far we assume a single global namespace for class names var @class = new ElfClass(null, type.RtimplOf(), type); // todo. before release we can add russian-names-only regex validator here if (@class.Name.IsNullOrEmpty()) { throw new UnexpectedLoaderException(String.Format( "Fatal error loading RTIMPL type '{0}'. Reason: Elf class name is null or empty.", type)); } if (classes.ContainsKey(@class.Name)) { throw new UnexpectedLoaderException(String.Format( "Fatal error loading RTIMPL type '{0}'. Reason: duplicate Elf class name.", @class.Name)); } else { classes.Add(@class.Name, @class); } foreach (var ctor in type.GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(ctor1 => ctor1.IsRtimpl())) { @class.Ctors.Add(new ClrMethod(null, @class, @class.Name, ctor)); } foreach (var method in type.GetMethods( BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic) .Where(method1 => method1.IsRtimpl())) { @class.Methods.Add(new ClrMethod(null, @class, method.RtimplOf(), method)); } VM.Classes.Add(@class); } if (type.IsElfSerializable()) { var serializableAs = type.ElfSerializableAs(); if (serializableAs.IsNullOrEmpty()) { throw new UnexpectedLoaderException(String.Format( "Fatal error registering type '{0}' as serializable. Reason: Type token is null or empty.", type)); } if (!type.GetInterfaces().Any(iface => iface == typeof(IElfObject))) { throw new UnexpectedLoaderException(String.Format( "Fatal error registering type '{0}' as serializable. Reason: Type doesn't implement the IElfObject interface.", type)); } var deserializer = type.ElfDeserializer(); if (deserializer == null) { throw new UnexpectedLoaderException(String.Format( "Fatal error registering type '{0}' as serializable. Reason: Type doesn't expose a static Parse method, neither it is convertible from string.", type)); } VM.Deserializers.Add(serializableAs, deserializer); } if (type.IsRthelper()) { foreach (var ctor in type.GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(ctor1 => ctor1.IsRtimpl())) { throw new UnexpectedLoaderException(String.Format( "Fatal error registering type '{0}' as RTHELPER. Reason: Rthelpers cannot define RTIMPL constructors.", type)); } foreach (var ctor in type.GetMethods( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(ctor1 => ctor1.IsRtimpl())) { throw new UnexpectedLoaderException(String.Format( "Fatal error registering type '{0}' as RTHELPER. Reason: Rthelpers cannot define RTIMPL instance methods.", type)); } foreach (var method in type.GetMethods( BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic) .Where(method1 => method1.IsRtimpl())) { VM.HelperMethods.Add(new ClrMethod(method.RtimplOf(), method)); } } } // n0te. this is useful for debugging so I didn't remove it // classes.Keys.Except(oldKeys).ForEach(cls => Trace.WriteLine(cls + " " + classes[cls])); } } catch (Exception e) { if (e is UnexpectedLoaderException) throw; throw new UnexpectedLoaderException(e); } }
public NativeMethod(AstNode elfNode, ElfClass declaringType) : base(elfNode, declaringType, ((FuncDef)elfNode).Name, ((FuncDef)elfNode).Args.ToArray(), false) { FuncDef = (FuncDef)elfNode; }
private NativeMethod LoadNativeFunc(ElfClass @class, FuncDef funcDef) { var native = new NativeMethod(funcDef, @class); native.Body = VM.Compiler.Compile(native.FuncDef); return native; }
public ClrMethod(AstNode elfNode, ElfClass declaringType, string name, MethodBase rtimpl) : base(elfNode, declaringType, name, rtimpl.GetParameters().Select(pi => pi.Name).ToArray(), rtimpl.IsVarargs()) { Rtimpl = rtimpl; }