Package org.sablecc.objectmacro.launcher

Source Code of org.sablecc.objectmacro.launcher.ObjectMacro

/* This file is part of SableCC ( http://sablecc.org ).
*
* See the NOTICE file distributed with this work for copyright information.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.sablecc.objectmacro.launcher;

import static org.sablecc.objectmacro.launcher.Version.*;

import java.io.*;
import java.util.*;

import org.sablecc.exception.*;
import org.sablecc.objectmacro.codegeneration.*;
import org.sablecc.objectmacro.codegeneration.c.*;
import org.sablecc.objectmacro.codegeneration.intermediate.*;
import org.sablecc.objectmacro.codegeneration.java.*;
import org.sablecc.objectmacro.codegeneration.scala.*;
import org.sablecc.objectmacro.errormessage.*;
import org.sablecc.objectmacro.exception.*;
import org.sablecc.objectmacro.intermediate.syntax3.node.*;
import org.sablecc.objectmacro.intermediate.syntax3.node.AMacro;
import org.sablecc.objectmacro.intermediate.syntax3.node.ATextInsert;
import org.sablecc.objectmacro.intermediate.syntax3.node.PMacro;
import org.sablecc.objectmacro.intermediate.syntax3.node.PTextInsert;
import org.sablecc.objectmacro.structure.*;
import org.sablecc.objectmacro.syntax3.lexer.*;
import org.sablecc.objectmacro.syntax3.node.*;
import org.sablecc.objectmacro.syntax3.node.Start;
import org.sablecc.objectmacro.syntax3.parser.*;
import org.sablecc.objectmacro.util.*;
import org.sablecc.objectmacro.walker.*;
import org.sablecc.util.*;

/**
* The main class of ObjectMacro.
*/
public class ObjectMacro {

    /** Prevents instantiation of this class. */
    private ObjectMacro() {

        throw new InternalException("this class may not have instances");
    }

    /** Launches ObjectMacro. */
    public static void main(
            String[] args) {

        try {
            compile(args);
        }
        catch (CompilerException e) {
            System.err.print(e.getMessage());
            System.err.flush();
            System.exit(1);
        }
        catch (ParserException e) {
            int start = e.getMessage().indexOf(' ');
            System.err.print(new MSyntaxError(e.getToken().getLine() + "", e
                    .getToken().getPos()
                    + "", e.getToken().getClass().getSimpleName().substring(1)
                    .toLowerCase(), e.getToken().getText(), e.getMessage()
                    .substring(start)));
            System.err.flush();
            System.exit(1);
        }
        catch (LexerException e) {
            int start = e.getMessage().indexOf('[') + 1;
            int end = e.getMessage().indexOf(',');
            String line = e.getMessage().substring(start, end);

            start = e.getMessage().indexOf(',') + 1;
            end = e.getMessage().indexOf(']');
            String pos = e.getMessage().substring(start, end);

            start = e.getMessage().indexOf(' ') + 1;

            System.err.print(new MLexicalError(line, pos, e.getMessage()
                    .substring(start)));
            System.err.flush();
            System.exit(1);
        }
        catch (InternalException e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            System.err.print(new MInternalError(sw.toString(), e.getMessage()));
            System.err.flush();
            System.exit(1);
        }
        catch (Throwable e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            pw.flush();
            System.err.print(new MInternalError(sw.toString(), e.getMessage()));
            System.err.flush();
            System.exit(1);
        }

        // finish gracefully
        System.exit(0);
    }

