package me.tomassetti.turin.compiler;
import com.google.common.collect.ImmutableList;
import me.tomassetti.turin.classloading.TurinClassLoader;
import me.tomassetti.turin.classloading.ClassFileDefinition;
import me.tomassetti.turin.resolvers.InFileSymbolResolver;
import me.tomassetti.turin.resolvers.jdk.JdkTypeResolver;
import me.tomassetti.turin.parser.ast.*;
import me.tomassetti.turin.parser.ast.expressions.*;
import me.tomassetti.turin.parser.ast.expressions.literals.StringLiteral;
import me.tomassetti.turin.parser.ast.statements.BlockStatement;
import me.tomassetti.turin.parser.ast.statements.ExpressionStatement;
import me.tomassetti.turin.parser.ast.statements.Statement;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* We test specifically the compilation of programs AST nodes.
*/
public class CompilerOnProgramTest extends AbstractCompilerTest {
private TurinFile emptyProgram() {
// define AST
TurinFile turinFile = new TurinFile();
NamespaceDefinition namespaceDefinition = new NamespaceDefinition("myProgram");
turinFile.setNameSpace(namespaceDefinition);
Program program = new Program("SuperSimple", new BlockStatement(ImmutableList.of()), "args");
program.setPosition(Position.create(0, 0, 0, 0));
turinFile.add(program);
return turinFile;
}
private TurinFile simpleProgram() {
// define AST
TurinFile turinFile = new TurinFile();
NamespaceDefinition namespaceDefinition = new NamespaceDefinition("myProgram");
turinFile.setNameSpace(namespaceDefinition);
StringLiteral stringLiteral = new StringLiteral("Hello Turin!");
QualifiedName javaLang = new QualifiedName(new QualifiedName("java"), "lang");
TypeIdentifier system = new TypeIdentifier(javaLang, "System");
StaticFieldAccess out = new StaticFieldAccess(system, "out");
FieldAccess println = new FieldAccess(out, "println");
FunctionCall printInvokation = new FunctionCall(println, ImmutableList.of(new ActualParam(stringLiteral)));
Statement printStatement = new ExpressionStatement(printInvokation);
Program program = new Program("SuperSimple", new BlockStatement(ImmutableList.of(printStatement)), "args");
program.setPosition(Position.create(0, 0, 0, 0));
turinFile.add(program);
return turinFile;
}
private void invokeProgram(Class<?> programClass) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method main = programClass.getMethod("main", String[].class);
assertEquals("main", main.getName());
assertEquals(true, Modifier.isStatic(main.getModifiers()));
assertEquals(1, main.getParameterTypes().length);
assertEquals(String[].class, main.getParameterTypes()[0]);
main.invoke(null, (Object)new String[]{});
}
private void loadAndInvoke(ClassFileDefinition classFileDefinition) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
TurinClassLoader turinClassLoader = new TurinClassLoader();
Class programClass = turinClassLoader.addClass(classFileDefinition.getName(),
classFileDefinition.getBytecode());
invokeProgram(programClass);
}
@Test
public void compileAnEmptyProgram() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = emptyProgram();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
loadAndInvoke(classFileDefinitions.get(0));
}
@Test
public void compileASimpleProgram() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
TurinFile turinFile = simpleProgram();
// generate bytecode
Compiler instance = new Compiler(new InFileSymbolResolver(JdkTypeResolver.getInstance()), new Compiler.Options());
List<ClassFileDefinition> classFileDefinitions = instance.compile(turinFile, new MyErrorCollector());
assertEquals(1, classFileDefinitions.size());
assertEquals("myProgram.SuperSimple", classFileDefinitions.get(0).getName());
loadAndInvoke(classFileDefinitions.get(0));
}
}