/** * This file is part of Erjang - A JVM-based Erlang VM * * Copyright (c) 2009 by Trifork * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ package erjang; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import erjang.codegen.EFunCG; import kilim.Pausable; public abstract class EModule { /** Base constructor for modules. Will register <code>this</code> in the system. */ public EModule() { this(false); } public EModule(boolean delay_setup) { // TODO: handle if there is a module of this name already! if (!delay_setup) setup(); } protected void setup() {EModuleManager.setup_module(this);} /** * This method is code-generated in subclasses * @return module name, as a Java string */ public abstract String module_name(); /** * This method is code-generated in subclasses * * @return the attributes associated with this module */ public ESeq attributes() { return ERT.NIL; } public ESeq compile() { return ERT.NIL; } /** * This method is used by EModuleManager in function resolution. */ public abstract void registerImportsAndExports() throws Exception; public abstract ClassLoader getModuleClassLoader(); protected void load_native_bifs() throws Exception { Class<? extends ENative> natives; String nname = "erjang.m."+module_name()+".Native"; try { natives = (Class<? extends ENative>) Class.forName(nname, true, getModuleClassLoader()); } catch (ClassNotFoundException e) { // System.out.println("no native: " + nname); return; } ENative en; try { en = natives.newInstance(); } catch (Exception e) { throw new Error("cannot instantiate Natives for module " + module_name(), e); } for (Class<?> nat : en.getNativeClasses()) { process_native_annotations(nat); } } protected void process_native_annotations(Class<?> nat) throws Exception { for (Field field : nat.getDeclaredFields()) { if (!Modifier.isStatic(field.getModifiers())) continue; Import imp = field.getAnnotation(Import.class); if (imp != null) { field.setAccessible(true); FunID f = new FunID(imp); EModuleManager.add_import(f, new FieldBinder(field, f, module_name())); //System.out.println("N import " + f); continue; } } // for native methods Method[] methods = nat.getDeclaredMethods(); next_method: for (Method method : methods) { BIF efun = method.getAnnotation(BIF.class); if (efun != null && efun.type().export()) { String mod = module_name(); String name = efun.name(); if (name.equals("__SELFNAME__")) name = method.getName(); Class<?>[] parameterTypes = method.getParameterTypes(); int arity = parameterTypes.length; if (arity > 0 && parameterTypes[0].equals(EProc.class)) { arity -= 1; } for (int i = 0; i < parameterTypes.length; i++) { if (i == 0 && parameterTypes[i].equals(EProc.class)) continue; if (parameterTypes[i].equals(EObject.class)) continue; // we only allow EProc as zero'th and EObject as other args // in exported functions continue next_method; } FunID f = new FunID(mod, name, arity); //System.out.println("N export " + f); EModuleManager.add_export(this, f, EFunCG.funForMethod(method, mod)); } } } public static class FieldBinder extends EModuleManager.FunctionBinder { WeakReference<Field> fieldRef; final WeakReference<Class> classRef; final FunID funID; final String mod; final String fieldName; public FieldBinder(Field field, FunID funID, String mod) { this.fieldRef = new WeakReference<Field>(field); this.classRef = new WeakReference<Class>(field.getDeclaringClass()); fieldName = field.getName(); field.setAccessible(true); this.funID = funID; this.mod = mod; } @Override public FunID getFunID(){ return funID; } public boolean bind(EFun value) { Field field = fieldRef.get(); if (field == null) { Class clazz = classRef.get(); if (clazz == null) { return false; } else { try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); this.fieldRef = new WeakReference<Field>(field); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } } try { field.set(null, value); return true; } catch (IllegalAccessException e) { throw new RuntimeException(e); } } public String toString() { return "<FieldBinder for "+funID+" in "+mod+": "+classRef.get()+">"; } } public EObject on_load(EProc proc) throws Pausable { return ERT.am_ok; } public boolean has_on_load() { return false; } }