    /**
     * Parses the provided arguments and launches macro compilation.
     */
    public static void compile(
            String[] arguments)
            throws ParserException, LexerException {

        // default target is java
        String targetLanguage = "java";

        // default destination directory is current working directory
        File destinationDirectory = new File(System.getProperty("user.dir"));

        // default destination package is anonymous
        String destinationPackage = "";

        // default option values
        boolean generateCode = true;
        Verbosity verbosity = Verbosity.INFORMATIVE;
        Strictness strictness = Strictness.STRICT;

        // parse command line arguments
        ArgumentCollection argumentCollection = new ArgumentCollection(
                arguments);

        // handle option arguments
        for (OptionArgument optionArgument : argumentCollection
                .getOptionArguments()) {

            switch (optionArgument.getOption()) {

            case LIST_TARGETS:
                System.out.println("Available targets:");
                System.out.println(" java (default)");
                System.out.println(" c");
                System.out.println(" scala");
                System.out.println(" intermediate");
                return;

            case TARGET:
                targetLanguage = optionArgument.getOperand();
                break;

            case DESTINATION:
                destinationDirectory = new File(optionArgument.getOperand());
                break;

            case PACKAGE:
                destinationPackage = optionArgument.getOperand();
                break;

            case GENERATE:
                generateCode = true;
                break;

            case NO_CODE:
                generateCode = false;
                break;

            case LENIENT:
                strictness = Strictness.LENIENT;
                break;

            case STRICT:
                strictness = Strictness.STRICT;
                break;

            case QUIET:
                verbosity = Verbosity.QUIET;
                break;

            case INFORMATIVE:
                verbosity = Verbosity.INFORMATIVE;
                break;

            case VERBOSE:
                verbosity = Verbosity.VERBOSE;
                break;

            case VERSION:
                System.out.println("ObjectMacro, part of SableCC version "
                        + VERSION);
                return;

            case HELP:
                System.out.println("Usage: objectmacro "
                        + Option.getShortHelpMessage() + " file.objectmacro");
                System.out.println("Options:");
                System.out.println(Option.getLongHelpMessage());
                return;

            default:
                throw new InternalException("unhandled option "
                        + optionArgument.getOption());
            }
        }

        switch (verbosity) {
        case INFORMATIVE:
        case VERBOSE:
            System.out.println();
            System.out.println("ObjectMacro, part of SableCC version "
                    + VERSION);
            System.out
                    .println("by Etienne M. Gagnon <egagnon@j-meg.com> and other contributors.");
            System.out.println();
            break;
        }

        // handle text arguments
        if (argumentCollection.getTextArguments().size() == 0) {
            System.out.println("Usage: objectmacro "
                    + Option.getShortHelpMessage() + " file.objectmacro");
            return;
        }
        else if (argumentCollection.getTextArguments().size() > 1) {
            throw CompilerException.invalidArgumentCount();
        }

        // check target
        if (!(targetLanguage.equals("java")
                || targetLanguage.equals("intermediate")
                || targetLanguage.equals("c") || targetLanguage.equals("scala"))) {
            throw CompilerException.unknownTarget(targetLanguage);
        }

        // check argument
        TextArgument textArgument = argumentCollection.getTextArguments()
                .get(0);

        if (!textArgument.getText().endsWith(".objectmacro")) {
            throw CompilerException.invalidSuffix(textArgument.getText());
        }

        File macroFile = new File(textArgument.getText());

        if (!macroFile.exists()) {
            throw CompilerException.missingMacroFile(textArgument.getText());
        }

        if (!macroFile.isFile()) {
            throw CompilerException.macroNotFile(textArgument.getText());
        }

        compile(macroFile, targetLanguage, destinationDirectory,
                destinationPackage, generateCode, strictness, verbosity);
    }

