マイペースなプログラミング日記

x86エミュレータやFPGA、WebGLにお熱なd-kamiがマイペースに書くブログ

System.out.printlnと書きたくない君へ

以前、JavaのSystem.out.printlnと書くのが面倒だという人がいた。なので、System.out.print系を書かずにHello Worldを出力するプログラムを考えてみた。

public class Test{
    public static void main(String[] args){
        throw new RuntimeException("Hello World");
    }
}

ああ、嘘です。ごめんなさい。他にもいくつか考えたけど、もっと真面目にやります。ではどうぞ↓。ほら、System.out.printlnどころかSystemとすら書かずに標準出力にメッセージが!勿論、System.out.printlnを使ってるんだけどね!

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException ;

import java.util.Stack;

public class Hello{
    private static final char[] SOURCE;
    
    static{
        StringBuilder builder = new StringBuilder();
        builder.append("auiiiiiiiaiiiiaiiiiiiiiiiiaiiiiiiiiiiiai");
        builder.append("iiiiiiiiiiiiiauddddddddddddddddddddddddd");
        builder.append("ddddddddauiiiiiiiiiiiiiiiiiiiiiiaiiiiiii");
        builder.append("iiiiiiiaiiiiiiiiiiiiiiiiiaiiiiiiiiiiiaii");
        builder.append("ipnipaiiiiiiiiiiiiiiiaiiiiiiiiiiiiiiiiia");
        builder.append("iiiiiiiiaiiiiiiiiiiiiiaiiiiiiiiiiiiiiiii");
        builder.append("iiaiiiiiiiiiiiaiiiiiiiiiiiiipaiiiiiiiiia");
        builder.append("aiiiiiiiiiiiiiiiiiiiiiaauddddddddddddddd");
        builder.append("ddddaiiiiiiiiaiiiiiiiiiiiiiiaudddddddddd");
        builder.append("dddddddddauiiiiiiiiiiiiiiiaiiiiiiiiiiiii");
        builder.append("iiiiaiiiiiiiiaiiiiiiiiiiiiiaiiiiiiiiiiii");
        builder.append("iiiiiiiauiiiiiiiiiiiiiiiiiiaiiiiiiiiiiii");
        builder.append("iiiiiiiaiiiiiiiiiiiiiiiiiaiiiiaaiiiiiiii");
        builder.append("iiiipaiiiiiiiiiiiiiiaiiiiiiiiiiiiiiiiiii");
        builder.append("iaiiiiiiiiiiiiiiiiiiipaiiiiiiiiiaaiiiiii");
        builder.append("iiiiiiiiiiiiiiiaaudddddddddddddddddddaii");
        builder.append("iiiiiiiiiaaiiiiiiiiiiiiiaiiiiiiauddddddd");
        builder.append("ddddddddddddauiiiiiiiiiiiiiiiiiiaiiiiiii");
        builder.append("iiiiiiiiiiiiiiiiiaiiiiiiiiiiiiiiiiiiaiii");
        builder.append("iiiiiiiiiiiiiiiiaiiiiaiiiiiiiiiiiipgm");
        SOURCE = builder.toString().toCharArray();
    }
    
    public static void main(String[] args) throws Exception{
        Hello.execute(Hello.SOURCE);
    }

    private static void execute(char[] program) throws Exception{
        int index = 0;
        char[] text = new char[4096];        
        int textIndex = -1;
        int number = -1;
        Stack<Object> stack = new Stack<Object>();
        
        while(index != program.length){
            switch(program[index]){

                case 'a':
                    textIndex++;
                    text[textIndex] = 'a';
                    break;

                case 'n':
                    textIndex = -1;
                    number = 0;
                    break;

                case 'x':
                    textIndex = -1;
                    number = Integer.MAX_VALUE;
                    break;

                case 'i':
                    if(textIndex > -1){
                        text[textIndex]++;
                    }else{
                        number++;
                    }
                
                        break;

                case 'd':
                    if(textIndex > -1){
                        text[textIndex]--;
                    }else{
                        number--;
                    }
                    break;

                case 'u':
                    text[textIndex] = Character.toUpperCase(text[textIndex]);
                    break;

                case 'l':
                    text[textIndex] = Character.toLowerCase(text[textIndex]);
                    break;

                case 'p':
                    if(textIndex > -1){
                        stack.push(new String(text, 0, textIndex + 1));
                        textIndex = -1;
                    }
                    else{
                        stack.push(number);
                        number = -1;
                    }

                    break;

                case 'o':
                    stack.pop();
                    break;

                case 'c':
                   stack.push(Hello.callConstructor(stack));
                   break;

                case 'm':
                    stack.push( Hello.invokeMethod(stack, false));
                    break;

                case 's':
                    stack.push( Hello.invokeMethod(stack, true));
                    break;

                case 'f':
                    stack.push(Hello.getField(stack, false));
                    break;

                case 'g':
                    stack.push( Hello.getField(stack, true));
                    break;

                default:
                    break;
            }

            index++;
        }
    }

