Package com.googlecode.aviator.code

Source Code of com.googlecode.aviator.code.OptimizeCodeGenerator

/**
*  Copyright (C) 2010 dennis zhuang (killme2008@gmail.com)
*
*  This library is free software; you can redistribute it and/or modify
*  it under the terms of the GNU Lesser General Public License as published
*  by the Free Software Foundation; either version 2.1 of the License, or
*  (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
**/
package com.googlecode.aviator.code;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.LiteralExpression;
import com.googlecode.aviator.code.asm.ASMCodeGenerator;
import com.googlecode.aviator.lexer.token.DelegateToken;
import com.googlecode.aviator.lexer.token.NumberToken;
import com.googlecode.aviator.lexer.token.OperatorToken;
import com.googlecode.aviator.lexer.token.OperatorType;
import com.googlecode.aviator.lexer.token.PatternToken;
import com.googlecode.aviator.lexer.token.StringToken;
import com.googlecode.aviator.lexer.token.Token;
import com.googlecode.aviator.lexer.token.Variable;
import com.googlecode.aviator.lexer.token.DelegateToken.DelegateTokenType;
import com.googlecode.aviator.lexer.token.Token.TokenType;
import com.googlecode.aviator.runtime.type.AviatorBoolean;
import com.googlecode.aviator.runtime.type.AviatorDouble;
import com.googlecode.aviator.runtime.type.AviatorLong;
import com.googlecode.aviator.runtime.type.AviatorNil;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorPattern;
import com.googlecode.aviator.runtime.type.AviatorString;


/**
* Optimized code generator
*
* @author dennis
*
*/
public class OptimizeCodeGenerator implements CodeGenerator {
    private final ASMCodeGenerator asmCodeGenerator;

    private final List<Token<?>> tokenList = new ArrayList<Token<?>>();

    private boolean trace = false;


    public OptimizeCodeGenerator(ClassLoader classLoader, boolean trace) {
        asmCodeGenerator = new ASMCodeGenerator(AviatorEvaluator.getAviatorClassLoader(), trace);
        this.trace = trace;

    }


    private Map<Integer, DelegateTokenType> getIndex2DelegateTypeMap(OperatorType opType) {
        Map<Integer, DelegateTokenType> result = new HashMap<Integer, DelegateTokenType>();
        switch (opType) {
        case AND:
            result.put(2, DelegateTokenType.And_Left);
            break;
        case OR:
            result.put(2, DelegateTokenType.Join_Left);
            break;
        case TERNARY:
            result.put(4, DelegateTokenType.Ternary_Boolean);
            result.put(2, DelegateTokenType.Ternary_Left);
            break;
        }
        return result;
    }


    private int execute() {
        int exeCount = 0;
        final int size = tokenList.size();
        printTokenList();
        for (int i = 0; i < size; i++) {
            Token<?> token = tokenList.get(i);
            if (token.getType() == TokenType.Operator) {
                final OperatorToken op = (OperatorToken) token;
                final OperatorType operatorType = op.getOperatorType();
                final int operandCount = operatorType.getOperandCount();
                switch (operatorType) {
                case FUNC:
                case INDEX:
                    // Could not optimize function and index call
                    break;
                default:
                    Map<Integer, DelegateTokenType> index2DelegateType = getIndex2DelegateTypeMap(operatorType);
                    final int result = executeOperator(i, operatorType, operandCount, index2DelegateType);
                    if (result < 0) {
                        compactTokenList();
                        return exeCount;
                    }
                    exeCount += result;
                    break;
                }

            }
        }
        compactTokenList();
        return exeCount;
    }


    private int executeOperator(int operatorIndex, final OperatorType operatorType, int operandCount,
            Map<Integer, DelegateTokenType> index2DelegateType) {
        Token<?> token = null;
        operandCount += index2DelegateType.size();
        // check if literal expression can be executed
        boolean canExecute = true;
        // operand count
        int count = 0;
        // operand start index
        int operandStartIndex = -1;
        for (int j = operatorIndex - 1; j >= 0; j--) {
            token = tokenList.get(j);
            if (token == null) {
                // we must compact token list and retry executing
                return -1;
            }
            final TokenType tokenType = token.getType();
            // Check if operand is a literal operand
            if (!isLiteralOperand(token, tokenType, count + 1, index2DelegateType)) {
                canExecute = false;
                break;
            }
            count++;

            if (count == operandCount) {
                operandStartIndex = j;
                break;
            }
        }

        // if we can execute it on compile
        if (canExecute) {
            // arguments
            AviatorObject[] args = new AviatorObject[operandCount];
            int index = 0;
            for (int j = operandStartIndex; j < operatorIndex; j++) {
                token = tokenList.get(j);
                if (token.getType() == TokenType.Delegate) {
                    tokenList.set(j, null);
                    continue;
                }
                args[index++] = getAviatorObjectFromToken(token);
                // set argument token to null
                tokenList.set(j, null);

            }
            // execute it now
            AviatorObject result = operatorType.eval(args);
            // set result as token to tokenList for next executing
            tokenList.set(operatorIndex, getTokenFromOperand(result));
            return 1;
        }
        return 0;
    }


