Explorar el Código

Added native loader to resolve dependencies between native modules.

Stan Hebben hace 5 años
padre
commit
a86086cdec

+ 155
- 0
JavaIntegration/src/main/java/org/openzen/zencode/java/JavaNativeLoader.java Ver fichero

@@ -0,0 +1,155 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.zencode.java;
7
+
8
+import java.util.ArrayList;
9
+import java.util.HashMap;
10
+import java.util.List;
11
+import java.util.Map;
12
+import java.util.function.Consumer;
13
+import org.openzen.zencode.shared.CompileException;
14
+import org.openzen.zenscript.codemodel.definition.ZSPackage;
15
+
16
+/**
17
+ *
18
+ * @author Stan Hebben
19
+ */
20
+public class JavaNativeLoader {
21
+	private final Class<?>[] classes;
22
+	private final Class<?>[] globals;
23
+	private final Map<String, LoadingModule> modulesByBasePackage = new HashMap<>();
24
+	private final Map<String, LoadingModule> modulesByName = new HashMap<>();
25
+	private boolean loaded = false;
26
+	
27
+	public JavaNativeLoader(Class<?>[] classes, Class<?>[] globals) {
28
+		this.classes = classes;
29
+		this.globals = globals;
30
+	}
31
+	
32
+	public LoadingModule addModule(
33
+			ZSPackage pkg,
34
+			String name,
35
+			String basePackage,
36
+			String... dependencies) {
37
+		if (loaded)
38
+			throw new IllegalStateException("Already loaded modules!");
39
+		if (modulesByName.containsKey(name))
40
+			throw new IllegalArgumentException("Module already exists: " + name);
41
+		
42
+		LoadingModule module = new LoadingModule(pkg, name, basePackage, dependencies);
43
+		modulesByBasePackage.put(name, module);
44
+		modulesByName.put(name, module);
45
+		
46
+		return module;
47
+	}
48
+	
49
+	public ScriptingEngine load() throws CompileException {
50
+		loaded = true;
51
+		
52
+		sortClasses();
53
+		
54
+		ScriptingEngine engine = new ScriptingEngine();
55
+		for (LoadingModule module : modulesByBasePackage.values()) {
56
+			load(engine, module);
57
+		}
58
+		return engine;
59
+	}
60
+	
61
+	private void sortClasses() throws CompileException {
62
+		Map<String, LoadingModule> modulesByPackage = new HashMap<>();
63
+		for (LoadingModule module : modulesByName.values()) {
64
+			if (modulesByPackage.containsKey(module.basePackage))
65
+				throw CompileException.internalError("Two modules have the same base package: " + module.basePackage);
66
+			
67
+			modulesByPackage.put(module.basePackage, module);
68
+		}
69
+		
70
+		for (Class<?> cls : classes) {
71
+			LoadingModule module = findModuleByPackage(modulesByPackage, getPackageName(cls));
72
+			if (module == null) {
73
+				System.out.println("Warning: module not found for class " + cls.getName());
74
+			} else {
75
+				module.classes.add(cls);
76
+			}
77
+		}
78
+		for (Class<?> cls : globals) {
79
+			LoadingModule module = findModuleByPackage(modulesByPackage, getPackageName(cls));
80
+			if (module == null) {
81
+				System.out.println("Warning: module not found for class " + cls.getName());
82
+			} else {
83
+				module.globals.add(cls);
84
+			}
85
+		}
86
+	}
87
+	
88
+	private String getPackageName(Class<?> cls) {
89
+		String name = cls.getName();
90
+		return name.substring(0, name.lastIndexOf('.'));
91
+	}
92
+	
93
+	private LoadingModule findModuleByPackage(Map<String, LoadingModule> modulesByPackage, String packageName) {
94
+		if (modulesByPackage.containsKey(packageName))
95
+			return modulesByPackage.get(packageName);
96
+		
97
+		int index = packageName.lastIndexOf('.');
98
+		if (index < 0)
99
+			return null;
100
+		
101
+		return findModuleByPackage(modulesByPackage, packageName.substring(0, index));
102
+	}
103
+	
104
+	private JavaNativeModule load(ScriptingEngine engine, LoadingModule module) throws CompileException {
105
+		if (module.resolved != null)
106
+			return module.resolved;
107
+		
108
+		JavaNativeModule[] dependencies = new JavaNativeModule[module.dependencies.length];
109
+		for (int i = 0; i < dependencies.length; i++) {
110
+			LoadingModule dependency = modulesByName.get(module.dependencies[i]);
111
+			if (dependency == null)
112
+				throw CompileException.internalError("Module dependency for " + module.name + " missing: " + module.dependencies[i]);
113
+			
114
+			dependencies[i] = load(engine, dependency);
115
+		}
116
+		
117
+		module.resolved = new JavaNativeModule(
118
+				module.pkg,
119
+				module.name,
120
+				module.basePackage,
121
+				engine.registry,
122
+				dependencies);
123
+		for (Class<?> cls : module.classes)
124
+			module.resolved.addClass(cls);
125
+		for (Class<?> cls : module.globals)
126
+			module.resolved.addGlobals(cls);
127
+		for (Consumer<JavaNativeModule> resolved : module.whenResolved)
128
+			resolved.accept(module.resolved);
129
+		
130
+		engine.registerNativeProvided(module.resolved);
131
+		return module.resolved;
132
+	}
133
+	
134
+	public static class LoadingModule {
135
+		private final ZSPackage pkg;
136
+		private final String name;
137
+		private final String basePackage;
138
+		private final String[] dependencies;
139
+		private final List<Consumer<JavaNativeModule>> whenResolved = new ArrayList<>();
140
+		private final List<Class<?>> classes = new ArrayList<>();
141
+		private final List<Class<?>> globals = new ArrayList<>();
142
+		private JavaNativeModule resolved;
143
+		
144
+		private LoadingModule(ZSPackage pkg, String name, String basePackage, String[] dependencies) {
145
+			this.pkg = pkg;
146
+			this.name = name;
147
+			this.basePackage = basePackage;
148
+			this.dependencies = dependencies;
149
+		}
150
+		
151
+		public void whenLoaded(Consumer<JavaNativeModule> consumer) {
152
+			whenResolved.add(consumer);
153
+		}
154
+	}
155
+}

+ 1
- 1
common.gradle Ver fichero

@@ -6,7 +6,7 @@ apply plugin: 'java'
6 6
 apply plugin: 'maven'
7 7
 
8 8
 String mavenGroupId = 'org.openzen.zencode'
9
-String mavenVersion = '0.3.6'
9
+String mavenVersion = '0.3.7'
10 10
 
11 11
 sourceCompatibility = '1.8'
12 12
 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

Loading…
Cancelar
Guardar