    private static Object callConstructor(Stack<Object> stack)
            throws ClassNotFoundException,  NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        String className = stack.pop().toString();

        String parameter = stack.pop().toString();
        int parameterCount = 0;
        if(parameter.equals("type")){
            parameterCount = Integer.parseInt(stack.pop().toString());
            return Hello.callConstructorWithType(stack, className, parameterCount);
        }else{
            parameterCount = Integer.parseInt(parameter);
            return Hello.callConstructorWithoutType(stack, className, parameterCount);
        }
    }

    private static Object callConstructorWithType(Stack<Object> stack, String className, int parameterCount)
          throws ClassNotFoundException,  NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Class<?>[] types = new Class<?>[parameterCount];
        Object[] args = new Object[parameterCount];

       for(int i = 0; i < parameterCount; i++){
            types[i] = Class.forName(stack.pop().toString());
        }

        for(int i = 0; i < parameterCount; i++){
            args[i] = stack.pop();;
        }

        return Hello.callConstructor(className, types, args);
    }

    private static Object callConstructorWithoutType(Stack<Object> stack, String className, int parameterCount)
            throws ClassNotFoundException,  NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Class<?>[] types = new Class<?>[parameterCount];
        Object[] args = new Object[parameterCount];

        for(int i = 0; i < parameterCount; i++){
            Object arg = stack.pop();
            types[i] = arg.getClass();
            args[i] = arg;
        }

        return Hello.callConstructor(className, types, args);
    }

    private static Object callConstructor(String className, Class<?>[] types, Object[] args)
            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Class<?> clazz = Class.forName(className);

        Constructor constructor = clazz.getConstructor(types);
        return constructor.newInstance(args);
    }

    private static Object invokeMethod(Stack<Object> stack, boolean isStatic)
             throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Object target = null;
        if(!isStatic)
            target = stack.pop();

        String className = stack.pop().toString();
        String methodName = stack.pop().toString();

        String parameter = stack.pop().toString();
        int parameterCount = 0;
        if(parameter.equals("type")){
            parameterCount = Integer.parseInt(stack.pop().toString());
            return Hello.invokeMethodWithType(stack, target, className, methodName, parameterCount);
        }else{
            parameterCount = Integer.parseInt(parameter);
            return Hello.invokeMethodWithoutType(stack, target, className, methodName, parameterCount);
        }
    }

    private static Object invokeMethodWithType(Stack<Object> stack, Object target, String className, String methodName, int parameterCount)
            throws ClassNotFoundException,  NoSuchMethodException, IllegalAccessException, InvocationTargetException{

        Class<?>[] types = new Class<?>[parameterCount];
        Object[] args = new Object[parameterCount];

       for(int i = 0; i < parameterCount; i++){
            types[i] = Class.forName(stack.pop().toString());
        }

        for(int i = 0; i < parameterCount; i++){
            args[i] = stack.pop();;
        }

        return Hello.invokeMethod(className, target, methodName, types, args);
    }

    private static Object invokeMethodWithoutType(Stack<Object> stack, Object target, String className, String methodName, int parameterCount)
            throws ClassNotFoundException,  NoSuchMethodException, IllegalAccessException, InvocationTargetException{

        Class<?>[] types = new Class<?>[parameterCount];
        Object[] args = new Object[parameterCount];

        for(int i = 0; i < parameterCount; i++){
            Object arg = stack.pop();
            types[i] = arg.getClass();
            args[i] = arg;
        }

        return Hello.invokeMethod(className, target, methodName, types, args);
    }

    private static Object invokeMethod(String className, Object target, String methodName, Class<?>[] types, Object[] args)
              throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Class<?> clazz = Class.forName(className);

        Method method = clazz.getMethod(methodName, types);
        return method.invoke(target, args);
    }

   private static Object getField(Stack<Object> stack, boolean isStatic)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException{

       Object target = null;
       if(!isStatic)
           target = stack.pop();

       String className = stack.pop().toString();
       String fieldName = stack.pop().toString();

       return Hello.getField(className, target, fieldName);
   }

    private static Object getField(String className, Object target, String fieldName)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException{

        Class<?> clazz = Class.forName(className);
        Field field = clazz.getField(fieldName);
        return field.get(target);
    }
}