org.overture.codegen.vdm2java.JavaFormat.java Source code

Java tutorial

Introduction

Here is the source code for org.overture.codegen.vdm2java.JavaFormat.java

Source

/*
 * #%~
 * VDM Code Generator
 * %%
 * Copyright (C) 2008 - 2014 Overture
 * %%
 * This program 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.
 * 
 * This program 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 this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #~%
 */
package org.overture.codegen.vdm2java;

import java.io.StringWriter;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.overture.ast.types.PType;
import org.overture.codegen.assistant.TypeAssistantCG;
import org.overture.codegen.cgast.INode;
import org.overture.codegen.cgast.SExpCG;
import org.overture.codegen.cgast.SStateDesignatorCG;
import org.overture.codegen.cgast.SStmCG;
import org.overture.codegen.cgast.STypeCG;
import org.overture.codegen.cgast.analysis.AnalysisException;
import org.overture.codegen.cgast.declarations.AClassDeclCG;
import org.overture.codegen.cgast.declarations.AFormalParamLocalParamCG;
import org.overture.codegen.cgast.declarations.AInterfaceDeclCG;
import org.overture.codegen.cgast.declarations.AMethodDeclCG;
import org.overture.codegen.cgast.declarations.ANamedTypeDeclCG;
import org.overture.codegen.cgast.declarations.ATypeDeclCG;
import org.overture.codegen.cgast.declarations.AVarDeclCG;
import org.overture.codegen.cgast.expressions.AAbsUnaryExpCG;
import org.overture.codegen.cgast.expressions.AApplyExpCG;
import org.overture.codegen.cgast.expressions.ABoolLiteralExpCG;
import org.overture.codegen.cgast.expressions.ACastUnaryExpCG;
import org.overture.codegen.cgast.expressions.AEnumMapExpCG;
import org.overture.codegen.cgast.expressions.AEqualsBinaryExpCG;
import org.overture.codegen.cgast.expressions.AFieldNumberExpCG;
import org.overture.codegen.cgast.expressions.AHeadUnaryExpCG;
import org.overture.codegen.cgast.expressions.AHistoryExpCG;
import org.overture.codegen.cgast.expressions.AIsolationUnaryExpCG;
import org.overture.codegen.cgast.expressions.AMapletExpCG;
import org.overture.codegen.cgast.expressions.AMinusUnaryExpCG;
import org.overture.codegen.cgast.expressions.ANewExpCG;
import org.overture.codegen.cgast.expressions.ANotEqualsBinaryExpCG;
import org.overture.codegen.cgast.expressions.ANotUnaryExpCG;
import org.overture.codegen.cgast.expressions.APlusUnaryExpCG;
import org.overture.codegen.cgast.expressions.AQuoteLiteralExpCG;
import org.overture.codegen.cgast.expressions.ASeqToStringUnaryExpCG;
import org.overture.codegen.cgast.expressions.AStringLiteralExpCG;
import org.overture.codegen.cgast.expressions.AStringToSeqUnaryExpCG;
import org.overture.codegen.cgast.expressions.AUndefinedExpCG;
import org.overture.codegen.cgast.expressions.SBinaryExpCG;
import org.overture.codegen.cgast.expressions.SLiteralExpCG;
import org.overture.codegen.cgast.expressions.SNumericBinaryExpCG;
import org.overture.codegen.cgast.expressions.SUnaryExpCG;
import org.overture.codegen.cgast.expressions.SVarExpCG;
import org.overture.codegen.cgast.name.ATypeNameCG;
import org.overture.codegen.cgast.statements.AAssignmentStmCG;
import org.overture.codegen.cgast.statements.ABlockStmCG;
import org.overture.codegen.cgast.statements.AForLoopStmCG;
import org.overture.codegen.cgast.statements.AMapSeqStateDesignatorCG;
import org.overture.codegen.cgast.statements.AStartStmCG;
import org.overture.codegen.cgast.types.ABoolBasicTypeCG;
import org.overture.codegen.cgast.types.ACharBasicTypeCG;
import org.overture.codegen.cgast.types.AClassTypeCG;
import org.overture.codegen.cgast.types.AInterfaceTypeCG;
import org.overture.codegen.cgast.types.AMethodTypeCG;
import org.overture.codegen.cgast.types.AObjectTypeCG;
import org.overture.codegen.cgast.types.ARecordTypeCG;
import org.overture.codegen.cgast.types.ATupleTypeCG;
import org.overture.codegen.cgast.types.AUnionTypeCG;
import org.overture.codegen.cgast.types.AUnknownTypeCG;
import org.overture.codegen.cgast.types.AVoidTypeCG;
import org.overture.codegen.cgast.types.SBasicTypeCG;
import org.overture.codegen.cgast.types.SMapTypeCG;
import org.overture.codegen.cgast.types.SSeqTypeCG;
import org.overture.codegen.cgast.types.SSetTypeCG;
import org.overture.codegen.ir.IRAnalysis;
import org.overture.codegen.ir.IRInfo;
import org.overture.codegen.ir.SourceNode;
import org.overture.codegen.logging.Logger;
import org.overture.codegen.merging.MergeVisitor;
import org.overture.codegen.merging.TemplateCallable;
import org.overture.codegen.merging.TemplateStructure;
import org.overture.codegen.trans.TempVarPrefixes;
import org.overture.codegen.trans.funcvalues.FunctionValueAssistant;
import org.overture.codegen.utils.GeneralUtils;
import org.overture.typechecker.assistant.type.PTypeAssistantTC;

