All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ssssssss.script.MagicScript Maven / Gradle / Ivy

The newest version!
package org.ssssssss.script;


import org.ssssssss.script.compile.CompileCache;
import org.ssssssss.script.compile.MagicScriptCompileException;
import org.ssssssss.script.compile.MagicScriptCompiler;
import org.ssssssss.script.exception.MagicExitException;
import org.ssssssss.script.exception.MagicScriptException;
import org.ssssssss.script.functions.DynamicModuleImport;
import org.ssssssss.script.parsing.Parser;
import org.ssssssss.script.parsing.Span;
import org.ssssssss.script.parsing.VarIndex;
import org.ssssssss.script.parsing.ast.Expression;
import org.ssssssss.script.parsing.ast.Node;
import org.ssssssss.script.parsing.ast.statement.Import;
import org.ssssssss.script.parsing.ast.statement.Return;
import org.ssssssss.script.parsing.ast.statement.VariableAccess;
import org.ssssssss.script.runtime.MagicScriptClassLoader;
import org.ssssssss.script.runtime.MagicScriptRuntime;
import org.ssssssss.script.runtime.MagicScriptVariableAccessRuntime;

import javax.script.Bindings;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

public class MagicScript extends CompiledScript {

	public static final String CONTEXT_ROOT = "ROOT";

	public static final String DEBUG_MARK = "!# DEBUG\r\n";

	/**
	 * 所有语句
	 */
	private final List nodes;

	private final ScriptEngine scriptEngine;

	/**
	 * 存放所有变量定义
	 */
	private final Set varIndices;

	/**
	 * 是否已经编译过
	 */
	private final AtomicBoolean compile = new AtomicBoolean(false);

	/**
	 * 如果是简单的取值操作,则跳过编译
	 */
	private MagicScriptVariableAccessRuntime accessRuntime;

	/**
	 * 构造函数
	 */
	private Constructor constructor;

	private final boolean debug;

	private List spans;

	private String[] varNames;

	private static CompileCache compileCache;

	private MagicScript(List nodes, Set varIndices, ScriptEngine scriptEngine, boolean debug) {
		this.nodes = nodes;
		this.varIndices = varIndices;
		this.scriptEngine = scriptEngine;
		this.debug = debug;
	}

	public static void setCompileCache(int capacity) {
		compileCache = new CompileCache(capacity);
	}

	/**
	 * 创建MagicScript
	 */
	public static MagicScript create(String source, ScriptEngine scriptEngine) {
		return create(false, source, scriptEngine);
	}

	/**
	 * 创建MagicScript
	 */
	public static MagicScript create(boolean expression, String source, ScriptEngine scriptEngine) {
		if (compileCache == null) {
			compileCache = new CompileCache(500);
		}
		return compileCache.get(source, () -> {
			Parser parser = new Parser();
			boolean debug = source.startsWith(DEBUG_MARK);
			String script = debug ? source.substring(DEBUG_MARK.length()) : source;
			List nodes = parser.parse(expression ? "return " + script : script);
			Set varIndices = parser.getVarIndices();
			return new MagicScript(nodes, varIndices, scriptEngine, debug);
		});
	}

	public Object execute(MagicScriptContext context) {
		MagicScriptRuntime runtime = null;
		try {
			MagicScriptEngine.getDefaultImports().forEach((name, value) -> {
				if (value instanceof DynamicModuleImport) {
					context.set(name, ((DynamicModuleImport) value).getDynamicModule(context));
				} else {
					context.set(name, value);
				}
			});
			runtime = compile();
			return runtime.execute(context);
		} catch (MagicExitException e) {
			return e.getExitValue();
		} catch (MagicScriptCompileException e) {
			throw e;
		} catch (Throwable t) {
			MagicScriptError.transfer(runtime, t);
		}
		return null;
	}

	/**
	 * 编译
	 */
	public MagicScriptRuntime compile() throws MagicScriptCompileException {
		if (this.accessRuntime != null) {
			return this.accessRuntime;
		}
		if (nodes.size() == 1 && nodes.get(0) instanceof Return) {
			Return returnNode = (Return) nodes.get(0);
			if (returnNode.getReturnValue() instanceof VariableAccess) {
				return this.accessRuntime = new MagicScriptVariableAccessRuntime(((VariableAccess) returnNode.getReturnValue()).getVarIndex().getName());
			}
		}
		if (!compile.get()) {
			synchronized (compile) {
				if (!compile.get()) {
					compile0();
					compile.set(true);
				}
			}
		}
		return buildRuntime();
	}

	private void compile0() {
		try {
			MagicScriptCompiler compiler = new MagicScriptCompiler(this.varIndices, this.debug);
			nodes.forEach(node -> node.visitMethod(compiler));
			// 如果只是一个表达式
			if (nodes.size() == 1 && nodes.get(0) instanceof Expression) {
				Node node = nodes.get(0);
				compiler.loadVars();
				compiler.compile(new Return(node.getSpan(), node));
			} else {
				// 根据是否有 import "xxx.xx.xx.*" 来分组
				Map> nodeMap = nodes.stream().collect(Collectors.partitioningBy(it -> it instanceof Import && ((Import) it).isImportPackage()));
				// 编译需要的方法
				compiler.compile(nodeMap.get(Boolean.TRUE));    // 先编译 import "xxx.xxx.x.*"
				// 加载变量信息
				compiler.loadVars();
				// 编译其它语句
				compiler.compile(nodeMap.get(Boolean.FALSE));
			}
			Class clazz = new MagicScriptClassLoader(Thread.currentThread().getContextClassLoader()).load(compiler.getClassName(), compiler.bytecode());
			this.constructor = clazz.getConstructor();
			// 设置变量名字
			this.varNames = varIndices.stream().map(VarIndex::getName).toArray(String[]::new);
			// 设置所有Span
			this.spans = compiler.getSpans();
		} catch (MagicScriptException mse) {
			throw new MagicScriptCompileException(mse.getSimpleMessage(), mse);
		} catch (MagicScriptCompileException e) {
			throw e;
		} catch (Exception e) {
			throw new MagicScriptCompileException(e);
		}
	}

	private MagicScriptRuntime buildRuntime() {
		try {
			MagicScriptRuntime runtime = constructor.newInstance();
			// 设置变量名字,为Runtime拷贝副本
			runtime.setVarNames(Arrays.copyOf(this.varNames, this.varNames.length));
			// 设置所有Span,为Runtime拷贝副本
			runtime.setSpans(new ArrayList<>(this.spans));
			return runtime;
		} catch (Exception e) {
			throw new MagicScriptCompileException(e);
		}
	}


	@Override
	public Object eval(ScriptContext context) {
		Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
		if (bindings.containsKey(CONTEXT_ROOT)) {
			Object root = bindings.get(CONTEXT_ROOT);
			if (root instanceof MagicScriptContext) {
				MagicScriptContext rootContext = (MagicScriptContext) root;
				return execute(rootContext);
			} else {
				throw new MagicScriptException("参数不正确!");
			}
		}
		MagicScriptContext magicScriptContext = new MagicScriptContext();
		magicScriptContext.putMapIntoContext(context.getBindings(ScriptContext.GLOBAL_SCOPE));
		magicScriptContext.putMapIntoContext(context.getBindings(ScriptContext.ENGINE_SCOPE));
		return execute(magicScriptContext);
	}

	@Override
	public ScriptEngine getEngine() {
		return scriptEngine;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy