package org.develnext.jphp.core.compiler.jvm;
import org.develnext.jphp.core.syntax.SyntaxAnalyzer;
import org.develnext.jphp.core.tester.Test;
import org.develnext.jphp.core.tokenizer.Tokenizer;
import org.develnext.jphp.core.tokenizer.token.Token;
import org.develnext.jphp.zend.ext.standard.StringFunctions;
import org.junit.Assert;
import php.runtime.Memory;
import php.runtime.common.LangMode;
import php.runtime.env.*;
import php.runtime.exceptions.CustomErrorException;
import php.runtime.exceptions.support.ErrorException;
import php.runtime.exceptions.support.ErrorType;
import php.runtime.ext.CoreExtension;
import php.runtime.ext.SPLExtension;
import php.runtime.lang.UncaughtException;
import php.runtime.lang.exception.BaseBaseException;
import php.runtime.loader.dump.ModuleDumper;
import php.runtime.memory.ArrayMemory;
import php.runtime.reflection.ClassEntity;
import php.runtime.reflection.ModuleEntity;
import php.runtime.util.PrintF;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
abstract public class JvmCompilerCase {
protected Environment environment = new Environment();
protected int runIndex = 0;
protected String lastOutput;
public boolean isConcurrent() {
String jphpTestConcurrent = System.getenv("JPHP_TEST_CONCURRENT");
return jphpTestConcurrent != null;
}
public boolean isCompiled() {
String jphpTestCompiled = System.getenv("JPHP_TEST_COMPILED");
return jphpTestCompiled != null;
}
protected CompileScope newScope(){
CompileScope compileScope = new CompileScope();
compileScope.setDebugMode(true);
compileScope.setLangMode(LangMode.DEFAULT);
compileScope.registerExtension(new CoreExtension());
compileScope.registerExtension(new SPLExtension());
return compileScope;
}
protected List<Token> getSyntaxTree(Context context){
Tokenizer tokenizer = null;
try {
tokenizer = new Tokenizer(context);
} catch (IOException e) {
throw new RuntimeException(e);
}
SyntaxAnalyzer analyzer = new SyntaxAnalyzer(environment, tokenizer);
return analyzer.getTree();
}
protected SyntaxAnalyzer getSyntax(Context context){
Tokenizer tokenizer = null;
try {
tokenizer = new Tokenizer(context);
} catch (IOException e) {
throw new RuntimeException(e);
}
environment.scope.setLangMode(LangMode.DEFAULT);
return new SyntaxAnalyzer(environment, tokenizer);
}
protected List<Token> getSyntaxTree(String code){
return getSyntaxTree(new Context(code));
}
protected Memory run(String code, boolean returned){
runIndex += 1;
Environment environment = new Environment(newScope());
code = "class TestClass { static function test(){ " + (returned ? "return " : "") + code + "; } }";
Context context = new Context(code);
JvmCompiler compiler = new JvmCompiler(environment, context, getSyntax(context));
ModuleEntity module = compiler.compile();
environment.getScope().loadModule(module);
ClassEntity entity = module.findClass("TestClass");
try {
return entity.findMethod("test").invokeStatic(environment);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
protected Memory runDynamic(String code, boolean returned){
runIndex += 1;
Environment environment = new Environment(newScope());
code = (returned ? "return " : "") + code + ";";
Context context = new Context(code);
JvmCompiler compiler = new JvmCompiler(environment, context, getSyntax(context));
ModuleEntity module = compiler.compile();
environment.getScope().loadModule(module);
try {
environment.registerModule(module);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
return module.includeNoThrow(environment);
}
@SuppressWarnings("unchecked")
protected Memory includeResource(String name, ArrayMemory globals){
ByteArrayOutputStream output = new ByteArrayOutputStream();
Environment environment;
if (isConcurrent()) {
environment = new ConcurrentEnvironment(newScope(), output);
} else {
environment = new Environment(newScope(), output);
}
File file = new File(Thread.currentThread().getContextClassLoader().getResource("resources/" + name).getFile());
Context context = new Context(file);
JvmCompiler compiler = new JvmCompiler(environment, context, getSyntax(context));
ModuleEntity module = compiler.compile();
environment.getScope().loadModule(module);
try {
environment.registerModule(module);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
if (globals != null)
environment.getGlobals().putAll(globals);
Memory memory = module.includeNoThrow(environment, environment.getGlobals());
try {
environment.doFinal();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
lastOutput = output.toString();
return memory;
}
protected String getOutput(){
return lastOutput;
}
protected Memory includeResource(String name){
return includeResource(name, null);
}
public static String rtrim(String s) {
int i = s.length() - 1;
while (i >= 0 && Character.isWhitespace(s.charAt(i))) {
i--;
}
return s.substring(0, i + 1);
}
public void check(String name){
check(name, false, -1);
}
public void check(String name, boolean withErrors) {
check(name, withErrors, -1);
}
public void check(String name, int errorFlags) {
check(name, false, errorFlags);
}
public void check(String name, boolean withErrors, int errorFlags){
File file;
ByteArrayOutputStream outputR = new ByteArrayOutputStream();
Environment environment;
if (isConcurrent()) {
environment = new ConcurrentEnvironment(newScope(), outputR);
} else {
environment = new Environment(newScope(), outputR);
}
//environment.setErrorFlags(ErrorType.E_ALL.value);
Test test = new Test(file = new File(
Thread.currentThread().getContextClassLoader().getResource("resources/" + name).getFile()
));
Context context = new Context(test.getFile(), file);
try {
JvmCompiler compiler = new JvmCompiler(environment, context, getSyntax(context));
environment.setErrorFlags(0);
if (errorFlags != -1)
environment.setErrorFlags(errorFlags);
if (!isCompiled()) {
environment.setErrorFlags(ErrorType.E_ALL.value);
}
ModuleEntity module = compiler.compile(false);
if (isCompiled()) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
ModuleDumper dumper = new ModuleDumper(context, environment, true);
dumper.save(module, output);
environment.setErrorFlags(ErrorType.E_ALL.value);
module = dumper.load(new ByteArrayInputStream(output.toByteArray()));
}
environment.getScope().loadModule(module);
environment.getScope().addUserModule(module);
environment.registerModule(module);
Memory memory = module.includeNoThrow(environment, environment.getGlobals());
} catch (ErrorException e) {
if (withErrors){
environment.getErrorReportHandler().onFatal(e);
} else {
throw new CustomErrorException(e.getType(), e.getMessage()
+ " line: "
+ (e.getTraceInfo().getStartLine() + test.getSectionLine("FILE") + 2)
+ ", pos: " + (e.getTraceInfo().getStartPosition() + 1),
e.getTraceInfo());
}
} catch (UncaughtException | BaseBaseException e){
environment.catchUncaught(e);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
try {
environment.doFinal();
} catch (ErrorException e){
if (withErrors) {
environment.getErrorReportHandler().onFatal(e);
try {
environment.getDefaultBuffer().flush();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
} else
throw e;
} catch (RuntimeException e){
throw e;
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
lastOutput = outputR.toString();
if (test.getExpect() != null)
Assert.assertEquals(test.getTest() + " (" + name + ")", test.getExpect(), rtrim(lastOutput));
if (test.getExpectF() != null){
Memory result = StringFunctions.sscanf(
environment, TraceInfo.valueOf(file.getName(), 0, 0), rtrim(lastOutput), test.getExpectF()
);
if (result.isNull())
result = new ArrayMemory();
PrintF printF = new PrintF(environment.getLocale(), test.getExpectF(), ((ArrayMemory)result).values());
String out = printF.toString();
Assert.assertEquals(out, rtrim(lastOutput));
}
}
protected Memory run(String code){
return run(code, true);
}
protected Memory runDynamic(String code){
return runDynamic(code, true);
}
}