package
week10;
import
org.objectweb.asm.ClassWriter;
import
org.objectweb.asm.Label;
import
org.objectweb.asm.MethodVisitor;
import
week9.AktkBinding;
import
week7.AktkAst;
import
week7.ast.*;
import
java.io.IOException;
import
java.nio.file.Files;
import
java.nio.file.Path;
import
java.nio.file.Paths;
import
java.util.HashMap;
import
java.util.Map;
import
static
org.objectweb.asm.Opcodes.*;
public
class
AktkCompiler {
public
static
void
main(String[] args)
throws
IOException {
if
(args.length !=
1
) {
throw
new
IllegalArgumentException(
"Sellele programmile tuleb anda parameetriks kompileeritava AKTK faili nimi"
);
}
Path sourceFile = Paths.get(args[
0
]);
if
(!Files.isRegularFile(sourceFile)) {
throw
new
IllegalArgumentException(
"Ei leia faili nimega '"
+ sourceFile +
"'"
);
}
String className = sourceFile.getFileName().toString().replace(
".aktk"
,
""
);
Path classFile = sourceFile.toAbsolutePath().getParent().resolve(className +
".class"
);
createClassFile(sourceFile, className, classFile);
}
private
static
void
createClassFile(Path sourceFile, String className, Path classFile)
throws
IOException {
String source = Files.readString(sourceFile);
AstNode ast = AktkAst.createAst(source);
AktkBinding.bind(ast);
byte
[] bytes = createClass(ast, className);
Files.write(classFile, bytes);
}
public
static
byte
[] createClass(AstNode ast, String className) {
ClassWriter cw =
new
ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className,
null
,
"java/lang/Object"
,
null
);
cw.visitSource(
null
,
null
);
MethodVisitor mv = cw.visitMethod(
ACC_PUBLIC + ACC_STATIC,
"main"
,
"([Ljava/lang/String;)V"
,
null
,
new
String[] {
"java/io/IOException"
});
mv.visitCode();
new
AktkCompilerVisitor(mv).visit(ast);
mv.visitInsn(RETURN);
mv.visitMaxs(
0
,
0
);
mv.visitEnd();
cw.visitEnd();
return
cw.toByteArray();
}
private
static
class
AktkCompilerVisitor
extends
AstVisitor.VoidVisitor {
private
final
MethodVisitor mv;
private
final
Map<VariableBinding, Integer> variableIndices =
new
HashMap<>();
private
AktkCompilerVisitor(MethodVisitor mv) {
this
.mv = mv;
}
private
int
getVariableIndex(VariableBinding binding) {
return
variableIndices.computeIfAbsent(binding, ignoreBinding -> variableIndices.size() +
1
);
}
@Override
protected
void
visitVoid(Assignment assignment) {
}
@Override
protected
void
visitVoid(Block block) {
for
(Statement stmt : block.getStatements()) {
visit(stmt);
}
}
@Override
protected
void
visitVoid(ExpressionStatement expressionStatement) {
}
@Override
protected
void
visitVoid(FunctionCall functionCall) {
if
(functionCall.isArithmeticOperation()) {
compileArithmeticOperation(functionCall);
}
else
if
(functionCall.isComparisonOperation()) {
compileComparisonOperation(functionCall);
}
else
{
compileBuiltinFunction(functionCall);
}
}
private
void
compileArithmeticOperation(FunctionCall functionCall) {
}
private
void
compileComparisonOperation(FunctionCall call) {
}
private
void
compileBuiltinFunction(FunctionCall functionCall) {
}
@Override
protected
void
visitVoid(FunctionDefinition functionDefinition) {
throw
new
UnsupportedOperationException(
"cannot compile function definitions"
);
}
@Override
protected
void
visitVoid(IfStatement ifStatement) {
Label doneLabel =
new
Label();
Label elseLabel =
new
Label();
}
@Override
protected
void
visitVoid(IntegerLiteral integerLiteral) {
}
@Override
protected
void
visitVoid(ReturnStatement returnStatement) {
throw
new
UnsupportedOperationException(
"cannot compile return statements"
);
}
@Override
protected
void
visitVoid(StringLiteral stringLiteral) {
throw
new
UnsupportedOperationException(
"cannot compile strings"
);
}
@Override
protected
void
visitVoid(Variable variable) {
}
@Override
protected
void
visitVoid(VariableDeclaration variableDeclaration) {
}
@Override
protected
void
visitVoid(WhileStatement whileStatement) {
}
}
}