public class JavaFormat {
    private static final String CLASS_EXTENSION = ".class";
    public static final String UTILS_FILE = "Utils";
    public static final String SEQ_UTIL_FILE = "SeqUtil";
    public static final String SET_UTIL_FILE = "SetUtil";
    public static final String MAP_UTIL_FILE = "MapUtil";

    public static final String JAVA_PUBLIC = "public";
    public static final String JAVA_PRIVATE = "private";

    public static final String JAVA_INT = "int";

    private List<AClassDeclCG> classes;

    private IRInfo info;

    private FunctionValueAssistant functionValueAssistant;
    private MergeVisitor mergeVisitor;
    private JavaValueSemantics valueSemantics;
    private JavaFormatAssistant javaFormatAssistant;

    public JavaFormat(TempVarPrefixes varPrefixes, TemplateStructure templateStructure, IRInfo info) {
        this.valueSemantics = new JavaValueSemantics(this);
        JavaClassCreatorBase recordCreator = new JavaRecordCreator(this);
        TemplateCallable[] templateCallables = TemplateCallableManager.constructTemplateCallables(this,
                IRAnalysis.class, varPrefixes, valueSemantics, recordCreator);
        this.mergeVisitor = new MergeVisitor(templateStructure, templateCallables);
        this.functionValueAssistant = null;
        this.info = info;
        this.javaFormatAssistant = new JavaFormatAssistant(this.info);
    }

    public JavaFormatAssistant getJavaFormatAssistant() {
        return javaFormatAssistant;
    }

    public String getJavaNumber() {
        return "Number";
    }

    public IRInfo getIrInfo() {
        return info;
    }

    public void setFunctionValueAssistant(FunctionValueAssistant functionValueAssistant) {
        this.functionValueAssistant = functionValueAssistant;
    }

    public void clearFunctionValueAssistant() {
        this.functionValueAssistant = null;
    }

    public List<AClassDeclCG> getClasses() {
        return classes;
    }

    public void setJavaSettings(JavaSettings javaSettings) {
        valueSemantics.setJavaSettings(javaSettings);
    }

    public JavaSettings getJavaSettings() {
        return valueSemantics.getJavaSettings();
    }

    public void init() {
        mergeVisitor.init();
    }

