All Downloads are FREE. Search and download functionalities are using the official Maven repository.

webit.script.core.VariantManager Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
// Copyright (c) 2013, Webit Team. All Rights Reserved.
package webit.script.core;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import webit.script.Engine;
import webit.script.exceptions.ParseException;
import webit.script.global.GlobalManager;
import webit.script.util.StringUtil;
import webit.script.util.collection.ArrayStack;
import webit.script.util.collection.Stack;

/**
 *
 * @author Zqq
 */
public class VariantManager {

    private Map[] elements;
    private int currentElementIndex;
    private final Stack varWallStack;

    private final GlobalManager globalManager;

    @SuppressWarnings("unchecked")
    public VariantManager(Engine engine) {
        this.varWallStack = new ArrayStack();
        this.globalManager = engine.getGlobalManager();

        this.elements = new Map[10];
        Map root = elements[0] = createNewMap(); //current
        String[] vars;
        if ((vars = engine.getVars()) != null) {
            String var;
            for (int i = 0, len = vars.length; i < len; i++) {
                var = vars[i];
                if (!root.containsKey(var)) {
                    root.put(var, root.size());
                }//ignore duplicate
            }
        }

        currentElementIndex = 0;
        pushVarWall();
    }

    public final void pushVarWall() {
        varWallStack.push(new VarWall(currentElementIndex));
    }

    public int[] popVarWall() {
        return varWallStack.pop().getOverflowUpstairs();
    }

    @SuppressWarnings("unchecked")
    public void push() {
        final int i;
        Map[] _elements;
        if ((i = ++currentElementIndex) >= (_elements = elements).length) {
            System.arraycopy(_elements, 0,
                    _elements = elements = new Map[i << 1], 0, i);
        }
        _elements[i] = createNewMap();
    }

    protected final Map createNewMap() {
        return new HashMap();
    }

    public void checkVarWall(int index) {
        for (int i = 0, len = varWallStack.size(); i < len; i++) {
            if (varWallStack.peek(i).checkOverflow(index) == false) {
                break;
            }
        }
    }

    public Map pop() {
        int index;
        if ((index = currentElementIndex--) >= 0) {
            Map element = elements[index];
            elements[index] = null;
            return element;
        } else {
            throw new ParseException("Variant stack overflow");
        }
    }

    public VarAddress assignVariantAddress(String name, int line, int column) {
        return VarAddress.context(0, assignVariant(name, line, column), currentElementIndex == 0);
    }

    public int assignVariant(String name, int line, int column) {
        Map current;
        if (!(current = elements[currentElementIndex]).containsKey(name)) {
            int address;
            current.put(name, (address = current.size()));
            return address;
        } else {
            throw new ParseException("Duplicate Variant declare: ".concat(name), line, column);
        }
    }

    public VarAddress assignVariantAtRoot(final String name, int line, int column) {
        //int topindex = varWallStack.peek().value;
        final Map top;
        if ((top = elements[0]).containsKey(name)) {
            throw new ParseException("Duplicate Variant declare: ".concat(name), line, column);
        }
        checkVarWall(0);
        final int address;
        top.put(name, address = top.size());
        return VarAddress.context(currentElementIndex, address, true);
    }

    public VarAddress locateAtUpstair(String name, int upstair, int line, int column) {
        if (upstair <= currentElementIndex) {
            final int i = currentElementIndex - upstair;
            Integer index;
            if ((index = elements[i].get(name)) != null) {
                checkVarWall(i);
                return VarAddress.context(currentElementIndex - i, index, i == 0);
            }
            throw new ParseException("Can't locate variant: ".concat(name), line, column);
        } else {
            throw new ParseException(StringUtil.concat("Stack overflow when locate variant in given upstair: ", name, "-", Integer.toString(upstair)), line, column);
        }
    }

    public VarAddress locate(String name, int fromUpstair, boolean force, int line, int column) {
        for (int i = currentElementIndex - fromUpstair; i >= 0; --i) {
            Integer index;
            if ((index = elements[i].get(name)) != null) {
                checkVarWall(i);
                return VarAddress.context(currentElementIndex - i, index, i == 0);
            }
        }

        int index;
        if ((index = this.globalManager.getVariantIndex(name)) >= 0) {
            return VarAddress.global(index);
        } else if (this.globalManager.hasConst(name)) {
            return VarAddress.constValue(this.globalManager.getConst(name));
        }

        if (force) {
            throw new ParseException("Can't locate variant: ".concat(name), line, column);
        } else {
            return assignVariantAtRoot(name, line, column);
        }
    }

    private static class VarWall {

        int value;
        TreeSet overflowUpstairSet;

        VarWall(int value) {
            this.value = value;
            this.overflowUpstairSet = new TreeSet();
        }

        public boolean checkOverflow(int index) {
            if (index < value) {
                overflowUpstairSet.add(value - index - 1);
                return true;
            } else {
                return false;
            }
        }

        public int[] getOverflowUpstairs() {
            int[] overflowUpstairs = new int[overflowUpstairSet.size()];
            int i = 0;
            Iterator it = overflowUpstairSet.iterator();
            while (it.hasNext()) {
                overflowUpstairs[i++] = it.next();
            }
            return overflowUpstairs;
        }
    }

    public static class VarAddress {

        public final static int CONTEXT = 0;
        public final static int ROOT = 1;
        public final static int GLOBAL = 2;
        public final static int CONST = 3;

        public final int upstairs;
        public final int index;
        public final int type;
        public final Object constValue;

        public VarAddress(int upstairs, int index, int type, Object constValue) {
            this.upstairs = upstairs;
            this.index = index;
            this.type = type;
            this.constValue = constValue;
        }

        public static VarAddress context(int upstairs, int index, boolean isRoot) {
            return new VarAddress(upstairs, index, isRoot ? ROOT : CONTEXT, null);
        }

        public static VarAddress global(int index) {
            return new VarAddress(-1, index, GLOBAL, null);
        }

        public static VarAddress constValue(Object value) {
            return new VarAddress(-1, -1, CONST, value);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy