net.sf.jame.contextfree.parser.Builder.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jame.contextfree.parser.Builder.java

Source

/*
 * JAME 6.2.1
 * http://jame.sourceforge.net
 *
 * Copyright 2001, 2016 Andrea Medeghini
 *
 * This file is part of JAME.
 *
 * JAME is an application for creating fractals and other graphics artifacts.
 *
 * JAME is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JAME 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JAME.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package net.sf.jame.contextfree.parser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Stack;

import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;

public class Builder {
    private static Builder currentBuilder;

    private CFDG cfdg = new CFDG();
    private Rand64 seed;
    private Stack<ASTRepContainer> containerStack = new Stack<ASTRepContainer>();
    private ASTRepContainer paramDecls = new ASTRepContainer();
    private Map<String, Integer> flagNames = new HashMap<String, Integer>();
    private List<StackRule> longLivedParams = new ArrayList<StackRule>();
    private Stack<String> fileNames = new Stack<String>();
    private Stack<String> filesToLoad = new Stack<String>();
    private Stack<CharStream> streamsToLoad = new Stack<CharStream>();
    private Stack<Boolean> includeNamespace = new Stack<Boolean>();
    private Stack<ASTSwitch> switchStack = new Stack<ASTSwitch>();
    private String currentNameSpace = "";
    private String currentPath;
    private String maybeVersion;
    private int currentShape;
    private int pathCount;
    private int includeDepth;
    private int localStackDepth;
    private double maxNatual;
    private boolean allowOverlap;
    private boolean inPathContainer;

    static List<String> globals = new ArrayList<String>();
    {
        globals.add("CIRCLE");
        globals.add("FILL");
        globals.add("SQUARE");
        globals.add("TRIANGLE");
    }

    public Builder() {
        containerStack.add(new ASTRepContainer());
    }

    protected void warning(String message, Token location) {
        System.out.println("[" + location.getLine() + ":" + location.getCharPositionInLine() + "] : " + message);
    }

    protected void error(String message, Token location) {
        System.err.println("[" + location.getLine() + ":" + location.getCharPositionInLine() + "] : " + message);
    }

    protected boolean isPrimeShape(int nameIndex) {
        return nameIndex < 4;
    }

    public int stringToShape(String name, boolean colonsAllowed, Token location) {
        checkName(name, colonsAllowed, location);
        if (currentNameSpace.length() == 0) {
            return cfdg.encodeShapeName(name);
        }
        int index = Collections.binarySearch(globals, name);
        String n = currentNameSpace + name;
        if (index != -1 && cfdg.tryEncodeShapeName(n) == -1) {
            return cfdg.encodeShapeName(name);
        } else {
            return cfdg.encodeShapeName(n);
        }
    }

    public String shapeToString(int shape) {
        return cfdg.decodeShapeName(shape);
    }

    public void checkName(String name, boolean colonsAllowed, Token location) {
        int pos = name.indexOf(":");
        if (pos == -1) {
            return;
        }
        if (!colonsAllowed) {
            error("namespace specification not allowed in this context", location);
            return;
        }
        if (pos == 0) {
            error("improper namespace specification", location);
            return;
        }
        for (;;) {
            if (pos == name.length() - 1 || name.charAt(pos + 1) != ':')
                break;
            int next = name.indexOf(":", pos + 2);
            if (next == -1)
                return;
            if (next == pos + 2)
                break;
            pos = next;
        }
        error("improper namespace specification", location);
    }

    public void includeFile(String fileName, Token location) {
        try {
            String path = relativeFilePath(currentPath, fileName);
            ANTLRFileStream is = new ANTLRFileStream(path);
            fileNames.push(path);
            currentPath = path;
            filesToLoad.push(currentPath);
            streamsToLoad.push(is);
            includeNamespace.push(Boolean.FALSE);
            pathCount++;
            includeDepth++;
            currentShape = -1;
            setShape(null, false, location);
            warning("Reading rules file " + path, location);
        } catch (Exception e) {
            error(e.getMessage(), location);
        }
    }

    public boolean endInclude(Token location) {
        try {
            boolean endOfInput = includeDepth == 0;
            setShape(null, false, location);
            includeDepth--;
            if (filesToLoad.isEmpty()) {
                return endOfInput;
            }
            if (includeNamespace.peek()) {
                popNameSpace();
            }
            streamsToLoad.pop();
            filesToLoad.pop();
            includeNamespace.pop();
            currentPath = filesToLoad.isEmpty() ? null : filesToLoad.peek();
            return endOfInput;
        } catch (Exception e) {
            error(e.getMessage(), location);
            return false;
        }
    }

    public void setShape(String name, Token location) {
        setShape(name, false, location);
    }

    public void setShape(String name, boolean isPath, Token location) {
        if (name == null) {
            currentShape = -1;
            return;
        }
        currentShape = stringToShape(name, false, location);
        ASTDefine def = cfdg.findFunction(currentShape);
        if (def != null) {
            error("There is a function with the same name as this shape: " + def.getLocation(), location);
            return;
        }
        String err = cfdg.setShapeParams(currentShape, paramDecls, paramDecls.getStackCount(), isPath);
        if (err != null) {
            error("cannot set shape params: " + err, location);
        }
        localStackDepth -= paramDecls.getStackCount();
        paramDecls.getParameters().clear();
        paramDecls.setStackCount(0);
    }

    public void addRule(ASTRule rule) {
        boolean isShapeItem = rule.getNameIndex() == -1;
        if (isShapeItem) {
            rule.setNameIndex(currentShape);
        } else {
            currentShape = -1;
        }
        if (rule.getNameIndex() == -1) {
            error("Shape rules/paths must follow a shape declaration", rule.getLocation());
        }
        EShapeType type = cfdg.getShapeType(rule.getNameIndex());
        if ((rule.isPath() && type == EShapeType.RuleType) || (!rule.isPath() && type == EShapeType.PathType)) {
            error("Cannot mix rules and shapes with the same name", rule.getLocation());
        }
        boolean matchesShape = cfdg.addRuleShape(rule);
        if (!isShapeItem && matchesShape) {
            error("Rule/path name matches existing shape name", rule.getLocation());
        }
    }

    public void nextParameterDecl(String type, String name, Token location) {
        int nameIndex = stringToShape(name, false, location);
        checkVariableName(nameIndex, true);
        paramDecls.addParameter(type, nameIndex, location);
        ASTParameter param = paramDecls.getParameters().get(paramDecls.getParameters().size() - 1);
        param.setStackIndex(localStackDepth);
        paramDecls.setStackCount(paramDecls.getStackCount() + param.getTupleSize());
        localStackDepth += param.getTupleSize();
    }

    public ASTDefine makeDefinition(String name, boolean isFunction, Token location) {
        if (name.startsWith("CF::")) {
            if (isFunction) {
                error("Configuration parameters cannot be functions", location);
                return null;
            }
            if (containerStack.lastElement().isGlobal()) {
                error("Configuration parameters must be at global scope", location);
                return null;
            }
            ASTDefine def = new ASTDefine(name, location);
            def.setConfigDepth(includeDepth);
            def.setDefineType(EDefineType.ConfigDefine);
            return def;
        }
        if (EFuncType.getFuncTypeByName(name) != EFuncType.NotAFunction) {
            error("Internal function names are reserved", location);
            return null;
        }
        int nameIndex = stringToShape(name, false, location);
        ASTDefine def = cfdg.findFunction(nameIndex);
        if (def != null) {
            error("Definition with same name as user function: " + def.getLocation(), location);
            return null;
        }
        checkVariableName(nameIndex, false);
        def = new ASTDefine(name, location);
        def.getShapeSpecifier().setShapeType(nameIndex);
        if (isFunction) {
            for (ASTParameter param : paramDecls.getParameters()) {
                param.setLocality(ELocality.PureNonlocal);
            }
            def.getParameters().clear();
            def.getParameters().addAll(paramDecls.getParameters());
            def.setStackCount(paramDecls.getStackCount());
            def.setDefineType(EDefineType.FunctionDefine);
            localStackDepth -= paramDecls.getStackCount();
            paramDecls.setStackCount(0);
            cfdg.declareFunction(nameIndex, def);
        } else {
            containerStack.lastElement().addDefParameter(nameIndex, def, location);
        }
        return def;
    }

    public void makeConfig(ASTDefine cfg) {
        if (cfg.getName().equals("CF::Impure")) {
            double[] v = new double[] { 0.0 };
            if (cfg.getExp() != null || cfg.getExp().isConstant() || cfg.getExp().evaluate(v, 1, null) != 1) {
                error("CF::Impure requires a constant numeric expression", cfg.getLocation());
            } else {
                ASTParameter.Impure = v[0] != 0.0;
            }
        }
        if (cfg.getName().equals("CF::AllowOverlap")) {
            double[] v = new double[] { 0.0 };
            if (cfg.getExp() != null || cfg.getExp().isConstant() || cfg.getExp().evaluate(v, 1, null) != 1) {
                error("CF::AllowOverlap requires a constant numeric expression", cfg.getLocation());
            } else {
                allowOverlap = v[0] != 0.0;
            }
        }
        if (cfg.getName().equals("CF::StartShape") && cfg.getExp() != null
                && (cfg.getExp() instanceof ASTStartSpecifier)) {
            ASTRuleSpecifier rule = null;
            ASTModification mod = null;
            List<ASTExpression> specAndMod = extract(cfg.getExp());
            switch (specAndMod.size()) {
            case 2:
                if (!(specAndMod.get(1) instanceof ASTModification)) {
                    error("CF::StartShape second term must be a modification", cfg.getLocation());
                } else {
                    mod = (ASTModification) specAndMod.get(1);
                }
                break;

            case 1:
                if (!(specAndMod.get(0) instanceof ASTRuleSpecifier)) {
                    error("CF::StartShape must start with a shape specification", cfg.getLocation());
                } else {
                    rule = (ASTRuleSpecifier) specAndMod.get(0);
                }
                break;

            default:
                error("CF::StartShape expression must have the form shape_spec or shape_spec, modification",
                        cfg.getLocation());
                break;
            }
            if (mod == null) {
                mod = new ASTModification(cfg.getLocation());
            }
            cfg.setExp(new ASTStartSpecifier(rule, mod, cfg.getLocation()));
        }
        ASTExpression current = cfg.getExp();
        if (!cfdg.addParameter(cfg.getName(), cfg.getExp(), cfg.getConfigDepth())) {
            error("Unknown configuration parameter", cfg.getLocation());
        }
        if (cfg.getName().equals("CF::MaxNatural")) {
            ASTExpression max = cfdg.hasParameter(ECFGParam.MaxNatural);
            if (max != current) {
                return;
            }
            double[] v = new double[] { -1.0 };
            if (max == null || !max.isConstant() || max.getType() != EExpType.NumericType
                    || max.evaluate(v, 1, null) != 1) {
                error("CF::MaxNatural requires a constant numeric expression", cfg.getLocation());
            } else if (v[0] < 1.0 || v[0] > 9007199254740992.0) {
                error(v[0] < 1.0 ? "CF::MaxNatural must be >= 1" : "CF::MaxNatural must be < 9007199254740992",
                        cfg.getLocation());
            } else {
                maxNatual = v[0];
            }
        }
    }

    private List<ASTExpression> extract(ASTExpression exp) {
        if (exp instanceof ASTCons) {
            return ((ASTCons) exp).getChildren();
        } else {
            List<ASTExpression> ret = new ArrayList<ASTExpression>();
            ret.add(exp);
            return ret;
        }
    }

    public ASTExpression makeVariable(String name, Token location) {
        Integer flagItem = flagNames.get(name);
        if (flagItem != null) {
            ASTReal flag = new ASTReal(flagItem, location);
            flag.setType(EExpType.FlagType);
            return flag;
        }
        if (name.startsWith("CF::")) {
            error("Configuration parameter names are reserved", location);
            return new ASTExpression(location);
        }
        if (EFuncType.getFuncTypeByName(name) != EFuncType.NotAFunction) {
            error("Internal function names are reserved", location);
            return new ASTExpression(location);
        }
        int varNum = stringToShape(name, true, location);
        boolean isGlobal = false;
        ASTParameter bound = findExpression(varNum, isGlobal);
        if (bound == null) {
            return new ASTRuleSpecifier(varNum, name, null, cfdg.getShapeParams(currentShape), location);
        }
        return new ASTVariable(varNum, name, location);
    }

    public ASTExpression makeArray(String name, ASTExpression args, Token location) {
        if (name.startsWith("CF::")) {
            error("Configuration parameter names are reserved", location);
            return args;
        }
        int varNum = stringToShape(name, true, location);
        boolean isGlobal = false;
        ASTParameter bound = findExpression(varNum, isGlobal);
        if (bound == null) {
            return args;
        }
        return new ASTArray(varNum, args, "", location);
    }

    public ASTExpression makeLet(ASTRepContainer vars, ASTExpression exp, Token location) {
        int nameIndex = stringToShape("let", false, location);
        ASTDefine def = new ASTDefine("let", location);
        def.getShapeSpecifier().setShapeType(nameIndex);
        def.setExp(exp);
        def.setDefineType(EDefineType.LetDefine);
        return new ASTLet(vars, def, location);
    }

    public ASTRuleSpecifier makeRuleSpec(String name, ASTExpression args, Token location) {
        return makeRuleSpec(name, args, null, false, location);
    }

    public ASTRuleSpecifier makeRuleSpec(String name, ASTExpression args, ASTModification mod, boolean makeStart,
            Token location) {
        if (name.equals("if") || name.equals("let") || name.equals("select")) {
            if (name.equals("select")) {
                args = new ASTSelect(args, false, location);
            }
            if (makeStart) {
                return new ASTStartSpecifier(args, mod, location);
            } else {
                return new ASTRuleSpecifier(args, location);
            }
        }
        int nameIndex = stringToShape(name, true, location);
        boolean isGlobal = false;
        ASTParameter bound = findExpression(nameIndex, isGlobal);
        if (bound != null && args != null && args.getType() == EExpType.ReuseType && !makeStart && isGlobal
                && nameIndex == currentShape) {
            error("Shape name binds to global variable and current shape, using current shape", location);
        }
        if (bound != null && bound.isParameter() && bound.getType() == EExpType.RuleType) {
            return new ASTRuleSpecifier(nameIndex, name, location);
        }
        ASTRuleSpecifier ret = null;
        cfdg.setShapeHasNoParam(nameIndex, args);
        if (makeStart) {
            ret = new ASTStartSpecifier(nameIndex, name, args, mod, location);
        } else {
            ret = new ASTRuleSpecifier(nameIndex, name, args, cfdg.getShapeParams(currentShape), location);
        }
        if (ret.getArguments() != null && ret.getArguments().getType() == EExpType.ReuseType) {
            if (makeStart) {
                error("Startshape cannot reuse parameters", location);
            } else if (nameIndex == currentShape) {
                ret.setArgSouce(EArgSource.SimpleArgs);
                ret.setTypeSignature(ret.getTypeSignature());
            }
        }
        return ret;
    }

    public void makeModTerm(ASTModification dest, ASTModTerm t, Token location) {
        if (t == null) {
            return;
        }
        if (t.getModType() == EModType.time) {
            timeWise();
        }
        if (t.getModType() == EModType.sat || t.getModType() == EModType.satTarg) {
            inColor();
        }
        dest.concat(t);
    }

    public ASTReplacement makeElement(String s, ASTModification mods, ASTExpression params, boolean subPath,
            Token location) {
        if (inPathContainer && !subPath && (s.equals("FILL") || s.equals("STROKE"))) {
            return new ASTPathCommand(s, mods, params, location);
        }
        ASTRuleSpecifier r = makeRuleSpec(s, params, null, false, location);
        ERepElemType t = ERepElemType.replacement;
        if (inPathContainer) {
            boolean isGlobal = false;
            ASTParameter bound = findExpression(r.getShapeType(), isGlobal);
            if (!subPath) {
                error("Replacements are not allowed in paths", location);
            } else if (r.getArgSource() == EArgSource.StackArgs || r.getArgSource() == EArgSource.ShapeArgs) {
                // Parameter subpaths must be all ops, but we must check at runtime
                t = ERepElemType.op;
            } else if (cfdg.getShapeType(r.getShapeType()) == EShapeType.PathType) {
                ASTRule rule = cfdg.findRule(r.getShapeType());
                if (rule != null) {
                    t = ERepElemType.typeByOrdinal(rule.getRuleBody().getRepType());
                } else {
                    error("Subpath references must be to previously declared paths", location);
                }
            } else if (bound != null) {
                // Variable subpaths must be all ops, but we must check at runtime
                t = ERepElemType.op;
            } else if (isPrimeShape(r.getShapeType())) {
                t = ERepElemType.op;
            } else {
                error("Subpath references must be to previously declared paths", location);
            }
        }
        return new ASTReplacement(r, mods, t, location);
    }

    public ASTExpression makeFunction(String name, ASTExpression args, Token location) {
        return makeFunction(name, args, false, location);
    }

    public ASTExpression makeFunction(String name, ASTExpression args, boolean consAllowed, Token location) {
        int nameIndex = stringToShape(name, true, location);
        boolean isGlobal = false;
        ASTParameter bound = findExpression(nameIndex, isGlobal);
        if (bound != null) {
            if (!consAllowed) {
                error("Cannot bind expression to variable/parameter", location);
            }
            return makeVariable(name, location).append(args);
        }
        if (name.equals("select") || name.equals("if")) {
            return new ASTSelect(args, name.equals("if"), location);
        }
        EFuncType t = EFuncType.getFuncTypeByName(name);
        if (t == EFuncType.NotAFunction) {
            return new ASTFunction(name, args, seed, location);
        }
        if (args != null && args.getType() == EExpType.ReuseType) {
            return makeRuleSpec(name, args, null, false, location);
        }
        return new ASTUserFunction(nameIndex, args, null, location);
    }

    public ASTModification makeModification(ASTModification mod, boolean canonial, Token location) {
        mod.setIsConstant(mod.getModExp().isEmpty());
        mod.setCanonical(canonial);
        mod.setLocation(location);
        return mod;
    }

    public String getTypeInfo(int nameIndex, ASTDefine[] func, List<ASTParameter>[] p) {
        func[0] = cfdg.findFunction(nameIndex);
        p[0] = cfdg.getShapeParams(nameIndex);
        return cfdg.decodeShapeName(nameIndex);
    }

    public ASTRule getRule(int nameIndex) {
        return cfdg.findRule(nameIndex);
    }

    public void pushRepContainer(ASTRepContainer c) {
        containerStack.push(c);
        processRepContainer(c);
    }

    private void processRepContainer(ASTRepContainer c) {
        c.setStackCount(0);
        for (ASTParameter param : c.getParameters()) {
            if (param.isParameter() || param.isLoopIndex()) {
                param.setStackIndex(localStackDepth);
                c.setStackCount(c.getStackCount() + param.getTupleSize());
                localStackDepth += param.getTupleSize();
            } else {
                break; // the parameters are all in front
            }
        }
    }

    public void popRepContainer(ASTReplacement r) {
        ASTRepContainer lastContainer = containerStack.lastElement();
        localStackDepth -= lastContainer.getStackCount();
        if (r != null) {
            r.setRepType(ERepElemType.typeByOrdinal(r.getRepType().ordinal() | lastContainer.getRepType()));
            if (r.getPathOp() == EPathOp.UNKNOWN) {
                r.setPathOp(lastContainer.getPathOp());
            }
        }
        containerStack.pop();
    }

    private boolean badContainer(int containerType) {
        return (containerType
                & (ERepElemType.op.ordinal() | ERepElemType.replacement.ordinal())) == (ERepElemType.op.ordinal()
                        | ERepElemType.replacement.ordinal());
    }

    public void pushRep(ASTReplacement r, boolean global) {
        if (r == null) {
            return;
        }
        ASTRepContainer container = containerStack.lastElement();
        if (container.getBody().size() > 0) {
            container.getBody().remove(container.getBody().size() - 1);
        }
        container.getBody().add(r);
        if (container.getPathOp() == EPathOp.UNKNOWN) {
            container.setPathOp(r.getPathOp());
        }
        int oldType = container.getRepType();
        container.setRepType(oldType | r.getRepType().ordinal());
        if (badContainer(container.getRepType()) && !badContainer(oldType) && !global) {
            error("Cannot mix path elements and replacements in the same container", r.getLocation());
        }
    }

    public ASTParameter findExpression(int nameIndex, boolean isGlobal) {
        for (ListIterator<ASTRepContainer> i = containerStack.listIterator(); i.hasPrevious();) {
            ASTRepContainer repCont = i.previous();
            for (ListIterator<ASTParameter> p = repCont.getParameters().listIterator(); i.hasPrevious();) {
                ASTParameter param = p.previous();
                if (param.getNameIndex() == nameIndex) {
                    isGlobal = repCont.isGlobal();
                    return param;
                }
            }
        }
        return null;
    }

    protected void checkVariableName(int nameIndex, boolean param) {
        if (allowOverlap && !param) {
            return;
        }
        ASTRepContainer repCont = param ? paramDecls : containerStack.lastElement();
        for (ListIterator<ASTParameter> i = repCont.getParameters().listIterator(); i.hasPrevious();) {
            ASTParameter p = i.previous();
            if (p.getNameIndex() == nameIndex) {
                error("Scope of name overlaps variable/parameter with same name", p.getLocation());
            }
        }
    }

    protected String relativeFilePath(String base, String rel) {
        int i = base.lastIndexOf("/");
        if (i == -1) {
            return rel;
        }
        return base.substring(0, i) + rel;
    }

    protected void popNameSpace() {
        currentNameSpace = currentNameSpace.substring(0, currentNameSpace.length() - 2);
        int end = currentNameSpace.lastIndexOf(":");
        if (end == -1) {
            currentNameSpace = "";
        } else {
            currentNameSpace.substring(0, end + 1);
        }
    }

    protected void pushNameSpace(String n, Token location) {
        if (n.equals("CF")) {
            error("CF namespace is reserved", location);
            return;
        }
        if (n.length() == 0) {
            error("zero-length namespace", location);
            return;
        }
        checkName(n, false, location);
        includeNamespace.pop();
        includeNamespace.push(Boolean.TRUE);
        currentNameSpace = currentNameSpace + n + "::";
    }

    public void inColor() {
        cfdg.addParameter(EParam.Color);
    }

    public void timeWise() {
        cfdg.addParameter(EParam.Time);
    }

    public void storeParams(StackRule p) {
        p.setRefCount(Integer.MAX_VALUE);
        longLivedParams.add(p);
    }

    public String getMaybeVersion() {
        return maybeVersion;
    }

    public void setMaybeVersion(String maybeVersion) {
        this.maybeVersion = maybeVersion;
    }

    public EExpType decodeType(String typeName, int[] tupleSize, boolean[] isNatural, Token location) {
        EExpType type;
        tupleSize[0] = 1;
        isNatural[0] = false;

        if (typeName.equals("number")) {
            type = EExpType.NumericType;
        } else if (typeName.equals("natural")) {
            type = EExpType.NumericType;
            isNatural[0] = true;
        } else if (typeName == "adjustment") {
            type = EExpType.ModType;
            tupleSize[0] = 6;
        } else if (typeName == "shape") {
            type = EExpType.RuleType;
        } else if (typeName.startsWith("vector")) {
            type = EExpType.NumericType;
            if (typeName.matches("vector[0-9]+")) {
                tupleSize[0] = Integer.parseInt(typeName.substring(6));
                if (tupleSize[0] <= 1 || tupleSize[0] > 99) {
                    error("Illegal vector size (<=1 or >99)", location);
                }
            } else {
                error("Illegal vector type specification", location);
            }
        } else {
            type = EExpType.NoType;
            error("Unrecognized type name", location);
        }
        return type;
    }

    public void setInPathContainer(boolean inPathContainer) {
        this.inPathContainer = inPathContainer;
    }

    public Stack<ASTSwitch> getSwitchStack() {
        return switchStack;
    }

    public void incSwitchStack() {
        localStackDepth--;
    }

    public void decSwitchStack() {
        localStackDepth++;
    }

    public Rand64 getSeed() {
        return seed;
    }

    public ASTRepContainer getParamDecls() {
        return paramDecls;
    }

    public static Builder currentBuilder() {
        return currentBuilder;
    }

    public int getLocalStackDepth() {
        return localStackDepth;
    }

    public boolean isInPathContainer() {
        return this.inPathContainer;
    }

    public Stack<ASTRepContainer> getContainerStack() {
        return containerStack;
    }

    public void setLocalStackDepth(int localStackDepth) {
        this.localStackDepth = localStackDepth;
    }
}