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

com.google.javascript.jscomp.jsonml.Writer Maven / Gradle / Ivy

Go to download

Closure Compiler is a JavaScript optimizing compiler. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. It is used in many of Google's JavaScript apps, including Gmail, Google Web Search, Google Maps, and Google Docs.

There is a newer version: v20240317
Show newest version
/*
 * Copyright 2010 The Closure Compiler Authors.
 *
 * 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 com.google.javascript.jscomp.jsonml;

import com.google.common.base.Preconditions;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;

import java.util.Iterator;
import java.util.Set;

/**
 * Converts internal AST into JsonML tree.
 *
 * @author [email protected] (Daniel Hans)
 */
public class Writer {

  /**
   * Creates JsonML tree based on a specified AST.
   * @param root AST node
   * @return root of a created JsonML tree
   */
  public JsonML processAst(Node root) {
    Preconditions.checkNotNull(root);
    Preconditions.checkArgument(
      root.getType() == Token.BLOCK || root.getType() == Token.SCRIPT);

    JsonML rootElement = new JsonML(TagType.BlockStmt);
    if (root.getType() == Token.SCRIPT) {
      processNode(root, rootElement);
      return rootElement.getChild(0);
    } else {
      Node child = root.getFirstChild();
      while (child != null) {
        processNode(child, rootElement);
        child = child.getNext();
      }
      // TODO(johnlenz): Add support for multiple scripts.
      return rootElement.getChild(0);
    }
  }