    public void setClasses(List<AClassDeclCG> classes) {
        this.classes = classes != null ? classes : new LinkedList<AClassDeclCG>();
    }

    public void clearClasses() {
        if (classes != null) {
            classes.clear();
        } else {
            classes = new LinkedList<AClassDeclCG>();
        }
    }

    public MergeVisitor getMergeVisitor() {
        return mergeVisitor;
    }

    public String format(AMethodTypeCG methodType) throws AnalysisException {
        final String OBJ = "Object";

        if (functionValueAssistant == null) {
            return OBJ;
        }

        AInterfaceDeclCG methodTypeInterface = functionValueAssistant.findInterface(methodType);

        if (methodTypeInterface == null) {
            return OBJ; // Should not happen
        }

        AInterfaceTypeCG methodClass = new AInterfaceTypeCG();
        methodClass.setName(methodTypeInterface.getName());

        LinkedList<STypeCG> params = methodType.getParams();

        for (STypeCG param : params) {
            methodClass.getTypes().add(param.clone());
        }

        methodClass.getTypes().add(methodType.getResult().clone());

        return methodClass != null ? format(methodClass) : OBJ;
    }

    public String format(INode node) throws AnalysisException {
        return format(node, false);
    }

    public String formatIgnoreContext(INode node) throws AnalysisException {
        return format(node, true);
    }

    private String format(INode node, boolean ignoreContext) throws AnalysisException {
        StringWriter writer = new StringWriter();
        node.apply(mergeVisitor, writer);

        return writer.toString() + getNumberDereference(node, ignoreContext);
    }

    private String findNumberDereferenceCall(STypeCG type) {
        if (type == null || type.parent() instanceof AHistoryExpCG) {
            return "";
        }

        final String DOUBLE_VALUE = ".doubleValue()";
        final String LONG_VALUE = ".longValue()";

        if (info.getAssistantManager().getTypeAssistant().isInt(type)) {
            return LONG_VALUE;
        } else if (info.getAssistantManager().getTypeAssistant().isRealOrRat(type)) {
            return DOUBLE_VALUE;
        } else {
            PTypeAssistantTC typeAssistant = info.getTcFactory().createPTypeAssistant();
            SourceNode sourceNode = type.getSourceNode();

            if (sourceNode != null && !(sourceNode.getVdmNode() instanceof PType)) {
                PType vdmType = (PType) sourceNode.getVdmNode();

                if (typeAssistant.isNumeric(vdmType)) {
                    return DOUBLE_VALUE;
                }
            }

            return "";
        }
    }

    public static boolean isMapSeq(SStateDesignatorCG stateDesignator) {
        return stateDesignator instanceof AMapSeqStateDesignatorCG;
    }

    public String formatMapSeqStateDesignator(AMapSeqStateDesignatorCG mapSeq) throws AnalysisException {
        INode parent = mapSeq.parent();

        SStateDesignatorCG stateDesignator = mapSeq.getMapseq();
        SExpCG domValue = mapSeq.getExp();

        String stateDesignatorStr = format(stateDesignator);
        String domValStr = format(domValue);

        if (parent instanceof AAssignmentStmCG) {
            AAssignmentStmCG assignment = (AAssignmentStmCG) parent;
            SExpCG rngValue = assignment.getExp();
            String rngValStr = format(rngValue);

            // e.g. counters.put("c1", 4);
            return stateDesignatorStr + ".put(" + domValStr + ", " + rngValStr + ")";
        } else {
            STypeCG type = mapSeq.getType();
            String typeStr = format(type);

            // e.g. ((Rec) m(true)).field := 2;
            return "( (" + typeStr + ")" + format(mapSeq.getMapseq()) + ".get(" + domValStr + "))";
        }
    }