    private boolean isLiteralOperand(Token<?> token, final TokenType tokenType, int index,
            Map<Integer, DelegateTokenType> index2DelegateType) {
        switch (tokenType) {
        case Variable:
            return token == Variable.TRUE || token == Variable.FALSE || token == Variable.NIL;
        case Delegate:
            DelegateTokenType targetDelegateTokenType = index2DelegateType.get(index);
            if (targetDelegateTokenType != null) {
                return targetDelegateTokenType == ((DelegateToken) token).getDelegateTokenType();
            }
            break;
        case Char:
        case Number:
        case Pattern:
        case String:
            return true;
        }
        return false;
    }


    private boolean isLiteralToken(Token<?> token) {
        switch (token.getType()) {
        case Variable:
            return token == Variable.TRUE || token == Variable.FALSE || token == Variable.NIL;
        case Char:
        case Number:
        case Pattern:
        case String:
            return true;
        }
        return false;
    }


    /**
     * Get token from executing result
     *
     * @param operand
     * @return
     */
    private Token<?> getTokenFromOperand(AviatorObject operand) {
        Token<?> token = null;
        switch (operand.getAviatorType()) {
        case Boolean:
            token = operand.booleanValue(null) ? Variable.TRUE : Variable.FALSE;
            break;
        case Nil:
            token = Variable.NIL;
            break;
        case Number:
            final Number value = (Number) operand.getValue(null);
            token = new NumberToken(value, value.toString());
            break;
        case String:
            final String str = (String) operand.getValue(null);
            token = new StringToken(str, -1);
            break;
        case Pattern:
            token = new PatternToken(((AviatorPattern) operand).getPattern().pattern(), -1);
            break;
        }
        return token;
    }


    private void compactTokenList() {
        Iterator<Token<?>> it = this.tokenList.iterator();
        while (it.hasNext()) {
            if (it.next() == null) {
                it.remove();
            }
        }
    }


    private AviatorObject getAviatorObjectFromToken(Token<?> lookhead) {
        AviatorObject result = null;
        switch (lookhead.getType()) {
        case Number:
            // load numbers
            NumberToken numberToken = (NumberToken) lookhead;
            if (numberToken.getNumber() instanceof Double) {
                result = AviatorDouble.valueOf(numberToken.getNumber());
            }
            else {
                result = AviatorLong.valueOf(numberToken.getNumber());
            }
            break;
        case String:
            // load string
            result = new AviatorString((String) lookhead.getValue(null));
            break;
        case Pattern:
            // load pattern
            result = new AviatorPattern((String) lookhead.getValue(null));
            break;
        case Variable:
            if (lookhead == Variable.TRUE) {
                result = AviatorBoolean.TRUE;
            }
            else if (lookhead == Variable.FALSE) {
                result = AviatorBoolean.FALSE;
            }
            else if (lookhead == Variable.NIL) {
                result = AviatorNil.NIL;
            }
            break;
        case Char:
            result = new AviatorPattern(String.valueOf(lookhead.getValue(null)));
            break;
        }
        return result;
    }


    public Expression getResult() {
        // execute literal expression
        while (execute() > 0) {
            ;
        }

        // call asm to generate byte codes
        callASM();

        // Last token is a literal token,then return a LiteralExpression
        if (tokenList.size() <= 1) {
            if (tokenList.isEmpty()) {
                return new LiteralExpression(null);
            }
            final Token<?> lastToken = tokenList.get(0);
            if (isLiteralToken(lastToken)) {
                return new LiteralExpression(getAviatorObjectFromToken(lastToken).getValue(null));
            }
        }

        // get result from asm
        return asmCodeGenerator.getResult();
    }