  /**
   * Dispatches an AST node to a function which converts it to JsonML.
   * @param node AST node to convert into JsonML element.
   * @param currentParent element to which newly created JsonML element will
   * be attached as a child
   */
  private void processNode(Node node, JsonML currentParent) {
    switch (node.getType()) {
      case Token.RETURN:
        processReturn(node, currentParent);
        break;
      case Token.BITOR:
        processBinaryExpr(node, currentParent, "|");
        break;
      case Token.BITXOR:
        processBinaryExpr(node, currentParent, "^");
        break;
      case Token.BITAND:
        processBinaryExpr(node, currentParent, "&");
        break;
      case Token.EQ:
        processBinaryExpr(node, currentParent, "==");
        break;
      case Token.NE:
        processBinaryExpr(node, currentParent, "!=");
        break;
      case Token.LT:
        processBinaryExpr(node, currentParent, "<");
        break;
      case Token.LE:
        processBinaryExpr(node, currentParent, "<=");
        break;
      case Token.GT:
        processBinaryExpr(node, currentParent, ">");
        break;
      case Token.GE:
        processBinaryExpr(node, currentParent, ">=");
        break;
      case Token.LSH:
        processBinaryExpr(node, currentParent, "<<");
        break;
      case Token.RSH:
        processBinaryExpr(node, currentParent, ">>");
        break;
      case Token.URSH:
        processBinaryExpr(node, currentParent, ">>>");
        break;
      case Token.ADD:
        processBinaryExpr(node, currentParent, "+");
        break;
      case Token.SUB:
        processBinaryExpr(node, currentParent, "-");
        break;
      case Token.MUL:
        processBinaryExpr(node, currentParent, "*");
        break;
      case Token.DIV:
        processBinaryExpr(node, currentParent, "/");
        break;
      case Token.MOD:
        processBinaryExpr(node, currentParent, "%");
        break;
      case Token.NOT:
        processUnaryExpr(node, currentParent, "!");
        break;
      case Token.BITNOT:
        processUnaryExpr(node, currentParent, "~");
        break;
      case Token.POS:
        processUnaryExpr(node, currentParent, "+");
        break;
      case Token.NEG:
        processUnaryExpr(node, currentParent, "-");
        break;
      case Token.NEW:
        processNew(node, currentParent, TagType.NewExpr);
        break;
      case Token.DELPROP:
        processOneArgExpr(node, currentParent, TagType.DeleteExpr);
        break;
      case Token.TYPEOF:
        processOneArgExpr(node, currentParent, TagType.TypeofExpr);
        break;
      case Token.GETPROP:
        processMemberExpr(node, currentParent, ".");
        break;
      case Token.GETELEM:
        processMemberExpr(node, currentParent, "[]");
        break;
      case Token.CALL:
        processCall(node, currentParent);
        break;
      case Token.NAME:
        processName(node, currentParent);
        break;
      case Token.NUMBER:
      case Token.STRING:
      case Token.NULL:
      case Token.FALSE:
      case Token.TRUE:
        processLiteral(node, currentParent);
        break;
      case Token.THIS:
        processThis(node, currentParent);
        break;
      case Token.SHEQ:
        processBinaryExpr(node, currentParent, "===");
        break;
      case Token.SHNE:
        processBinaryExpr(node, currentParent, "!==");
        break;
      case Token.REGEXP:
        processRegExp(node, currentParent);
        break;
      case Token.THROW:
        processThrow(node, currentParent);
        break;
      case Token.IN:
        processBinaryExpr(node, currentParent, "in");
        break;
      case Token.INSTANCEOF:
        processBinaryExpr(node, currentParent, "instanceof");
        break;
      case Token.ARRAYLIT:
        processArrayLiteral(node, currentParent);
        break;
      case Token.OBJECTLIT:
        processObjectLiteral(node, currentParent);
        break;
      case Token.TRY:
        processTry(node, currentParent);
        break;
      case Token.COMMA:
        processBinaryExpr(node, currentParent, ",");
        break;
      case Token.ASSIGN:
        processAssignExpr(node, currentParent, "=");
        break;
      case Token.ASSIGN_BITOR:
        processAssignExpr(node, currentParent, "|=");
        break;
      case Token.ASSIGN_BITXOR:
        processAssignExpr(node, currentParent, "^=");
        break;
      case Token.ASSIGN_BITAND:
        processAssignExpr(node, currentParent, "&=");
        break;
      case Token.ASSIGN_LSH:
        processAssignExpr(node, currentParent, "<<=");
        break;
      case Token.ASSIGN_RSH:
        processAssignExpr(node, currentParent, ">>=");
        break;
      case Token.ASSIGN_URSH:
        processAssignExpr(node, currentParent, ">>>=");
        break;
      case Token.ASSIGN_ADD:
        processAssignExpr(node, currentParent, "+=");
        break;
      case Token.ASSIGN_SUB:
        processAssignExpr(node, currentParent, "-=");
        break;
      case Token.ASSIGN_MUL:
        processAssignExpr(node, currentParent, "*=");
        break;
      case Token.ASSIGN_DIV:
        processAssignExpr(node, currentParent, "/=");
        break;
      case Token.ASSIGN_MOD:
        processAssignExpr(node, currentParent, "%=");
        break;
      case Token.HOOK:
        processHook(node, currentParent);
        break;
      case Token.OR:
        processLogicalExpr(node, currentParent, "||");
        break;
      case Token.AND:
        processLogicalExpr(node, currentParent, "&&");
        break;
      case Token.INC:
        processIncrDecrExpr(node, currentParent, "++");
        break;
      case Token.DEC:
        processIncrDecrExpr(node, currentParent, "--");
        break;
      case Token.FUNCTION:
        processFunction(node, currentParent);
        break;
      case Token.IF:
        processIf(node, currentParent);
        break;
      case Token.SWITCH:
        processSwitch(node, currentParent);
        break;
      case Token.CASE:
        processCase(node, currentParent, TagType.Case);
        break;
      case Token.DEFAULT_CASE:
        processCase(node, currentParent, TagType.DefaultCase);
        break;
      case Token.WHILE:
        processLoop(node, currentParent, TagType.WhileStmt);
        break;
      case Token.DO:
        processLoop(node, currentParent, TagType.DoWhileStmt);
        break;
      case Token.FOR:
        processForLoop(node, currentParent);
        break;
      case Token.BREAK:
        processJmp(node, currentParent, TagType.BreakStmt);
        break;
      case Token.CONTINUE:
        processJmp(node, currentParent, TagType.ContinueStmt);
        break;
      case Token.VAR:
        processVar(node, currentParent);
        break;
      case Token.WITH:
        processWith(node, currentParent);
        break;
      case Token.CATCH:
        processCatch(node, currentParent);
        break;
      case Token.VOID:
        processUnaryExpr(node, currentParent, "void");
        break;
      case Token.EMPTY:
        processEmpty(node, currentParent);
        break;
      case Token.BLOCK:
        processBlock(node, currentParent);
        break;
      case Token.LABEL:
        processLabel(node, currentParent);
        break;
      case Token.EXPR_RESULT:
        processExprResult(node, currentParent);
        break;
      case Token.SCRIPT:
        processScript(node, currentParent);
        break;
    }
  }