    private String getNumberDereference(INode node, boolean ignoreContext) {
        if (ignoreContext && node instanceof SExpCG) {
            SExpCG exp = (SExpCG) node;
            STypeCG type = exp.getType();

            if (isNumberDereferenceCandidate(exp)) {
                return findNumberDereferenceCall(type);
            }
        }

        INode parent = node.parent();

        if (parent instanceof SNumericBinaryExpCG || parent instanceof AAbsUnaryExpCG
                || parent instanceof AMinusUnaryExpCG || parent instanceof APlusUnaryExpCG) {
            SExpCG exp = (SExpCG) node;
            STypeCG type = exp.getType();

            if (isNumberDereferenceCandidate(exp)) {
                return findNumberDereferenceCall(type);
            }
        }

        // No dereference is needed
        return "";
    }

    private static boolean isNumberDereferenceCandidate(SExpCG node) {
        boolean fitsCategory = !(node instanceof SNumericBinaryExpCG) && !(node instanceof SLiteralExpCG)
                && !(node instanceof AIsolationUnaryExpCG) && !(node instanceof SUnaryExpCG);

        boolean isException = node instanceof AHeadUnaryExpCG || node instanceof AQuoteLiteralExpCG
                || node instanceof ACastUnaryExpCG;

        return fitsCategory || isException;
    }

    public String formatName(INode node) throws AnalysisException {
        if (node instanceof ANewExpCG) {
            ANewExpCG newExp = (ANewExpCG) node;

            return formatTypeName(node, newExp.getName());
        } else if (node instanceof ARecordTypeCG) {
            ARecordTypeCG record = (ARecordTypeCG) node;
            ATypeNameCG typeName = record.getName();

            return formatTypeName(node, typeName);
        }

        throw new AnalysisException("Unexpected node in formatName: " + node.getClass().getName());
    }

    public String formatTypeName(INode node, ATypeNameCG typeName) {
        AClassDeclCG classDef = node.getAncestor(AClassDeclCG.class);

        String definingClass = typeName.getDefiningClass() != null && classDef != null
                && !classDef.getName().equals(typeName.getDefiningClass()) ? typeName.getDefiningClass() + "." : "";

        String name = typeName.getName();

        return definingClass + name;
    }

    public String format(SExpCG exp, boolean leftChild) throws AnalysisException {
        String formattedExp = format(exp);

        JavaPrecedence precedence = new JavaPrecedence();

        INode parent = exp.parent();

        if (!(parent instanceof SExpCG)) {
            return formattedExp;
        }

        boolean isolate = precedence.mustIsolate((SExpCG) parent, exp, leftChild);

        return isolate ? "(" + formattedExp + ")" : formattedExp;
    }

    public String formatUnary(SExpCG exp) throws AnalysisException {
        return format(exp, false);
    }

    public String formatNotUnary(SExpCG exp) throws AnalysisException {
        String formattedExp = format(exp, false);

        boolean doNotWrap = exp instanceof ABoolLiteralExpCG
                || formattedExp.startsWith("(") && formattedExp.endsWith(")");

        return doNotWrap ? "!" + formattedExp : "!(" + formattedExp + ")";
    }

    public String formatTemplateTypes(List<STypeCG> types) throws AnalysisException {
        if (types.isEmpty()) {
            return "";
        }

        return "<" + formattedTypes(types, "") + ">";
    }

    private String formattedTypes(List<STypeCG> types, String typePostFix) throws AnalysisException {
        STypeCG firstType = types.get(0);

        if (info.getAssistantManager().getTypeAssistant().isBasicType(firstType)) {
            firstType = info.getAssistantManager().getTypeAssistant().getWrapperType((SBasicTypeCG) firstType);
        }

        StringWriter writer = new StringWriter();
        writer.append(format(firstType) + typePostFix);

        for (int i = 1; i < types.size(); i++) {
            STypeCG currentType = types.get(i);

            if (info.getAssistantManager().getTypeAssistant().isBasicType(currentType)) {
                currentType = info.getAssistantManager().getTypeAssistant()
                        .getWrapperType((SBasicTypeCG) currentType);
            }

            writer.append(", " + format(currentType) + typePostFix);
        }

        String result = writer.toString();

        return result;
    }