    /**
     * Compiles the provided macro file.
     */
    private static void compile(
            File macroFile,
            String targetLanguage,
            File destinationDirectory,
            String destinationPackage,
            boolean generateCode,
            Strictness strictness,
            Verbosity verbosity)
            throws ParserException, LexerException {

        switch (verbosity) {
        case INFORMATIVE:
        case VERBOSE:
            System.out.println("Compiling \"" + macroFile + "\"");
            break;
        }

        Start ast;

        try {
            FileReader fr = new FileReader(macroFile);
            BufferedReader br = new BufferedReader(fr);
            PushbackReader pbr = new PushbackReader(br, 1024);

            switch (verbosity) {
            case VERBOSE:
                System.out.println(" Parsing");
                break;
            }

            ast = new Parser(new CustomLexer(pbr)).parse();

            pbr.close();
            br.close();
            fr.close();
        }
        catch (IOException e) {
            throw CompilerException.inputError(macroFile.toString(), e);
        }

        GlobalIndex globalIndex = verifySemantics(ast, strictness, verbosity);

        processSemantics(globalIndex, verbosity);

        PIntermediateRepresentation intermediateAST = generateIntermediateAST(
                globalIndex, verbosity);

        IntermediateRepresentation ir = new IntermediateRepresentation(
                intermediateAST, macroFile, destinationDirectory,
                destinationPackage);

        CodeGenerator codeGenerator;

        if (targetLanguage.equals("java")) {
            codeGenerator = new JavaCodeGenerator(ir);
        }
        else if (targetLanguage.equals("intermediate")) {
            codeGenerator = new IntermediateCodeGenerator(ir);
        }
        else if (targetLanguage.equals("c")) {
            codeGenerator = new CCodeGenerator(ir);
        }
        else if (targetLanguage.equals("scala")) {
            codeGenerator = new ScalaCodeGenerator(ir);
        }
        else {
            throw new InternalException("unhandled case");
        }

        switch (verbosity) {
        case VERBOSE:
            System.out.println(" Verifying target-specific semantics");
            break;
        }

        codeGenerator.verifyTargetSpecificSemantics(strictness);

        if (generateCode) {
            switch (verbosity) {
            case VERBOSE:
                System.out.println(" Generating code");
                break;
            }

            codeGenerator.generateCode();
        }
    }

    private static GlobalIndex verifySemantics(
            Start ast,
            Strictness strictness,
            Verbosity verbosity) {

        switch (verbosity) {
        case VERBOSE:
            System.out.println(" Verifying semantics");
            break;
        }

        GlobalIndex globalIndex = new GlobalIndex();

        ast.apply(new DeclarationCollector(globalIndex));
        ast.apply(new ExpandCollector(globalIndex));
        ast.apply(new TextInsertCollector(globalIndex));
        ast.apply(new VarVerifier(globalIndex));

        globalIndex.computeIndirectlyReferencedTextBlocks();

        for (Macro macro : globalIndex.getAllMacros()) {
            for (TextBlock textBlock : macro
                    .getIndirectlyReferencedTextBlocks()) {
                textBlock.setReachable();
            }
        }

        ast.apply(new CyclicTextBlockDetector(globalIndex));

        if (strictness == Strictness.STRICT) {
            for (TextBlock textBlock : globalIndex.getAllTextBlocks()) {
                if (!textBlock.isReachable()) {
                    throw CompilerException.unusedTextBlock(textBlock);
                }
            }

            for (Macro macro : globalIndex.getAllMacros()) {
                for (Param param : macro.getParams()) {
                    if (!param.isUsed()) {
                        throw CompilerException.unusedParam(param);
                    }
                }
            }

            for (TextBlock textBlock : globalIndex.getAllTextBlocks()) {
                for (Param param : textBlock.getParams()) {
                    if (!param.isUsed()) {
                        throw CompilerException.unusedParam(param);
                    }
                }
            }
        }

        return globalIndex;
    }

    private static void processSemantics(
            GlobalIndex globalIndex,
            Verbosity verbosity) {

        switch (verbosity) {
        case VERBOSE:
            System.out.println(" Processing semantics");
            break;
        }

        for (Macro macro : globalIndex.getAllMacros()) {
            macro.computeImplicitExpansion();
        }

        boolean modified;
        do {
            modified = false;

            for (TextBlock textBlock : globalIndex.getAllTextBlocks()) {
                if (textBlock.propagateAncestorReferences()) {
                    modified = true;
                }
            }

            for (Macro macro : globalIndex.getAllMacros()) {
                if (macro.propagateAncestorReferences()) {
                    modified = true;
                }
            }
        }
        while (modified);
    }

    private static PIntermediateRepresentation generateIntermediateAST(
            GlobalIndex globalIndex,
            Verbosity verbosity) {

        switch (verbosity) {
        case VERBOSE:
            System.out.println(" Creating intermediate structure");
            break;
        }

        List<PText> texts = new LinkedList<PText>();

        for (TextBlock textBlock : globalIndex.getAllTextBlocks()) {

            texts.add(createText(textBlock));
        }

        List<PMacro> macros = new LinkedList<PMacro>();

        for (Macro macro : globalIndex.getAllMacros()) {

            macros.add(createMacro(macro));
        }

        return new AIntermediateRepresentation(texts, macros);
    }

    private static AText createText(
            TextBlock textBlock) {

        TString name = new TString("'" + textBlock.getCamelCaseName() + "'");

        List<TString> params = new LinkedList<TString>();
        for (Param param : textBlock.getParams()) {
            params.add(new TString("'" + param.getCamelCaseName() + "'"));
        }

        PBoolean self_ref;
        if (textBlock.referencesSelf()) {
            self_ref = new ATrueBoolean();
        }
        else {
            self_ref = new AFalseBoolean();
        }

        List<TString> ancestor_refs = new LinkedList<TString>();
        for (Scope referencedAncestor : textBlock.getReferencedAncestors()) {
            TString ancestorName = new TString("'"
                    + referencedAncestor.getCamelCaseName() + "'");
            ancestor_refs.add(ancestorName);
        }

        List<PParamRef> param_refs = new LinkedList<PParamRef>();
        for (Param referencedParam : textBlock.getReferencedParams()) {
            TString paramName = new TString("'"
                    + referencedParam.getCamelCaseName() + "'");
            TString scopeName = new TString("'"
                    + referencedParam.getScope().getCamelCaseName() + "'");
            param_refs.add(new AParamRef(paramName, scopeName));
        }

        List<PTextPart> text_parts = new LinkedList<PTextPart>();
        {
            StringBuilder textBuilder = null;

            for (PTextBlockBodyPart pTextBlockBodyPart : textBlock
                    .getDeclaration().getParts()) {

                if (pTextBlockBodyPart instanceof ATextTextBlockBodyPart) {
                    ATextTextBlockBodyPart textBlockBodyPart = (ATextTextBlockBodyPart) pTextBlockBodyPart;
                    if (textBuilder == null) {
                        textBuilder = new StringBuilder();
                    }
                    TText textToken = textBlockBodyPart.getText();
                    for (char c : textToken.getText().toCharArray()) {
                        if (c == '\'') {
                            textBuilder.append("\\'");
                        }
                        else {
                            textBuilder.append(c);
                        }
                    }
                }
                else if (pTextBlockBodyPart instanceof AEolTextBlockBodyPart) {
                    if (textBuilder != null) {
                        text_parts.add(new AStringTextPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    text_parts.add(new AEolTextPart());
                }
                else if (pTextBlockBodyPart instanceof AEscapeTextBlockBodyPart) {
                    AEscapeTextBlockBodyPart textBlockBodyPart = (AEscapeTextBlockBodyPart) pTextBlockBodyPart;

                    char c = textBlockBodyPart.getEscape().getText().charAt(1);
                    if (c == '$') {
                        if (textBuilder == null) {
                            textBuilder = new StringBuilder();
                        }
                        textBuilder.append(c);
                    }
                    else if (c == '\\') {
                        if (textBuilder == null) {
                            textBuilder = new StringBuilder();
                        }
                        textBuilder.append("\\\\");
                    }
                    else if (c == 'n') {
                        if (textBuilder != null) {
                            text_parts.add(new AStringTextPart(new TString("'"
                                    + textBuilder.toString() + "'")));
                            textBuilder = null;
                        }
                        text_parts.add(new AEolTextPart());
                    }
                    else {
                        throw new InternalException("unhandled case");
                    }
                }
                else if (pTextBlockBodyPart instanceof AVarTextBlockBodyPart) {
                    AVarTextBlockBodyPart textBlockBodyPart = (AVarTextBlockBodyPart) pTextBlockBodyPart;
                    if (textBuilder != null) {
                        text_parts.add(new AStringTextPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    text_parts.add(new AParamInsertTextPart(new TString("'"
                            + Utils.toCamelCase(textBlockBodyPart.getVar())
                            + "'")));
                }
                else if (pTextBlockBodyPart instanceof ATextInsertTextBlockBodyPart) {
                    ATextInsertTextBlockBodyPart textBlockBodyPart = (ATextInsertTextBlockBodyPart) pTextBlockBodyPart;
                    if (textBuilder != null) {
                        text_parts.add(new AStringTextPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    TextInsert textInsert = textBlock
                            .getTextInsert(textBlockBodyPart.getTextInsert());
                    text_parts.add(new ATextInsertTextPart(createTextInsert(
                            textInsert, textBlock)));
                }
                else {
                    if (!(pTextBlockBodyPart instanceof ATextBlockTextBlockBodyPart)) {
                        throw new InternalException("unhandled case");
                    }
                    if (textBuilder != null) {
                        text_parts.add(new AStringTextPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                }
            }

            if (textBuilder != null) {
                text_parts.add(new AStringTextPart(new TString("'"
                        + textBuilder.toString() + "'")));
                textBuilder = null;
            }
        }

        return new AText(name, params, self_ref, ancestor_refs, param_refs,
                text_parts);
    }

    private static PTextInsert createTextInsert(
            TextInsert textInsert,
            Scope context) {

        TString name = new TString("'"
                + textInsert.getInsertedTextBlock().getCamelCaseName() + "'");

        List<PValue> args = new LinkedList<PValue>();
        for (PStaticValue staticValue : textInsert.getDeclaration()
                .getStaticValues()) {
            args.add(createValue(staticValue, context));
        }

        List<TString> ancestor_refs = new LinkedList<TString>();
        for (Scope ancestor : textInsert.getInsertedTextBlock()
                .getReferencedAncestors()) {
            ancestor_refs.add(new TString("'" + ancestor.getCamelCaseName()
                    + "'"));
        }

        return new ATextInsert(name, args, ancestor_refs);
    }

    private static PValue createValue(
            PStaticValue pStaticValue,
            Scope context) {

        if (pStaticValue instanceof ATextInsertStaticValue) {
            ATextInsertStaticValue staticValue = (ATextInsertStaticValue) pStaticValue;

            TextInsert textInsert = context.getTextInsert(staticValue
                    .getTextInsert());
            return new ATextInsertValue(createTextInsert(textInsert, context));
        }
        else if (pStaticValue instanceof AVarStaticValue) {
            AVarStaticValue staticValue = (AVarStaticValue) pStaticValue;

            return new AParamInsertValue(new TString("'"
                    + Utils.toCamelCase(staticValue.getVar()) + "'"));
        }
        else if (pStaticValue instanceof AStringStaticValue) {
            AStringStaticValue staticValue = (AStringStaticValue) pStaticValue;

            return new AInlineTextValue(createInlineText(staticValue
                    .getString()));
        }
        else {
            throw new InternalException("unhandled case");
        }
    }

    private static List<PInlineText> createInlineText(
            PString pString) {

        AString string = (AString) pString;
        List<PInlineText> inlineTexts = new LinkedList<PInlineText>();
        StringBuilder textBuilder = null;

        if (string.getParts().size() == 0) {
            inlineTexts.add(new AStringInlineText(new TString("''")));
            return inlineTexts;
        }

        for (PStringPart pStringPart : string.getParts()) {
            if (pStringPart instanceof ATextStringPart) {
                ATextStringPart stringPart = (ATextStringPart) pStringPart;

                if (textBuilder == null) {
                    textBuilder = new StringBuilder();
                }
                String text = stringPart.getText().getText();
                for (char c : text.toCharArray()) {
                    if (c == '\'') {
                        textBuilder.append("\\'");
                    }
                    else {
                        textBuilder.append(c);
                    }
                }
            }
            else if (pStringPart instanceof AEscapeStringPart) {
                AEscapeStringPart stringPart = (AEscapeStringPart) pStringPart;

                char c = stringPart.getEscape().getText().charAt(1);
                if (c == '$') {
                    if (textBuilder == null) {
                        textBuilder = new StringBuilder();
                    }
                    textBuilder.append("$");
                }
                else if (c == '\"') {
                    if (textBuilder == null) {
                        textBuilder = new StringBuilder();
                    }
                    textBuilder.append("\"");
                }
                else if (c == '\\') {
                    if (textBuilder == null) {
                        textBuilder = new StringBuilder();
                    }
                    textBuilder.append("\\\\");
                }
                else if (c == 'n') {
                    if (textBuilder != null) {
                        inlineTexts.add(new AStringInlineText(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    inlineTexts.add(new AEolInlineText());
                }
                else {
                    throw new InternalException("unhandled case");
                }
            }
            else {
                throw new InternalException("unhandled case");
            }
        }

        if (textBuilder != null) {
            inlineTexts.add(new AStringInlineText(new TString("'"
                    + textBuilder.toString() + "'")));
        }

        return inlineTexts;
    }

    private static AMacro createMacro(
            Macro macro) {

        TString name = new TString("'" + macro.getCamelCaseName() + "'");

        PBoolean is_public;
        if (macro.getParent() == null) {
            is_public = new ATrueBoolean();
        }
        else {
            is_public = new AFalseBoolean();
        }

        List<TString> params = new LinkedList<TString>();
        for (Param param : macro.getParams()) {
            params.add(new TString("'" + param.getCamelCaseName() + "'"));
        }

        PBoolean self_ref;
        if (macro.referencesSelf()) {
            self_ref = new ATrueBoolean();
        }
        else {
            self_ref = new AFalseBoolean();
        }

        List<TString> ancestor_refs = new LinkedList<TString>();
        for (Scope referencedAncestor : macro.getReferencedAncestors()) {
            TString ancestorName = new TString("'"
                    + referencedAncestor.getCamelCaseName() + "'");
            ancestor_refs.add(ancestorName);
        }

        List<PParamRef> param_refs = new LinkedList<PParamRef>();
        for (Param referencedParam : macro.getReferencedParams()) {
            TString paramName = new TString("'"
                    + referencedParam.getCamelCaseName() + "'");
            TString scopeName = new TString("'"
                    + referencedParam.getScope().getCamelCaseName() + "'");
            param_refs.add(new AParamRef(paramName, scopeName));
        }

        List<TString> expands = new LinkedList<TString>();
        for (ExpandSignature signature : macro.getExpandSignatures()) {
            expands.add(new TString("'" + signature.toCamelCase() + "'"));
        }

        List<PExpandedMacro> expanded_macros = new LinkedList<PExpandedMacro>();
        for (Macro implicitlyExpandedMacro : macro
                .getImplicitlyExpandedMacros()) {
            TString macroName = new TString("'"
                    + implicitlyExpandedMacro.getCamelCaseName() + "'");
            List<TString> macroParams = new LinkedList<TString>();
            for (Param param : implicitlyExpandedMacro.getParams()) {
                macroParams.add(new TString("'" + param.getCamelCaseName()
                        + "'"));
            }
            List<TString> ancestors = new LinkedList<TString>();
            for (Scope ancestor : implicitlyExpandedMacro
                    .getReferencedAncestors()) {
                TString ancestorName = new TString("'"
                        + ancestor.getCamelCaseName() + "'");
                ancestors.add(ancestorName);
            }
            List<TString> macroExpands = new LinkedList<TString>();
            for (ExpandSignature signature : macro.getExpandSignatures()) {
                if (signature.getMacroSet().contains(implicitlyExpandedMacro)) {
                    macroExpands.add(new TString("'" + signature.toCamelCase()
                            + "'"));
                }
            }
            expanded_macros.add(new AExpandedMacro(macroName, macroParams,
                    ancestors, macroExpands));
        }
        for (Macro explicitlyExpandedMacro : macro
                .getExplicitlyExpandedMacros()) {
            TString macroName = new TString("'"
                    + explicitlyExpandedMacro.getCamelCaseName() + "'");
            List<TString> macroParams = new LinkedList<TString>();
            for (Param param : explicitlyExpandedMacro.getParams()) {
                macroParams.add(new TString("'" + param.getCamelCaseName()
                        + "'"));
            }
            List<TString> ancestors = new LinkedList<TString>();
            for (Scope ancestor : explicitlyExpandedMacro
                    .getReferencedAncestors()) {
                TString ancestorName = new TString("'"
                        + ancestor.getCamelCaseName() + "'");
                ancestors.add(ancestorName);
            }
            List<TString> macroExpands = new LinkedList<TString>();
            for (ExpandSignature signature : macro.getExpandSignatures()) {
                if (signature.getMacroSet().contains(explicitlyExpandedMacro)) {
                    macroExpands.add(new TString("'" + signature.toCamelCase()
                            + "'"));
                }
            }
            expanded_macros.add(new AExpandedMacro(macroName, macroParams,
                    ancestors, macroExpands));
        }

        List<PMacroPart> macro_parts = new LinkedList<PMacroPart>();
        {
            StringBuilder textBuilder = null;

            for (PMacroBodyPart pMacroBodyPart : macro.getDeclaration()
                    .getParts()) {
                if (pMacroBodyPart instanceof ATextMacroBodyPart) {
                    ATextMacroBodyPart macroBodyPart = (ATextMacroBodyPart) pMacroBodyPart;
                    if (textBuilder == null) {
                        textBuilder = new StringBuilder();
                    }
                    TText textToken = macroBodyPart.getText();
                    for (char c : textToken.getText().toCharArray()) {
                        if (c == '\'') {
                            textBuilder.append("\\'");
                        }
                        else {
                            textBuilder.append(c);
                        }
                    }
                }
                else if (pMacroBodyPart instanceof AEolMacroBodyPart) {
                    if (textBuilder != null) {
                        macro_parts.add(new AStringMacroPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    macro_parts.add(new AEolMacroPart());
                }
                else if (pMacroBodyPart instanceof AEscapeMacroBodyPart) {
                    AEscapeMacroBodyPart macroBodyPart = (AEscapeMacroBodyPart) pMacroBodyPart;

                    char c = macroBodyPart.getEscape().getText().charAt(1);
                    if (c == '$') {
                        if (textBuilder == null) {
                            textBuilder = new StringBuilder();
                        }
                        textBuilder.append(c);
                    }
                    else if (c == '\\') {
                        if (textBuilder == null) {
                            textBuilder = new StringBuilder();
                        }
                        textBuilder.append("\\\\");
                    }
                    else if (c == 'n') {
                        if (textBuilder != null) {
                            macro_parts.add(new AStringMacroPart(new TString(
                                    "'" + textBuilder.toString() + "'")));
                            textBuilder = null;
                        }
                        macro_parts.add(new AEolMacroPart());
                    }
                    else {
                        throw new InternalException("unhandled case c = (" + c
                                + ")");
                    }
                }
                else if (pMacroBodyPart instanceof AVarMacroBodyPart) {
                    AVarMacroBodyPart macroBodyPart = (AVarMacroBodyPart) pMacroBodyPart;
                    if (textBuilder != null) {
                        macro_parts.add(new AStringMacroPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    macro_parts
                            .add(new AParamInsertMacroPart(new TString("'"
                                    + Utils.toCamelCase(macroBodyPart.getVar())
                                    + "'")));
                }
                else if (pMacroBodyPart instanceof ATextInsertMacroBodyPart) {
                    ATextInsertMacroBodyPart macroBodyPart = (ATextInsertMacroBodyPart) pMacroBodyPart;
                    if (textBuilder != null) {
                        macro_parts.add(new AStringMacroPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    TextInsert textInsert = macro.getTextInsert(macroBodyPart
                            .getTextInsert());
                    macro_parts.add(new ATextInsertMacroPart(createTextInsert(
                            textInsert, macro)));
                }
                else if (pMacroBodyPart instanceof AExpandMacroBodyPart) {
                    AExpandMacroBodyPart macroBodyPart = (AExpandMacroBodyPart) pMacroBodyPart;
                    if (textBuilder != null) {
                        macro_parts.add(new AStringMacroPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    Expand expand = macro.getExpand(macroBodyPart.getExpand());
                    TString expandName = new TString("'"
                            + expand.getSignature().toCamelCase() + "'");
                    PValue none = null;
                    PValue separator = null;
                    PValue before_first = null;
                    PValue after_last = null;
                    PValue before_one = null;
                    PValue after_one = null;
                    PValue before_many = null;
                    PValue after_many = null;

                    if (expand.getNone() != null) {
                        none = createValue(expand.getNone().getStaticValue(),
                                macro);
                    }

                    if (expand.getSeparator() != null) {
                        separator = createValue(expand.getSeparator()
                                .getStaticValue(), macro);
                    }

                    if (expand.getBeforeFirst() != null) {
                        before_first = createValue(expand.getBeforeFirst()
                                .getStaticValue(), macro);
                    }

                    if (expand.getAfterLast() != null) {
                        after_last = createValue(expand.getAfterLast()
                                .getStaticValue(), macro);
                    }

                    if (expand.getBeforeOne() != null) {
                        before_one = createValue(expand.getBeforeOne()
                                .getStaticValue(), macro);
                    }

                    if (expand.getAfterOne() != null) {
                        after_one = createValue(expand.getAfterOne()
                                .getStaticValue(), macro);
                    }

                    if (expand.getBeforeMany() != null) {
                        before_many = createValue(expand.getBeforeMany()
                                .getStaticValue(), macro);
                    }

                    if (expand.getAfterMany() != null) {
                        after_many = createValue(expand.getAfterMany()
                                .getStaticValue(), macro);
                    }

                    macro_parts.add(new AExpandInsertMacroPart(
                            new AExpandInsert(expandName, none, separator,
                                    before_first, after_last, before_one,
                                    after_one, before_many, after_many)));
                }
                else if (pMacroBodyPart instanceof AMacroMacroBodyPart) {
                    AMacroMacroBodyPart macroBodyPart = (AMacroMacroBodyPart) pMacroBodyPart;
                    if (textBuilder != null) {
                        macro_parts.add(new AStringMacroPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                    Macro subMacro = macro
                            .getMacro(((org.sablecc.objectmacro.syntax3.node.AMacro) macroBodyPart
                                    .getMacro()).getName());
                    if (subMacro.isImplicitlyExpanded()) {
                        TString expandName = new TString("'"
                                + subMacro.getImplicitSignature().toCamelCase()
                                + "'");
                        macro_parts.add(new AExpandInsertMacroPart(
                                new AExpandInsert(expandName, null, null, null,
                                        null, null, null, null, null)));
                    }
                }
                else {
                    if (!(pMacroBodyPart instanceof ATextBlockMacroBodyPart)) {
                        throw new InternalException("unhandled case");
                    }
                    if (textBuilder != null) {
                        macro_parts.add(new AStringMacroPart(new TString("'"
                                + textBuilder.toString() + "'")));
                        textBuilder = null;
                    }
                }
            }

            if (textBuilder != null) {
                macro_parts.add(new AStringMacroPart(new TString("'"
                        + textBuilder.toString() + "'")));
                textBuilder = null;
            }
        }

        return new AMacro(name, is_public, params, self_ref, ancestor_refs,
                param_refs, expands, expanded_macros, macro_parts);
    }
}
TOP

Related Classes of org.sablecc.objectmacro.launcher.ObjectMacro

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.