@Override public DataType visitFactor(@NotNull PythonParser.FactorContext ctx) { if (ctx.power() != null) { return visitPower(ctx.power()); } else if (ctx.factor() != null) { DataType type = visitFactor(ctx.factor()); if (type.isInteger()) { if (ctx.PLUS() != null) { return type; } else if (ctx.MINUS() != null) { mv.visitInsn(INEG); return type; } } else if (type.isBoolean()) { if (ctx.PLUS() != null) { return type; } else if (ctx.MINUS() != null) { mv.visitInsn(INEG); return PrimitiveType.INTEGER; } } else { if (ctx.PLUS() != null) { throw new CompileException( String.format("Doing %s with %s is making no sense!", ctx.PLUS().getText(), type)); } else if (ctx.MINUS() != null) { throw new CompileException( String.format("Doing %s with %s is making no sense!", ctx.MINUS().getText(), type)); } } } throw new CompileException( String.format( "Something gone wrong! Please write to [email protected] with example test.")); }
@Override public DataType visitArith_expr(@NotNull PythonParser.Arith_exprContext ctx) { DataType type = visitTerm(ctx.term(0)); int i = 1; if (!ctx.MINUS().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.MINUS().get(0).getText(), type)); } for (TerminalNode ignored : ctx.MINUS()) { type = visitTerm(ctx.term(i++)); mv.visitInsn(ISUB); } if (type.equals(PrimitiveType.BOOLEAN)) return PrimitiveType.INTEGER; } else if (!ctx.PLUS().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.PLUS().get(0).getText(), type)); } for (TerminalNode ignored : ctx.PLUS()) { type = visitTerm(ctx.term(i++)); mv.visitInsn(IADD); } if (type.equals(PrimitiveType.BOOLEAN)) return PrimitiveType.INTEGER; } return type; }
@Override public DataType visitAnd_test(@NotNull PythonParser.And_testContext ctx) { DataType type = visitNot_test(ctx.not_test(0)); if (!ctx.isEmpty() && ctx.not_test().size() > 1) { if (!type.isPrimitive()) { throw new CompileException(String.format("Doing and with %s is making no sense!", type)); } for (int i = 1; i < ctx.not_test().size(); i++) { visitNot_test(ctx.not_test(i)); Label falseLabel = new Label(); Label fastFalseLabel = new Label(); Label exitLabel = new Label(); mv.visitJumpInsn(IFEQ, fastFalseLabel); mv.visitJumpInsn(IFEQ, falseLabel); mv.visitInsn(ICONST_1); mv.visitJumpInsn(GOTO, exitLabel); mv.visitLabel(fastFalseLabel); mv.visitInsn(POP); mv.visitLabel(falseLabel); mv.visitInsn(ICONST_0); mv.visitLabel(exitLabel); } return PrimitiveType.BOOLEAN; } return type; }
@Override public DataType visitPrint_stmt(@NotNull PythonParser.Print_stmtContext ctx) { mv.visitFieldInsn( GETSTATIC, Type.getInternalName(System.class), "out", Type.getDescriptor(PrintStream.class)); DataType type = visitTest(ctx.test()); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName(PrintStream.class), "println", Type.getMethodDescriptor(Type.VOID_TYPE, type.getType()), false); return null; }
@Override public DataType visitXor_expr(@NotNull PythonParser.Xor_exprContext ctx) { DataType type = visitAnd_expr(ctx.and_expr(0)); int i = 1; if (!ctx.CIRCUMFLEX().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.CIRCUMFLEX().get(0).getText(), type)); } for (TerminalNode ignored : ctx.CIRCUMFLEX()) { type = visitAnd_expr(ctx.and_expr(i++)); mv.visitInsn(IXOR); } if (type.equals(PrimitiveType.BOOLEAN)) return PrimitiveType.INTEGER; } return type; }
@Override public DataType visitComparison(@NotNull PythonParser.ComparisonContext ctx) { DataType type = visitExpr(ctx.expr(0)); int i = 1; if (!ctx.comp_op().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.comp_op().get(0).getText(), type)); } for (PythonParser.Comp_opContext op : ctx.comp_op()) { visitExpr(ctx.expr(i++)); visitComp_op(op); } return PrimitiveType.BOOLEAN; } return type; }
@Override public DataType visitTerm(@NotNull PythonParser.TermContext ctx) { DataType type = visitFactor(ctx.factor(0)); int i = 1; if (!ctx.PERCENT().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.PERCENT().get(0).getText(), type)); } for (TerminalNode ignored : ctx.PERCENT()) { type = visitFactor(ctx.factor(i++)); mv.visitInsn(IREM); } if (type.equals(PrimitiveType.BOOLEAN)) return PrimitiveType.INTEGER; } else if (!ctx.SLASH().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.SLASH().get(0).getText(), type)); } for (TerminalNode ignored : ctx.SLASH()) { type = visitFactor(ctx.factor(i++)); mv.visitInsn(IDIV); } if (type.equals(PrimitiveType.BOOLEAN)) return PrimitiveType.INTEGER; } else if (!ctx.STAR().isEmpty()) { if (!type.isPrimitive()) { throw new CompileException( String.format( "Doing %s with %s is making no sense!", ctx.STAR().get(0).getText(), type)); } for (TerminalNode ignored : ctx.STAR()) { type = visitFactor(ctx.factor(i++)); mv.visitInsn(IMUL); } if (type.equals(PrimitiveType.BOOLEAN)) return PrimitiveType.INTEGER; } return type; }
@Override public DataType visitAtom(@NotNull PythonParser.AtomContext ctx) { // System.out.println("Zz" + ctx.NAME() + ctx.STRING()); if (ctx.test() != null) { // 1 return visitTest(ctx.test()); } else if (ctx.STRING().size() > 0) { // 7,8,9 String ss = ""; for (TerminalNode s : ctx.STRING()) { ss += s.getText(); } mv.visitLdcInsn(ss.length()); mv.visitIntInsn(NEWARRAY, T_CHAR); int tempIndex = 0; for (int i = 0; i < ss.length(); i++) { if (!("\"".equals(ss.substring(i, i + 1))) && !("\'".equals(ss.substring(i, i + 1)))) { mv.visitInsn(DUP); mv.visitLdcInsn(tempIndex); mv.visitLdcInsn(ss.charAt(i)); mv.visitInsn(CASTORE); tempIndex++; } } if (ctx.LBRACK() != null) { if (Integer.parseInt(ctx.INT().getText()) > tempIndex - 1) { throw new CompileException( String.format( "Index out of bounds exception for string %s with index %s", ss, Integer.parseInt(ctx.INT().getText()))); } mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText())); mv.visitInsn(CALOAD); mv.visitMethodInsn( INVOKESTATIC, Type.getType(String.class).getInternalName(), "valueOf", "(C)Ljava/lang/String;", false); return new StringType(1); } else { mv.visitMethodInsn( INVOKESTATIC, Type.getType(String.class).getInternalName(), "valueOf", "([C)Ljava/lang/String;", false); return new StringType(ss.length()); } } else if (!ctx.NAME().isEmpty()) { // 3,4,5 DataType type = null; // System.out.println("GG" + ctx.getText() + "GG"); String varName = ctx.NAME().get(0).getText(); if (scope.isLocalVariable(varName)) { if (ctx.LBRACK() != null) { // 4,5 type = scope.getLocalVariableType(varName); if (!(type instanceof StringType)) { throw new CompileException(String.format("Trying to take index not from string!!")); } mv.visitVarInsn(type.isPrimitive() ? ILOAD : ALOAD, scope.getLocalVariableIndex(varName)); if (ctx.INT() != null) { mv.visitMethodInsn( INVOKEVIRTUAL, Type.getType(String.class).getInternalName(), "toCharArray", "()[C", false); if (Integer.parseInt(ctx.INT().getText()) > type.getSize()) { throw new CompileException(String.format("Index out of bounds exception!")); } mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText())); mv.visitInsn(CALOAD); mv.visitMethodInsn( INVOKESTATIC, Type.getType(String.class).getInternalName(), "valueOf", "(C)Ljava/lang/String;", false); return new StringType(1); } else if (ctx.NAME(1) != null) { varName = ctx.NAME(1).getText(); type = scope.getLocalVariableType(ctx.NAME(1).getText()); if (!type.isInteger()) { throw new CompileException( String.format("Trying to take index from string not with int!")); } else { Label okLabel = new Label(); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getType(String.class).getInternalName(), "toCharArray", "()[C", false); mv.visitVarInsn(ILOAD, scope.getLocalVariableIndex(ctx.NAME(1).getText())); mv.visitInsn(DUP); mv.visitLdcInsn(type.getSize()); mv.visitInsn(SWAP); mv.visitJumpInsn(IF_ICMPGT, okLabel); mv.visitLabel(okLabel); mv.visitInsn(CALOAD); mv.visitMethodInsn( INVOKESTATIC, Type.getType(String.class).getInternalName(), "valueOf", "(C)Ljava/lang/String;", false); // TODO out of bounds a[b] // mv.visitLdcInsn("Out of bounds!"); // mv.visitMethodInsn(INVOKESPECIAL, // "java/lang/CompilerException", "<init>", // "(Ljava/lang/String;)V", false); return new StringType(1); } } else { throw new CompileException(String.format("Unidentified operation")); } } else { // 3 type = scope.getLocalVariableType(varName); mv.visitVarInsn(type.isPrimitive() ? ILOAD : ALOAD, scope.getLocalVariableIndex(varName)); } } else if (scope.isGlobalVariable(varName)) { if (ctx.LBRACK() != null) { // 4,5 type = scope.getGlobalVariableType(varName); if (!(type instanceof StringType)) { throw new CompileException(String.format("Trying to take index not from string!!")); } mv.visitFieldInsn( GETSTATIC, scope.getClassName(), varName, type.getType().getDescriptor()); if (ctx.INT() != null) { mv.visitMethodInsn( INVOKEVIRTUAL, Type.getType(String.class).getInternalName(), "toCharArray", "()[C", false); if (Integer.parseInt(ctx.INT().getText()) > type.getSize()) { throw new CompileException(String.format("Index out of bounds exception!")); } mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText())); mv.visitInsn(CALOAD); mv.visitMethodInsn( INVOKESTATIC, Type.getType(String.class).getInternalName(), "valueOf", "(C)Ljava/lang/String;", false); return new StringType(1); } else if (ctx.NAME(1) != null) { varName = ctx.NAME(1).getText(); type = scope.getLocalVariableType(ctx.NAME(1).getText()); if (!type.isInteger()) { throw new CompileException( String.format("Trying to take index from string not with int!")); } else { Label okLabel = new Label(); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getType(String.class).getInternalName(), "toCharArray", "()[C", false); mv.visitVarInsn(ILOAD, scope.getLocalVariableIndex(ctx.NAME(1).getText())); mv.visitInsn(DUP); mv.visitLdcInsn(type.getSize()); mv.visitInsn(SWAP); mv.visitJumpInsn(IF_ICMPGT, okLabel); mv.visitLabel(okLabel); mv.visitInsn(CALOAD); mv.visitMethodInsn( INVOKESTATIC, Type.getType(String.class).getInternalName(), "valueOf", "(C)Ljava/lang/String;", false); // TODO out of bounds a[b] // mv.visitLdcInsn("Out of bounds!"); // mv.visitMethodInsn(INVOKESPECIAL, // "java/lang/CompilerException", "<init>", // "(Ljava/lang/String;)V", false); return new StringType(1); } } else { throw new CompileException(String.format("Unidentified operation")); } } else { // 3 type = scope.getGlobalVariableType(varName); mv.visitFieldInsn( GETSTATIC, scope.getClassName(), varName, type.getType().getDescriptor()); } } return type; // } else if (scope.isFunction) } else if (ctx.INT() != null) { // 6 mv.visitLdcInsn(Integer.parseInt(ctx.INT().getText())); return PrimitiveType.INTEGER; } else if (ctx.BOOL() != null) { // 2 mv.visitInsn("False".equals(ctx.BOOL().getText()) ? ICONST_0 : ICONST_1); return PrimitiveType.BOOLEAN; } else { throw new CompileException(String.format("Undefined thing to work with! %s", ctx.getText())); } }
@Override public DataType visitPower(@NotNull PythonParser.PowerContext ctx) { // System.out.println("called!"); if (ctx.trailer() != null) if (ctx.atom().NAME() != null) { String name = ctx.atom().NAME(0).getText(); Integer argumentGiven = 0; String returnSignatue = "V"; String argSignature = ""; String totalSinature = ""; if (ctx.trailer().arglist() != null) { argumentGiven = ctx.trailer().arglist().argument().size(); } if (!scope.isFunctionDeclared(name)) throw new CompileException(String.format("Function %s is not defined.", name)); else { Integer argumentsCount = scope.functionArgumentCount(name); if (!argumentsCount.equals(argumentGiven)) { throw new CompileException( String.format( "Function %s takes exactly %s arguments (%s given)", name, argumentsCount, argumentGiven)); } else { if (argumentGiven == 0) { argSignature = ""; } else { int i = 0; String[] argumentsNames = scope.getFunctionArgumentsNames(name, argumentGiven); for (PythonParser.ArgumentContext argctx : ctx.trailer().arglist().argument()) { DataType argType = visitArgument(argctx); argSignature += argType.getType().getDescriptor(); // System.out.println("Хуйня тут" + argType + argumentsNames[i]); scope.addLocalVariable(argumentsNames[i], argType); // int opcode = // scope.getLocalVariableType(argumentsNames[i]).isPrimitive() ? ISTORE : ASTORE; // mv.visitVarInsn(opcode, // scope.getLocalVariableIndex(argumentsNames[i])); i++; } } totalSinature = "(" + argSignature + ")" + returnSignatue; System.out.println("ACTION!" + totalSinature); MethodVisitor mvSave = mv; mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, name, totalSinature, null, null); visitSuite(scope.getFunctionSuite(name, argumentGiven)); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); scope.setMethodName(name); scope.refreshLocalVariables(); mv = mvSave; mv.visitMethodInsn(INVOKESTATIC, scope.getClassName(), name, totalSinature, false); } } // //TODO function with () call {a()} + default values // DataType returnType = scope.getFunctionReturnType(name, argumentType); // mv.visitMethodInsn(INVOKESTATIC, scope.getClassName(), name, // Utils.getFunctionDescriptor(returnType, argumentType), false); // System.out.println("called!"); return null; } else { throw new CompileException( String.format("%s object is not callable!", ctx.atom().getText())); } return visitAtom(ctx.atom()); }
@Override public DataType visitExpr_stmt(@NotNull PythonParser.Expr_stmtContext ctx) { if (ctx.power() != null) { if (ctx.power().atom().NAME() != null && ctx.power().atom().STRING().size() == 0) { String var = ctx.power().atom().NAME().get(0).getText(); if (ctx.power().atom().LBRACK() != null) { if (scope.isLocalVariable(var)) { if (!(scope.getLocalVariableType(var) instanceof StringType)) { throw new CompileException(String.format("Trying to take index not from string!")); } } else if (scope.isGlobalVariable(var)) { if (!(scope.getGlobalVariableType(var) instanceof StringType)) { throw new CompileException(String.format("Trying to take index not from string!")); } } throw new CompileException( String.format("Assigning to element of String is not implemented yet!")); // if (ctx.power().atom().INT() != null) { // // } else { // // } } else { if (ctx.test() != null) { if (ctx.power().trailer() != null) { throw new CompileException(String.format("Can't assign to function!")); } DataType etype = visitTest(ctx.test()); if (scope.isLocalVariable(var)) { // System.out.println("LOCAL" + var + "e" + etype + "e" + // scope.getLocalVariableType(var) ); if (etype.equals(scope.getLocalVariableType(var))) { // System.out.println("Type not changing!"); int opcode = scope.getLocalVariableType(var).isPrimitive() ? ISTORE : ASTORE; mv.visitVarInsn(opcode, scope.getLocalVariableIndex(var)); } else { // System.out.println("Type changing!"); scope.changeLocalVariableType(var, etype); int opcode = etype.isPrimitive() ? ISTORE : ASTORE; mv.visitVarInsn(opcode, scope.getLocalVariableIndex(var)); } } else if (scope.isGlobalVariable(var)) { DataType vtype = scope.getGlobalVariableType(var); mv.visitFieldInsn( PUTSTATIC, scope.getClassName(), var, vtype.getType().getDescriptor()); // } else if (scope.isFunctionDeclared(var)) { TODO } else { scope.addLocalVariable(var, etype); int opcode = scope.getLocalVariableType(var).isPrimitive() ? ISTORE : ASTORE; mv.visitVarInsn(opcode, scope.getLocalVariableIndex(var)); // throw new CompileException(String.format("Variable %s not found in context %s.", // var, ctx.getText())); } return etype; } else if (ctx.power().trailer() != null) { // is function visitPower(ctx.power()); // if // (!scope.isFunctionDeclared(ctx.power().atom().NAME(0).getText(), // ctx.power().trailer().arglist().argument().size())) // throw new CompileException(String.format("Function %s not // defined.", var)); // else // System.out.println("ACTION!"); } else if (scope.isLocalVariable(var)) { return scope.getLocalVariableType(var); } else if (scope.isGlobalVariable(var)) { return scope.getGlobalVariableType(var); } else throw new CompileException(String.format("Variable %s not defined.", var)); } } else { throw new CompileException(String.format("can't assign to operator")); } } else { System.out.println("Something bad happened!"); } return null; }