    public String formatTypeArg(STypeCG type) throws AnalysisException {
        if (type == null) {
            return null;
        } else {
            List<STypeCG> types = new LinkedList<STypeCG>();
            types.add(type);

            return formattedTypes(types, CLASS_EXTENSION);
        }
    }

    public String formatTypeArgs(ATupleTypeCG tupleType) throws AnalysisException {
        return formatTypeArgs(tupleType.getTypes());
    }

    public String formatTypeArgs(List<STypeCG> types) throws AnalysisException {
        if (types.isEmpty()) {
            return "";
        }

        return formattedTypes(types, CLASS_EXTENSION);
    }

    public String formatEqualsBinaryExp(AEqualsBinaryExpCG node) throws AnalysisException {
        STypeCG leftNodeType = node.getLeft().getType();

        if (leftNodeType instanceof SSeqTypeCG || leftNodeType instanceof SSetTypeCG
                || leftNodeType instanceof SMapTypeCG) {
            return handleCollectionComparison(node);
        } else {
            return handleEquals(node);
        }
    }

    public String formatNotEqualsBinaryExp(ANotEqualsBinaryExpCG node) throws AnalysisException {
        ANotUnaryExpCG transformed = transNotEquals(node);
        return formatNotUnary(transformed.getExp());
    }

    private ANotUnaryExpCG transNotEquals(ANotEqualsBinaryExpCG notEqual) {
        ANotUnaryExpCG notUnary = new ANotUnaryExpCG();
        notUnary.setType(new ABoolBasicTypeCG());

        AEqualsBinaryExpCG equal = new AEqualsBinaryExpCG();
        equal.setType(new ABoolBasicTypeCG());
        equal.setLeft(notEqual.getLeft().clone());
        equal.setRight(notEqual.getRight().clone());

        notUnary.setExp(equal);

        // Replace the "notEqual" expression with the transformed expression
        INode parent = notEqual.parent();

        // It may be the case that the parent is null if we execute e.g. [1] <> [1] in isolation
        if (parent != null) {
            parent.replaceChild(notEqual, notUnary);
            notEqual.parent(null);
        }

        return notUnary;
    }

    private String handleEquals(AEqualsBinaryExpCG valueType) throws AnalysisException {
        return String.format("%s.equals(%s, %s)", UTILS_FILE, format(valueType.getLeft()),
                format(valueType.getRight()));
    }

    private String handleCollectionComparison(SBinaryExpCG node) throws AnalysisException {
        // In VDM the types of the equals are compatible when the AST passes the type check
        SExpCG leftNode = node.getLeft();
        SExpCG rightNode = node.getRight();

        final String EMPTY = ".isEmpty()";

        if (isEmptyCollection(leftNode.getType())) {
            return format(node.getRight()) + EMPTY;
        } else if (isEmptyCollection(rightNode.getType())) {
            return format(node.getLeft()) + EMPTY;
        }

        return UTILS_FILE + ".equals(" + format(node.getLeft()) + ", " + format(node.getRight()) + ")";
    }

    private boolean isEmptyCollection(STypeCG type) {
        if (type instanceof SSeqTypeCG) {
            SSeqTypeCG seq = (SSeqTypeCG) type;

            return seq.getEmpty();
        } else if (type instanceof SSetTypeCG) {
            SSetTypeCG set = (SSetTypeCG) type;

            return set.getEmpty();
        } else if (type instanceof SMapTypeCG) {
            SMapTypeCG map = (SMapTypeCG) type;

            return map.getEmpty();
        }

        return false;
    }

