提交 c5d8aae5 编写于 作者: M Maxim Shafirov

codegen, initial

上级 80167437
<component name="ProjectDictionaryState">
<dictionary name="max">
<words>
<w>codegen</w>
</words>
</dictionary>
</component>
\ No newline at end of file
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.util.TraceClassVisitor;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* @author max
*/
public class ClassVisitorFactory {
public ClassVisitor visitorForClassIn(JetNamespace namespace) {
return new TraceClassVisitor(new PrintWriter(new StringWriter()));
}
}
package org.jetbrains.jet.codegen;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.jet.lang.psi.*;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import java.util.List;
import java.util.Stack;
/**
* @author max
*/
public class ExpressionCodegen extends JetVisitor {
private final Stack<Label> myLoopStarts = new Stack<Label>();
private final Stack<Label> myLoopEnds = new Stack<Label>();
private final InstructionAdapter v;
private final TObjectIntHashMap<JetProperty> myVarIndex = new TObjectIntHashMap<JetProperty>();
private int myMaxVarIndex = 0;
public ExpressionCodegen(MethodVisitor v) {
this.v = new InstructionAdapter(v);
}
private void gen(JetElement expr) {
if (expr == null) throw new CompilationException();
expr.accept(this);
}
@Override
public void visitExpression(JetExpression expression) {
throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
}
@Override
public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
gen(expression.getExpression());
}
@Override
public void visitAnnotatedExpression(JetAnnotatedExpression expression) {
gen(expression.getBaseExpression());
}
@Override
public void visitIfExpression(JetIfExpression expression) {
gen(expression.getCondition());
unboxBoolean();
JetExpression thenExpression = expression.getThen();
JetExpression elseExpression = expression.getElse();
if (thenExpression == null && elseExpression == null) {
throw new CompilationException();
}
if (thenExpression == null) {
generateSingleBranchIf(elseExpression, false);
return;
}
if (elseExpression == null) {
generateSingleBranchIf(thenExpression, true);
return;
}
Label elseLabel = new Label();
v.ifeq(elseLabel); // == 0, i.e. false
gen(thenExpression);
Label endLabel = new Label();
v.goTo(endLabel);
v.mark(elseLabel);
gen(elseExpression);
v.mark(endLabel);
}
@Override
public void visitWhileExpression(JetWhileExpression expression) {
Label condition = new Label();
myLoopStarts.push(condition);
v.mark(condition);
Label end = new Label();
myLoopEnds.push(end);
gen(expression.getCondition());
unboxBoolean();
v.ifeq(end);
genToUnit(expression.getBody());
v.goTo(condition);
v.mark(end);
myLoopEnds.pop();
myLoopStarts.pop();
}
@Override
public void visitDoWhileExpression(JetDoWhileExpression expression) {
Label condition = new Label();
v.mark(condition);
myLoopStarts.push(condition);
Label end = new Label();
myLoopEnds.push(end);
genToUnit(expression.getBody());
gen(expression.getCondition());
unboxBoolean();
v.ifne(condition);
v.mark(end);
myLoopEnds.pop();
myLoopStarts.pop();
}
@Override
public void visitBreakExpression(JetBreakExpression expression) {
String labelName = expression.getLabelName();
Label label = labelName == null ? myLoopEnds.peek() : null; // TODO:
v.goTo(label);
}
@Override
public void visitContinueExpression(JetContinueExpression expression) {
String labelName = expression.getLabelName();
Label label = labelName == null ? myLoopStarts.peek() : null; // TODO:
v.goTo(label);
}
private void unboxBoolean() {
v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z");
}
private void generateSingleBranchIf(JetExpression expression, boolean inverse) {
Label endLabel = new Label();
if (inverse) {
v.ifeq(endLabel);
}
else {
v.ifne(endLabel);
}
genToUnit(expression);
v.mark(endLabel);
}
private void genToUnit(JetExpression expression) {
gen(expression);
if (!isUnitType(expression)) {
v.pop();
}
}
@Override
public void visitConstantExpression(JetConstantExpression expression) {
Object value = expression.getValue();
v.aconst(value);
if (value instanceof Integer) {
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
}
else if (value instanceof Boolean) {
v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
}
else if (value instanceof Character) {
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
}
else if (value instanceof Short) {
v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
}
else if (value instanceof Long) {
v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
}
else if (value instanceof Byte) {
v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
}
else if (value instanceof Float) {
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
}
else if (value instanceof Double) {
v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
}
}
@Override
public void visitBlockExpression(JetBlockExpression expression) {
Label blockStart = new Label();
v.mark(blockStart);
List<JetElement> statements = expression.getStatements();
for (JetElement statement : statements) {
if (statement instanceof JetProperty) {
myVarIndex.put((JetProperty) statement, myMaxVarIndex++);
}
}
for (JetElement statement : statements) {
gen(statement);
}
Label blockEnd = new Label();
v.mark(blockEnd);
for (JetElement statement : statements) {
if (statement instanceof JetProperty) {
JetProperty var = (JetProperty) statement;
int index = myVarIndex.remove(var);
v.visitLocalVariable(var.getName(), getType(var).getDescriptor(), null, blockStart, blockEnd, index);
myMaxVarIndex--;
}
}
}
private Type getType(JetProperty var) {
return InstructionAdapter.OBJECT_TYPE; // TODO:
}
private boolean isUnitType(JetExpression e) {
return false; // TODO:!!!
}
@Override
public void visitProperty(JetProperty property) {
int index = myVarIndex.get(property);
assert index >= 0;
JetExpression initializer = property.getInitializer();
if (initializer != null) {
gen(initializer);
v.store(index, getType(property));
}
}
private static class CompilationException extends RuntimeException {
}
}
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.objectweb.asm.ClassVisitor;
/**
* @author max
*/
public class FunctionCodegen {
private final ClassVisitor v;
public FunctionCodegen(ClassVisitor v) {
this.v = v;
}
public void gen(JetFunction f, JetNamespace owner) {
}
public void gen(JetFunction f, JetClass owner) {
}
}
package org.jetbrains.jet.codegen;
/**
* @author max
*/
public class MethodCodeGen {
}
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
/**
* @author max
*/
public class NamespaceCodegen {
private final ClassVisitorFactory factory;
public NamespaceCodegen(ClassVisitorFactory factory) {
this.factory = factory;
}
public void generate(JetNamespace namespace) {
final ClassVisitor v = factory.visitorForClassIn(namespace);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
final FunctionCodegen functionCodegen = new FunctionCodegen(v);
v.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC,
namespace.getFQName().replace('.', '/') + "/namespace",
null,
"jet/lang/Namespace",
new String[0]
);
for (JetDeclaration declaration : namespace.getDeclarations()) {
if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration, namespace);
}
else if (declaration instanceof JetFunction) {
functionCodegen.gen((JetFunction) declaration, namespace);
}
}
v.visitEnd();
}
}
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.objectweb.asm.ClassVisitor;
/**
* @author max
*/
public class PropertyCodegen {
private final ClassVisitor v;
public PropertyCodegen(ClassVisitor v) {
this.v = v;
}
public void gen(JetProperty p, JetNamespace owner) {
}
public void gen(JetProperty p, JetClass owner) {
}
}
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
......@@ -15,4 +17,45 @@ public class JetConstantExpression extends JetExpression {
public void accept(JetVisitor visitor) {
visitor.visitConstantExpression(this);
}
public Object getValue() {
IElementType elementType = getNode().getElementType();
String nodeText = getNode().getText();
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
return Integer.parseInt(nodeText);
}
else if (elementType == JetNodeTypes.LONG_CONSTANT) {
return Long.parseLong(nodeText);
}
else if (elementType == JetNodeTypes.FLOAT_CONSTANT) {
assert nodeText.length() > 0;
char lastChar = nodeText.charAt(nodeText.length() - 1);
if (lastChar == 'f' || lastChar == 'F') {
return Float.parseFloat(nodeText.substring(0, nodeText.length() - 1));
}
else if (lastChar == 'd' || lastChar == 'D') {
return Double.parseDouble(nodeText.substring(0, nodeText.length() - 1));
}
else {
return Double.parseDouble(nodeText);
}
}
else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) {
return Boolean.parseBoolean(nodeText);
}
else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) {
return nodeText.charAt(1);
}
else if (elementType == JetNodeTypes.STRING_CONSTANT) {
int tail = nodeText.length();
if (nodeText.endsWith("\"")) tail--;
return nodeText.substring(1, tail);
}
else if (elementType == JetNodeTypes.NULL) {
return null;
}
else {
throw new IllegalArgumentException("Unsupported constant: " + this);
}
}
}
......@@ -35,4 +35,8 @@ public class JetNamespace extends JetDeclaration {
PsiElement nameNode = findChildByType(JetNodeTypes.NAMESPACE_NAME);
return nameNode != null ? nameNode.getText() : "";
}
public String getFQName() {
return getName(); // TODO: Must include container namespace names, module root namespace
}
}
package org.jetbrains.jet.codegen;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.objectweb.asm.util.TraceMethodVisitor;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* @author max
*/
public class ExpressionGenTest extends LightDaemonAnalyzerTestCase {
public void testIntegerZeroExpression() throws Exception {
checkCode("0",
"LDC 0\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;");
}
public void testIf() throws Exception {
checkCode("if (false) 15 else 20",
"LDC false\n" +
"INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" +
"INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z\n" +
"IFEQ L0\n" +
"LDC 15\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"GOTO L1\n" +
"L0\n" +
"LDC 20\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"L1");
checkCode("if (false) 15",
"LDC false\n" +
"INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" +
"INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z\n" +
"IFEQ L0\n" +
"LDC 15\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"POP\n" +
"L0");
checkCode("if (false) else 20",
"LDC false\n" +
"INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;\n" +
"INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z\n" +
"IFNE L0\n" +
"LDC 20\n" +
"INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;\n" +
"POP\n" +
"L0");
}
private void checkCode(String expr, String expectation) throws IOException {
configureFromFileText("test.jet", "val x = " + expr);
JetProperty p = PsiTreeUtil.getParentOfType(getFile().findElementAt(0), JetProperty.class);
TraceMethodVisitor trace = new TraceMethodVisitor();
p.getInitializer().accept(new ExpressionCodegen(trace));
StringWriter out = new StringWriter();
trace.print(new PrintWriter(out));
assertEquals(trimLines(expectation), trimLines(out.getBuffer().toString()));
}
private static String trimLines(String s) {
StringBuilder b = new StringBuilder();
for (String line : s.split("\\n")) {
b.append(line.trim()).append('\n');
}
return b.toString();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册