    private void callASM() {
        for (int i = 0; i < tokenList.size(); i++) {
            Token<?> token = tokenList.get(i);
            switch (token.getType()) {
            case Operator:
                OperatorToken op = (OperatorToken) token;

                switch (op.getOperatorType()) {
                case ADD:
                    this.asmCodeGenerator.onAdd(token);
                    break;
                case SUB:
                    this.asmCodeGenerator.onSub(token);
                    break;
                case MULT:
                    this.asmCodeGenerator.onMult(token);
                    break;
                case DIV:
                    this.asmCodeGenerator.onDiv(token);
                    break;
                case MOD:
                    this.asmCodeGenerator.onMod(token);
                    break;
                case EQ:
                    this.asmCodeGenerator.onEq(token);
                    break;
                case NEQ:
                    this.asmCodeGenerator.onNeq(token);
                    break;
                case LT:
                    this.asmCodeGenerator.onLt(token);
                    break;
                case LE:
                    this.asmCodeGenerator.onLe(token);
                    break;
                case GT:
                    this.asmCodeGenerator.onGt(token);
                    break;
                case GE:
                    this.asmCodeGenerator.onGe(token);
                    break;
                case NOT:
                    this.asmCodeGenerator.onNot(token);
                    break;
                case NEG:
                    this.asmCodeGenerator.onNeg(token);
                    break;
                case AND:
                    this.asmCodeGenerator.onAndRight(token);
                    break;
                case OR:
                    this.asmCodeGenerator.onJoinRight(token);
                    break;
                case FUNC:
                    this.asmCodeGenerator.onMethodInvoke(token);
                    break;
                case INDEX:
                    this.asmCodeGenerator.onElementEnd(token);
                    break;
                case MATCH:
                    this.asmCodeGenerator.onMatch(token);
                    break;
                case TERNARY:
                    this.asmCodeGenerator.onTernaryRight(token);
                    break;
                }
                break;
            case Delegate:
                DelegateToken delegateToken = (DelegateToken) token;
                final Token<?> realToken = delegateToken.getToken();
                switch (delegateToken.getDelegateTokenType()) {
                case And_Left:
                    this.asmCodeGenerator.onAndLeft(realToken);
                    break;
                case Join_Left:
                    this.asmCodeGenerator.onJoinLeft(realToken);
                    break;
                case Element_Start:
                    this.asmCodeGenerator.onElementStart(realToken);
                    break;
                case Ternary_Boolean:
                    this.asmCodeGenerator.onTernaryBoolean(realToken);
                    break;
                case Ternary_Left:
                    this.asmCodeGenerator.onTernaryLeft(realToken);
                    break;
                case Method_Name:
                    this.asmCodeGenerator.onMethodName(realToken);
                    break;
                case Method_Param:
                    this.asmCodeGenerator.onMethodParameter(realToken);
                    break;
                }
                break;

            default:
                this.asmCodeGenerator.onConstant(token);
                break;
            }

        }
    }


    private void printTokenList() {
        if (trace) {
            for (Token<?> t : tokenList) {
                System.out.print(t.getLexeme() + " ");
            }
            System.out.println();
        }
    }


    public void onAdd(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.ADD));

    }


    public void onAndLeft(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.And_Left));
    }


    public void onAndRight(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.AND));

    }


    public void onConstant(Token<?> lookhead) {
        tokenList.add(lookhead);
    }


    public void onDiv(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.DIV));

    }


    public void onElementEnd(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.INDEX));
    }


    public void onElementStart(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.Element_Start));

    }


    public void onEq(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.EQ));

    }


    public void onGe(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.GE));

    }


    public void onGt(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.GT));

    }


    public void onJoinLeft(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.Join_Left));
    }


    public void onJoinRight(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.OR));

    }


    public void onLe(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.LE));

    }


    public void onLt(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.LT));

    }


    public void onMatch(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.MATCH));

    }


    public void onMethodInvoke(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.FUNC));

    }


    public void onMethodName(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.Method_Name));

    }


    public void onMethodParameter(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.Method_Param));

    }


    public void onMod(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.MOD));

    }


    public void onMult(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.MULT));

    }


    public void onNeg(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.NEG));

    }


    public void onNeq(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.NEQ));

    }


    public void onNot(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.NOT));

    }


    public void onSub(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.SUB));

    }


    public void onTernaryBoolean(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.Ternary_Boolean));

    }


    public void onTernaryLeft(Token<?> lookhead) {
        tokenList.add(new DelegateToken(lookhead == null ? -1 : lookhead.getStartIndex(), lookhead,
            DelegateTokenType.Ternary_Left));

    }


    public void onTernaryRight(Token<?> lookhead) {
        tokenList.add(new OperatorToken(lookhead == null ? -1 : lookhead.getStartIndex(), OperatorType.TERNARY));
    }

}
TOP

Related Classes of com.googlecode.aviator.code.OptimizeCodeGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.