    public String format(List<AFormalParamLocalParamCG> params) throws AnalysisException {
        StringWriter writer = new StringWriter();

        if (params.size() <= 0) {
            return "";
        }

        final String finalPrefix = " final ";

        AFormalParamLocalParamCG firstParam = params.get(0);
        writer.append(finalPrefix);
        writer.append(format(firstParam));

        for (int i = 1; i < params.size(); i++) {
            AFormalParamLocalParamCG param = params.get(i);
            writer.append(", ");
            writer.append(finalPrefix);
            writer.append(format(param));
        }
        return writer.toString();
    }

    public String formatSuperType(AClassDeclCG classDecl) {
        return classDecl.getSuperName() == null ? "" : "extends " + classDecl.getSuperName();
    }

    public String formatInterfaces(AClassDeclCG classDecl) {
        LinkedList<AInterfaceDeclCG> interfaces = classDecl.getInterfaces();

        if (interfaces == null || interfaces.isEmpty()) {
            return "";
        }

        String implementsClause = "implements";

        implementsClause += " " + interfaces.get(0).getName();

        for (int i = 1; i < interfaces.size(); i++) {
            implementsClause += ", " + interfaces.get(i).getName();
        }

        return implementsClause;
    }

    public String formatMaplets(AEnumMapExpCG mapEnum) throws AnalysisException {
        LinkedList<AMapletExpCG> members = mapEnum.getMembers();

        return "new Maplet[]{" + formatArgs(members) + "}";
    }

    public String formatArgs(List<? extends SExpCG> exps) throws AnalysisException {
        StringWriter writer = new StringWriter();

        if (exps.size() <= 0) {
            return "";
        }

        SExpCG firstExp = exps.get(0);
        writer.append(format(firstExp));

        for (int i = 1; i < exps.size(); i++) {
            SExpCG exp = exps.get(i);
            writer.append(", " + format(exp));
        }

        return writer.toString();
    }

    public boolean isNull(INode node) {
        return node == null;
    }

    public boolean isVoidType(STypeCG node) {
        return node instanceof AVoidTypeCG;
    }

    public String formatInitialExp(SExpCG exp) throws AnalysisException {
        // Examples:
        // private int a; (exp == null || exp instanceof AUndefinedExpCG)
        // private int a = 2; (otherwise)

        return exp == null || exp instanceof AUndefinedExpCG ? "" : " = " + format(exp);
    }

    public String formatOperationBody(SStmCG body) throws AnalysisException {
        String NEWLINE = "\n";
        if (body == null) {
            return ";";
        }

        StringWriter generatedBody = new StringWriter();

        generatedBody.append("{" + NEWLINE + NEWLINE);
        generatedBody.append(handleOpBody(body));
        generatedBody.append(NEWLINE + "}");

        return generatedBody.toString();
    }

    private String handleOpBody(SStmCG body) throws AnalysisException {
        AMethodDeclCG method = body.getAncestor(AMethodDeclCG.class);

        if (method == null) {
            Logger.getLog()
                    .printErrorln("Could not find enclosing method when formatting operation body. Got: " + body);
        } else if (method.getAsync() != null && method.getAsync()) {
            return "new VDMThread(){ " + "\tpublic void run() {" + "\t " + format(body) + "\t} " + "}.start();";
        }

        return format(body);
    }

    public String formatTemplateParam(INode potentialBasicType) throws AnalysisException {
        if (potentialBasicType == null) {
            return "";
        }

        TypeAssistantCG typeAssistant = info.getAssistantManager().getTypeAssistant();

        if (potentialBasicType instanceof STypeCG && typeAssistant.isNumericType((STypeCG) potentialBasicType)) {
            return "Number";
        } else if (potentialBasicType instanceof ABoolBasicTypeCG) {
            return "Boolean";
        } else if (potentialBasicType instanceof ACharBasicTypeCG) {
            return "Character";
        } else {
            return format(potentialBasicType);
        }
    }

    public boolean isStringLiteral(SExpCG exp) {
        return exp instanceof AStringLiteralExpCG;
    }