  private void processAssignExpr(Node node, JsonML currentParent, String op) {
    processTwoArgExpr(node, currentParent, TagType.AssignExpr, op);
  }

  private void processArrayLiteral(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.ArrayExpr);
    currentParent.appendChild(element);
    Iterator it = node.children().iterator();
    while (it.hasNext()) {
      processNode(it.next(), element);
    }
  }

  private void processBinaryExpr(Node node, JsonML currentParent,
      String op) {
    processTwoArgExpr(node, currentParent, TagType.BinaryExpr, op);
  }

  private void processBlock(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.BlockStmt);
    if (currentParent != null) {
      currentParent.appendChild(element);
    }

    processDirectives(node, element);

    for (Node child : node.children()) {
      processNode(child, element);
    }
  }

  private void processCall(Node node, JsonML currentParent) {
    Iterator it = node.children().iterator();
    Node child = it.next();
    JsonML element;
    // the first child may indicate that it is invoke expression
    // or a standard function call
    switch (child.getType()) {
      case Token.GETPROP:         // a.x()
      case Token.GETELEM:         // a[x]()
        // we have to process this node here and cannot call processNode(child)
        // other children of CALL represent arguments, so we need to have
        // access to them while processing InvokeExpr
        element = new JsonML(TagType.InvokeExpr);
        element.setAttribute(
            TagAttr.OP,
            child.getType() == Token.GETPROP ? "." : "[]");
        currentParent.appendChild(element);

        // there should be exactly two children
        Node grandchild = child.getFirstChild();
        processNode(grandchild, element);
        processNode(grandchild.getNext(), element);


        break;
      case Token.NAME:
        // caja treats calls to eval in a special way
        if (child.getString().equals("eval")) {
          element = new JsonML(TagType.EvalExpr);
        } else {
          // element representing function name is created
          element = new JsonML(TagType.IdExpr);
          element.setAttribute(TagAttr.NAME, child.getString());
          // element representing function is created
          element = new JsonML(TagType.CallExpr, element);
        }
        currentParent.appendChild(element);
        break;
      default:
       // it addresses all cases where the first argument evaluates to
       // another expression
       element = new JsonML(TagType.CallExpr);
       currentParent.appendChild(element);
       processNode(child, element);
       break;
    }

    // there may be arguments applied
    while (it.hasNext()) {
      processNode(it.next(), element);
    }
  }

  private void processCase(Node node, JsonML currentParent,
      TagType type) {
    JsonML element = new JsonML(type);
    currentParent.appendChild(element);

    Node child = node.getFirstChild();
    // for case, the first child represents its argument
    if (type == TagType.Case) {
      processNode(child, element);
      child = child.getNext();
    }

    // it should be a BLOCK which is required by rhino for compatibility
    // the writer skips the node and move on to its children
    Preconditions.checkNotNull(child);
    Preconditions.checkState(child.getType() == Token.BLOCK);
    child = child.getFirstChild();
    while (child != null) {
      processNode(child, element);
      child = child.getNext();
    }
  }

  private void processCatch(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.CatchClause);
    currentParent.appendChild(element);

    // the first child represents exception's name
    Node child = node.getFirstChild();
    JsonML patt = new JsonML(TagType.IdPatt);
    patt.setAttribute(TagAttr.NAME, child.getString());
    element.appendChild(patt);

    // the second child represents content
    child = child.getNext();
    processNode(child, element);
  }

  private void processEmpty(Node node, JsonML currentParent) {
    if (currentParent.getType() == TagType.ArrayExpr) {
      // Empty expression are only found in Array literals
      currentParent.appendChild(new JsonML(TagType.Empty));
    } else {
      currentParent.appendChild(new JsonML(TagType.EmptyStmt));
    }
  }

  private void processExprResult(Node node, JsonML currentParent) {
    // this not interesting to JsonML, so we just need to skip it
    processNode(node.getFirstChild(), currentParent);
  }

  private void processForLoop(Node node, JsonML currentParent) {
    if (NodeUtil.isForIn(node)) {
      processLoop(node, currentParent, TagType.ForInStmt);
    } else {
      processLoop(node, currentParent, TagType.ForStmt);
    }
  }

  private void processFunction(Node node, JsonML currentParent) {
    JsonML element;
    if (NodeUtil.isFunctionDeclaration(node)) {
      element = new JsonML(TagType.FunctionDecl);
    } else {  // isFunctionExpresion == true
      element = new JsonML(TagType.FunctionExpr);
    }
    currentParent.appendChild(element);

    // the first child represents function's name
    Node child = node.getFirstChild();
    String name = child.getString();
    if (!name.equals("")) {
      JsonML nameElement = new JsonML(TagType.IdPatt);
      nameElement.setAttribute(TagAttr.NAME, name);
      element.appendChild(nameElement);
    } else {
      element.appendChild(new JsonML(TagType.Empty));
    }

    // the second child is a wrapper for formal parameters
    child = child.getNext();
    JsonML params = new JsonML(TagType.ParamDecl);
    element.appendChild(params);
    Iterator it = child.children().iterator();
    while (it.hasNext()) {
      JsonML param = new JsonML(TagType.IdPatt);
      Node nameNode = it.next();
      param.setAttribute(TagAttr.NAME, nameNode.getString());
      params.appendChild(param);
    }

    // the third child represents function's body
    child = child.getNext();

    // it can contain some directives
    processDirectives(child, element);

    it = child.children().iterator();
    while (it.hasNext()) {
      processNode(it.next(), element);
    }
  }

  private void processHook(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.ConditionalExpr);
    currentParent.appendChild(element);
    processChildren(node, element);
  }

  private void processIf(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.IfStmt);
    currentParent.appendChild(element);
    Iterator it = node.children().iterator();

    // there should be at least one child
    while (it.hasNext()) {
      processNode(it.next(), element);
    }
    // append EmptyStmt for each missing part
    int childCount = node.getChildCount();
    Preconditions.checkState(childCount >= 2);
    if (childCount < 3) { // no "else" part for sure
      element.appendChild(new JsonML(TagType.EmptyStmt));
    }
  }

  private void processIncrDecrExpr(Node node, JsonML currentParent,
      String op) {
    JsonML element = new JsonML(TagType.CountExpr);
    currentParent.appendChild(element);
    if (op.equals("++")) {
      element.setAttribute(TagAttr.OP, "++");
    } else { // op.euals("--")
      element.setAttribute(TagAttr.OP, "--");
    }

    if (node.getIntProp(Node.INCRDECR_PROP) == 1) {
      element.setAttribute(TagAttr.IS_PREFIX, false);
    } else { // INCRDECR_PROP == 0
      element.setAttribute(TagAttr.IS_PREFIX, true);
    }

    // there is exactly one child
    processNode(node.getFirstChild(), element);
  }

  private void processJmp(Node node, JsonML currentParent,
      TagType type) {
    JsonML element = new JsonML(type);
    currentParent.appendChild(element);

    // optional child may point to a label
    Node child = node.getFirstChild();
    if (child != null) {
      element.setAttribute(TagAttr.LABEL, child.getString());
    }
  }

  private void processLabel(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.LabelledStmt);
    currentParent.appendChild(element);

    // the first child represents label's name
    Node child = node.getFirstChild();
    element.setAttribute(TagAttr.LABEL, child.getString());

    // the second child represents labelled content
    child = child.getNext();
    processNode(child, element);
  }

  private void processLiteral(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.LiteralExpr);
    switch (node.getType()) {
      case Token.NUMBER:
        element.setAttribute(TagAttr.TYPE, "number");
        element.setAttribute(TagAttr.VALUE, node.getDouble());
        break;
      case Token.STRING:
        element.setAttribute(TagAttr.TYPE, "string");
        element.setAttribute(TagAttr.VALUE, node.getString());
        break;
      case Token.NULL:
        element.setAttribute(TagAttr.TYPE, "null");
        element.setAttribute(TagAttr.VALUE, null);
        break;
      case Token.TRUE:
        element.setAttribute(TagAttr.TYPE, "boolean");
        element.setAttribute(TagAttr.VALUE, true);
        break;
      case Token.FALSE:
        element.setAttribute(TagAttr.TYPE, "boolean");
        element.setAttribute(TagAttr.VALUE, false);
        break;
      default:
        throw new IllegalArgumentException("Illegal type of node.");
    }
    currentParent.appendChild(element);
  }

  private void processLogicalExpr(Node node, JsonML currentParent,
      String op) {
    if (op.equals("||")) {
      processTwoArgExpr(node, currentParent, TagType.LogicalOrExpr);
    } else if (op.endsWith("&&")) {
      processTwoArgExpr(node, currentParent, TagType.LogicalAndExpr);
    } else {
      throw new IllegalArgumentException("Unsupported value of op argument.");
    }
  }

  private void processLoop(Node node, JsonML currentParent,
      TagType type) {
    JsonML element = new JsonML(type);
    currentParent.appendChild(element);
    processChildren(node, element);
  }

  private void processMemberExpr(Node node, JsonML currentParent,
      String op) {
    JsonML element = new JsonML(TagType.MemberExpr);
    element.setAttribute(TagAttr.OP, op);
    currentParent.appendChild(element);

    // there should be exactly two children
    Node child = node.getFirstChild();
    processNode(child, element);
    processNode(child.getNext(), element);
  }

  private void processName(Node node, JsonML currentParent) {
    Preconditions.checkState(!node.hasChildren());

    JsonML element = new JsonML(TagType.IdExpr);
    element.setAttribute(TagAttr.NAME, node.getString());
    currentParent.appendChild(element);
  }

  private void processNew(Node node, JsonML currentParent, TagType type) {
    JsonML element = new JsonML(type);
    currentParent.appendChild(element);

    processChildren(node, element);
  }

  private void processObjectLiteral(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.ObjectExpr);
    currentParent.appendChild(element);
    for (Node key : node.children()) {
      Node value = key.getFirstChild();
      JsonML item;
      Object name;
      switch (key.getType()) {
        case Token.STRING:
          item = new JsonML(TagType.DataProp);
          name = key.getString();
          break;
        case Token.NUMBER:
          item = new JsonML(TagType.DataProp);
          name = key.getDouble();
          break;
        case Token.GETTER_DEF:
          item = new JsonML(TagType.GetterProp);
          name = key.getString();
          break;
        case Token.SETTER_DEF:
          item = new JsonML(TagType.SetterProp);
          name = key.getString();
          break;
        default:
          throw new IllegalArgumentException("Illegal type of node.");
      }
      item.setAttribute(TagAttr.NAME, name);
      processNode(value, item);
      element.appendChild(item);
    }
  }

  private void processRegExp(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.RegExpExpr);
    currentParent.appendChild(element);

    // first child represents expression's body
    Node child = node.getFirstChild();
    element.setAttribute(TagAttr.BODY, child.getString());

    // optional second child represents flags
    String flags = "";
    child = child.getNext();
    if (child != null) {
      flags = child.getString();
    }
    element.setAttribute(TagAttr.FLAGS, flags);
  }

  private void processSwitch(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.SwitchStmt);
    currentParent.appendChild(element);

    // the first child represents expression
    Node child = node.getFirstChild();
    processNode(child, element);

    // next children represent particular cases
    for (Node c = child.getNext(); c != null; c = c.getNext()) {
      processNode(c, element);
    }
  }

  private void processThis(Node node, JsonML currentParent) {
    currentParent.appendChild(new JsonML(TagType.ThisExpr));
  }

  private void processThrow(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.ThrowStmt);
    currentParent.appendChild(element);

    // there is exactly one child
    processNode(node.getFirstChild(), element);
  }

  private void processTry(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.TryStmt);
    currentParent.appendChild(element);

    // first child represents actual try block
    Node child = node.getFirstChild();
    processNode(child, element);

    // second child (precisely: child of that child) represents catch block
    child = child.getNext();
    if (child.hasChildren()) {
      processNode(child.getFirstChild(), element);
    } else {  // catch block is not present
      element.appendChild(new JsonML(TagType.Empty));
    }

    //optional third child represents finally block
    child = child.getNext();
    if (child != null) {
      processNode(child, element);
    }
  }

  private void processTwoArgExpr(Node node, JsonML currentParent,
      TagType type) {
    processTwoArgExpr(node, currentParent, type, null);
  }

  private void processTwoArgExpr(Node node, JsonML currentParent,
      TagType type, String op) {
    JsonML element = new JsonML(type);
    if (op != null) {
      element.setAttribute(TagAttr.OP, op);
    }
    currentParent.appendChild(element);

    Preconditions.checkState(node.getChildCount() == 2);
    Node child = node.getFirstChild();
    processNode(child, element);
    processNode(child.getNext(), element);
  }

  /**
   * Process nodes which JsonML represents by UnaryExpr.
   * @param node node to process
   * @param op operation for this unary expression - depends on node type
   */
  private void processUnaryExpr(Node node, JsonML currentParent,
      String op) {
    JsonML element = new JsonML(TagType.UnaryExpr);
    element.setAttribute(TagAttr.OP, op);
    currentParent.appendChild(element);

    processNode(node.getFirstChild(), element);
  }

  private void processVar(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.VarDecl);
    currentParent.appendChild(element);

    //there may be many actual declarations
    Iterator it = node.children().iterator();
    while (it.hasNext()) {
      Node child = it.next();  // this node represents var's id
                               // its own child represents initial value

      JsonML id = new JsonML(TagType.IdPatt);
      id.setAttribute(TagAttr.NAME, child.getString());

      if (child.hasChildren()) {
        JsonML patt = new JsonML(TagType.InitPatt);
        element.appendChild(patt);
        patt.appendChild(id);
        processNode(child.getFirstChild(), patt);
      } else {
        element.appendChild(id);
      }
    }
  }

  private void processReturn(Node currentNode, JsonML currentParent) {
    JsonML element = new JsonML(TagType.ReturnStmt);
    currentParent.appendChild(element);

    // there is exactly one child if return statement is not empty
    if (currentNode.hasChildren()) {
      processNode(currentNode.getFirstChild(), element);
    }
  }

  private void processScript(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.Program);
    currentParent.appendChild(element);

    processDirectives(node, element);

    processChildren(node, element);
  }

  private void processWith(Node node, JsonML currentParent) {
    JsonML element = new JsonML(TagType.WithStmt);
    currentParent.appendChild(element);

    // the first child represent object
    Node child = node.getFirstChild();
    processNode(child, element);

    // the second one represents content
    child = child.getNext();
    processNode(child, element);
  }

  private void processChildren(Node node, JsonML currentParent) {
    for (Node child : node.children()) {
      processNode(child, currentParent);
    }
  }

  private void processDirectives(Node node, JsonML currectParent) {
    Set directives = node.getDirectives();

    if (directives == null) {
      return;
    }

    for (String directive : directives) {
      JsonML element = new JsonML(TagType.PrologueDecl);
      element.setAttribute(TagAttr.DIRECTIVE, directive);
      element.setAttribute(TagAttr.VALUE, directive);
      currectParent.appendChild(element);
    }
  }

  private void processOneArgExpr(Node node, JsonML currentParent,
      TagType type) {
    JsonML element = new JsonML(type);
    currentParent.appendChild(element);

    // there is only one child node
    processNode(node.getFirstChild(), element);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy