Skip to content

Instantly share code, notes, and snippets.

@abstractj
Created January 20, 2012 20:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abstractj/1649499 to your computer and use it in GitHub Desktop.
Save abstractj/1649499 to your computer and use it in GitHub Desktop.
Main.java
/**
* Copyright 2011 Douglas Campos
* Copyright 2011 dynjs contributors
*
* 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 org.dynjs.compiler;
import me.qmx.internal.org.objectweb.asm.ClassReader;
import me.qmx.internal.org.objectweb.asm.util.CheckClassAdapter;
import me.qmx.jitescript.CodeBlock;
import me.qmx.jitescript.JDKVersion;
import me.qmx.jitescript.JiteClass;
import org.dynjs.api.Function;
import org.dynjs.api.Scope;
import org.dynjs.parser.Statement;
import org.dynjs.runtime.DynFunction;
import org.dynjs.runtime.DynJS;
import org.dynjs.runtime.DynThreadContext;
import org.dynjs.runtime.DynamicClassLoader;
import org.dynjs.runtime.FunctionFactory;
import org.dynjs.runtime.Script;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicInteger;
import static me.qmx.jitescript.CodeBlock.newCodeBlock;
import static me.qmx.jitescript.util.CodegenUtils.p;
import static me.qmx.jitescript.util.CodegenUtils.sig;
public class DynJSCompiler {
private static final AtomicInteger counter = new AtomicInteger(0);
private static final String PACKAGE = "org.dynjs.gen.".replace('.', '/');
private boolean debug = false;
private final DynamicClassLoader classLoader = new DynamicClassLoader();
public Function compile(final DynFunction arg) {
final String className = PACKAGE + "AnonymousDynFunction" + counter.incrementAndGet();
JiteClass jiteClass = new JiteClass(className, p(DynFunction.class), new String[]{p(Function.class)}) {{
defineMethod("<init>", ACC_PUBLIC, sig(void.class),
newCodeBlock()
.aload(0)
.invokespecial(p(DynFunction.class), "<init>", sig(void.class))
.voidreturn()
);
defineMethod("call", ACC_PUBLIC, sig(Object.class, DynThreadContext.class, Object[].class), alwaysReturnWrapper(arg));
defineMethod("getArguments", ACC_PUBLIC, sig(String[].class), new CodeBlock() {{
String[] arguments = arg.getArguments();
bipush(arguments.length);
anewarray(p(String.class));
for (int i = 0; i < arguments.length; i++) {
String argument = arguments[i];
dup();
bipush(i);
ldc(argument);
aastore();
}
areturn();
}});
}};
Class<Function> functionClass = (Class<Function>) defineClass(jiteClass);
return FunctionFactory.create(functionClass);
}
private CodeBlock alwaysReturnWrapper(DynFunction arg) {
CodeBlock codeBlock = arg.getCodeBlock();
if (!codeBlock.returns()) {
codeBlock = codeBlock.aconst_null().areturn();
}
return codeBlock;
}
public Script compile(final Statement... statements) {
String className = PACKAGE + "AnonymousDynScript" + counter.incrementAndGet();
JiteClass jiteClass = new JiteClass(className, p(BaseScript.class), new String[]{p(Script.class)}) {
{
defineMethod("<init>", ACC_PUBLIC | ACC_VARARGS, sig(void.class, Statement[].class),
newCodeBlock()
.aload(0)
.aload(1)
.invokespecial(p(BaseScript.class), "<init>", sig(void.class, Statement[].class))
.voidreturn()
);
defineMethod("execute", ACC_PUBLIC | ACC_VARARGS, sig(void.class, DynThreadContext.class), getCodeBlock());
}
private CodeBlock getCodeBlock() {
final CodeBlock block = newCodeBlock();
for (Statement statement : statements) {
block.append(statement.getCodeBlock());
}
return block.voidreturn();
}
};
Class<?> functionClass = defineClass(jiteClass);
try {
Constructor<?> ctor = functionClass.getDeclaredConstructor(Statement[].class);
return (Script) ctor.newInstance(new Object[]{statements});
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
public void debugMode(boolean debug) {
this.debug = debug;
}
private Class<?> defineClass(JiteClass jiteClass) {
byte[] bytecode = jiteClass.toBytes(JDKVersion.V1_7);
if (debug) {
ClassReader reader = new ClassReader(bytecode);
CheckClassAdapter.verify(reader, true, new PrintWriter(System.out));
}
return classLoader.define(jiteClass.getClassName().replace('/', '.'), bytecode);
}
public static interface Types {
String RUNTIME = p(DynJS.class);
String CONTEXT = p(DynThreadContext.class);
String Scope = p(Scope.class);
}
public static interface Arities {
int THIS = 0;
int CONTEXT = 1;
}
public static interface Helper {
CodeBlock EMPTY_CODEBLOCK = newCodeBlock();
}
}
/**
* Copyright 2011 Douglas Campos
* Copyright 2011 dynjs contributors
*
* 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 org.dynjs.cli;
import org.dynjs.DynJSVersion;
import org.dynjs.api.Scope;
import org.dynjs.runtime.DynJS;
import org.dynjs.runtime.DynObject;
import org.dynjs.runtime.DynThreadContext;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class Main {
private Arguments dynJsArguments;
private CmdLineParser parser;
private String[] arguments;
private DynJS dynJS;
private DynThreadContext context;
private PrintStream stream;
public Main(PrintStream stream, String[] args) {
dynJsArguments = new Arguments();
parser = new CmdLineParser(dynJsArguments);
parser.setUsageWidth(80);
arguments = args;
dynJS = new DynJS();
context = new DynThreadContext();
this.stream = stream;
}
public static void main(String[] args) {
new Main(System.out, args).run();
}
void run() {
try {
parser.parseArgument(arguments);
if (dynJsArguments.isHelp() || dynJsArguments.isEmpty()) {
showUsage();
} else if (dynJsArguments.isConsole()) {
startRepl();
} else if (dynJsArguments.isConsole() && dynJsArguments.isDebug()){
startReplDebugMode();
} else if (dynJsArguments.isVersion()) {
showVersion();
} else if (!dynJsArguments.getFilename().isEmpty()) {
executeFile(dynJsArguments.getFilename());
}
} catch (CmdLineException e) {
stream.println(e.getMessage());
stream.println();
showUsage();
}
}
private void startReplDebugMode() {
//TODO do something here
}
private void executeFile(String filename) {
try {
dynJS.eval(context, new FileInputStream(filename));
} catch (FileNotFoundException e) {
stream.println("File " + filename + " not found");
}
}
private void showVersion() {
stream.println("Dyn.JS version " + DynJSVersion.FULL);
}
private void startRepl() {
DynThreadContext threadContext = new DynThreadContext();
Scope scope = new DynObject();
DynJS environment = new DynJS();
Repl repl = new Repl(environment, threadContext, scope, stream);
repl.run();
}
private void showUsage() {
StringBuilder usageText = new StringBuilder("Usage: dynjs [--console | --help | --version | FILE]\n");
usageText.append("Starts the dynjs console or executes FILENAME depending the parameters\n");
stream.println(usageText.toString());
parser.printUsage(stream);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment