ArduinoComments.java

/*******************************************************************************
 * jArduino: Arduino C++ Code Generation From Java
 * Copyright 2020 Tony Washer
 *
 * 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 net.sourceforge.jarduino.message;

import java.util.HashMap;
import java.util.Map;

import net.sourceforge.jarduino.ArduinoException;
import net.sourceforge.jarduino.message.ArduinoParser.ArduinoParserException;

/**
 * Comments.
 */
public class ArduinoComments {
    /**
     * The Marker.
     */
    static final String MARKER = "CM_";

    /**
     * The map of comments.
     */
    private Map<ArduinoNamedObject, String> theComments;

    /**
     * Constructor.
     */
    ArduinoComments() {
        theComments = new HashMap<>();
    }

    /**
     * Obtain the comment for an object (if any).
     * @param pObject the object
     * @return the comment (or null)
     */
    public String getCommentForObject(final ArduinoNamedObject pObject) {
        return theComments.get(pObject);
    }

    /**
     * Store the comment for an object.
     * @param pObject the object
     * @param pComment the comment
     */
    void storeCommentForObject(final ArduinoNamedObject pObject,
                               final String pComment) {
        theComments.put(pObject, pComment);
    }

    /**
     * parse the comment definition.
     * @param pSystem the system
     * @param pCommentDef the comment definition
     * @throws ArduinoException on error
     */
    public static void parseComment(final ArduinoSystem pSystem,
                                    final String pCommentDef) throws ArduinoException {
        /* Marker is first token in header */
        final String myMarker = ArduinoParser.nextToken(pCommentDef);
        String myDef = ArduinoParser.stripToken(pCommentDef, myMarker);
        if (!myMarker.equals(MARKER)) {
            throw new ArduinoException("Invalid marker", pCommentDef);
        }

        /* Split out id/comment */
        final int myIndex = myDef.indexOf(ArduinoChar.QUOTE);
        if (myIndex == -1) {
            throw new ArduinoException("Missing " + ArduinoChar.QUOTE + " separator", pCommentDef);
        }
        String myId = myDef.substring(0, myIndex);
        myDef = myDef.substring(myIndex);

        /* Check that the end character is semicolon */
        final int myLen = myDef.length();
        if (myDef.length() == 0 || myDef.charAt(myLen - 1) != ArduinoChar.SEMICOLON) {
            throw new ArduinoException("Missing terminator", pCommentDef);
        }
        myDef = myDef.substring(0, myLen - 1);

        /* Protect against exceptions */
        try {
            /* Comments is final token */
            final String myComment = ArduinoParser.nextQuotedToken(myDef);

            /* The next tokens are the object type and id */
            final String myType = ArduinoParser.nextToken(myId);
            myId = ArduinoParser.stripToken(myId, myType);

            /* Determine the target for the comment */
            final ArduinoNamedObject myTarget = determineTarget(pSystem, myType, myId);

            /* Store the comment */
            pSystem.storeCommentForObject(myTarget, myComment);

            /* Handle parser exceptions */
        } catch (ArduinoParserException e) {
            throw new ArduinoException(e.getMessage() + ArduinoChar.COLON + e.getDetail(), pCommentDef);
        }
    }

    /**
     * Obtain the target.
     * @param pSystem the system
     * @param pType the target type
     * @param pId the target id
     * @return the object
     * @throws ArduinoParserException on error
     */
    private static ArduinoNamedObject determineTarget(final ArduinoSystem pSystem,
                                                      final String pType,
                                                      final String pId) throws ArduinoParserException {
        /* If this is a system */
        if (pType.length() == 0) {
            return pSystem;
        }

        /* If this is a node */
        if (pType.equals(ArduinoNode.MARKER)) {
            return pSystem.findNodeByName(pId);
        }

        /* MsgId is the next token */
        final String myId = ArduinoParser.nextToken(pId);
        final String mySignal = ArduinoParser.stripToken(pId, myId);
        final ArduinoMessage myMessage = pSystem.findMessageById(myId);

        /* If this is a message */
        if (pType.equals(ArduinoMessage.MARKER)) {
            return myMessage;
        }

        /* If this is a signal */
        if (pType.equals(ArduinoSignal.MARKER)) {
            return myMessage.findSignalByName(mySignal);
        }

        /* Unrecognised marker */
        throw new ArduinoParserException("Invalid comment type", pType);
    }
}