    public boolean isSeqType(SExpCG exp) {
        return info.getAssistantManager().getTypeAssistant().isSeqType(exp);
    }

    public boolean isMapType(SExpCG exp) {
        return info.getAssistantManager().getTypeAssistant().isMapType(exp);
    }

    public boolean isStringType(STypeCG type) {
        return info.getAssistantManager().getTypeAssistant().isStringType(type);
    }

    public boolean isStringType(SExpCG exp) {
        return info.getAssistantManager().getTypeAssistant().isStringType(exp);
    }

    public boolean isCharType(STypeCG type) {
        return type instanceof ACharBasicTypeCG;
    }

    public String buildString(List<SExpCG> exps) throws AnalysisException {
        StringBuilder sb = new StringBuilder();

        sb.append("new String(new char[]{");

        if (exps.size() > 0) {
            sb.append(format(exps.get(0)));

            for (int i = 1; i < exps.size(); i++) {
                sb.append(", " + format(exps.get(i)));
            }
        }

        sb.append("})");

        return sb.toString();
    }

    public String formatElementType(STypeCG type) throws AnalysisException {
        if (type instanceof SSetTypeCG) {
            SSetTypeCG setType = (SSetTypeCG) type;

            return format(setType.getSetOf());
        } else if (type instanceof SSeqTypeCG) {
            SSeqTypeCG seqType = (SSeqTypeCG) type;

            return format(seqType.getSeqOf());
        }

        throw new AnalysisException("Expected set or seq type when trying to format element type");
    }

    public String nextVarName(String prefix) {
        return info.getTempVarNameGen().nextVarName(prefix);
    }

    public boolean isLoopVar(AVarDeclCG localVar) {
        return localVar.parent() instanceof AForLoopStmCG;
    }

    public boolean isLambda(AApplyExpCG applyExp) {
        SExpCG root = applyExp.getRoot();

        if (root instanceof AApplyExpCG && root.getType() instanceof AMethodTypeCG) {
            return true;
        }

        if (!(root instanceof SVarExpCG)) {
            return false;
        }

        SVarExpCG varExp = (SVarExpCG) root;

        return varExp.getIsLambda() != null && varExp.getIsLambda();
    }

    public String escapeStr(String str) {
        String escaped = "";
        for (int i = 0; i < str.length(); i++) {
            char currentChar = str.charAt(i);
            escaped += GeneralUtils.isEscapeSequence(currentChar) ? StringEscapeUtils.escapeJava(currentChar + "")
                    : currentChar + "";
        }

        return escaped;
    }

    public static boolean castNotNeeded(STypeCG type) {
        return type instanceof AObjectTypeCG || type instanceof AUnknownTypeCG || type instanceof AUnionTypeCG;
    }

    public String escapeChar(char c) {
        return GeneralUtils.isEscapeSequence(c) ? StringEscapeUtils.escapeJavaScript(c + "") : c + "";
    }

    public boolean isInnerClass(AClassDeclCG node) {
        return node.parent() != null && node.parent().getAncestor(AClassDeclCG.class) != null;
    }

    public static boolean isQuote(AClassDeclCG classCg) {
        return classCg != null && "quotes".equals(classCg.getPackage());
    }

    public String formatStartStmExp(AStartStmCG node) throws AnalysisException {
        String str = format(node.getExp());

        if (node.getExp().getType() instanceof AClassTypeCG) {
            return str;
        } else {
            return "((Thread)" + str + ")";
        }
    }

    public static boolean isNamedTypeDecl(ATypeDeclCG node) {
        return node.getDecl() instanceof ANamedTypeDeclCG;
    }

    public static boolean isSeqConversion(AFieldNumberExpCG node) {
        INode parent = node.parent();
        return parent instanceof ASeqToStringUnaryExpCG || parent instanceof AStringToSeqUnaryExpCG;
    }

    public static boolean isScoped(ABlockStmCG block) {
        return block != null && block.getScoped() != null && block.getScoped();
    }
}