/*
* Copyright (C) 2012-2016 NS Solutions Corporation
*
* 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.htmlhifive.tools.rhino;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.mozilla.javascript.Node;
import org.mozilla.javascript.Token;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.Comment;
import org.mozilla.javascript.ast.Name;
import org.mozilla.javascript.ast.Word;
/**
* ユーティリティ.
*/
public class Util {
/** ファイル出力時の文字コード. */
public static final String ENCODE = "UTF-8";
/** インデント文字列 */
public static final String INDENT = " ";
/**
* インデント文字列を生成する.
*
* @param indent
* @return
*/
public static String makeIndent(int indent) {
if (0 == indent) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < indent; i++) {
sb.append(INDENT);
}
return sb.toString();
}
/**
* 兄弟として、1つ前のノードを返す.
*
* @param node
* @return
*/
public static AstNode getPrev(AstNode node) {
AstNode parent = node.getParent();
if (null == parent) {
return null;
}
Node prev = null;
Node child = parent.getFirstChild();
while (null != child) {
if (child == node) {
return (AstNode) prev;
}
prev = child;
child = child.getNext();
}
return null;
}
/**
* 子ノード中、木構造上最初のノードを返す.
*
* @param node
* @return
*/
public static AstNode getFirst(AstNode node) {
if (null == node) {
return null;
}
AstNode first = (AstNode) node.getFirstChild();
if (null == first) {
return node;
} else {
return getFirst(first);
}
}
/**
* 子ノード中、木構造上最後のノードを返す.
*
* @param node
* @return
*/
public static AstNode getLast(AstNode node) {
if (null == node) {
return null;
}
AstNode last = (AstNode) node.getLastChild();
if (null == last) {
return node;
} else {
return getLast(last);
}
}
/**
* 1つ前に追加する.
*
* @param newNode
* @param node
*/
public static void addBefore(AstNode newNode, AstNode node) {
AstNode parent = node.getParent();
if (null == parent) {
return;
}
Node prev = null;
Node child = parent.getFirstChild();
while (null != child) {
if (child == node) {
if (null != prev) {
parent.addChildAfter(newNode, prev);
} else {
parent.addChildrenToFront(newNode);
}
newNode.setParent(parent);
return;
}
prev = child;
child = child.getNext();
}
}
/**
* ツリー中のノード情報を表示する.
*
* @param node
* @return
*/
public static String printTree(AstNode node) {
StringBuilder sb = new StringBuilder(printNode(node));
Node child = node.getFirstChild();
while (null != child) {
sb.append(printTree((AstNode) child));
child = child.getNext();
}
return sb.toString();
}
public static String printNode(AstNode node) {
StringBuilder sb = new StringBuilder();
// int depth = getPropValue(node, Constants.DEPTH);
int depth = node.depth();
String indent = makeIndent(depth);
sb.append(indent);
String name = typeToName(node);
sb.append(name);
sb.append("(lno:");
sb.append(node.getLineno());
sb.append(", abp:");
sb.append(node.getAbsolutePosition());
sb.append(", pos:");
sb.append(node.getPosition());
sb.append(", len:");
sb.append(node.getLength());
sb.append(")");
int tt = node.getType();
if (tt == Token.NAME) {
String identifier = ((Name) node).getIdentifier();
sb.append(identifier);
} else if (node instanceof Word || node instanceof Comment) {
String value = null;
if (node instanceof Word) {
value = ((Word) node).getValue();
} else {
value = ((Comment) node).getValue();
}
if (null != value) {
value = value.replaceAll("\n", "\\\\n");
value = value.replaceAll("\r", "\\\\r");
value = value.substring(0, Math.min(30, value.length()));
sb.append("\"" + value + "\"");
}
}
sb.append("\n");
return sb.toString();
}
/**
*
* @param node
* @return
*/
public static String typeToName(Node node) {
if (node instanceof Word) {
return "WORD";
}
int type = node.getType();
String name = Token.typeToName(type);
return name;
}
/**
* ファイルにjson情報を格納する.
*
* @param g
* @param file
* @throws IOException
*/
public static void dumpToFile(AstNode node, File file) throws IOException {
if (file.getParentFile().mkdirs()) {
System.out.println("mkdirs" + file.getParentFile().getAbsolutePath());
}
String src = SourceMaker.toSource(node);
FileUtils.write(file, src, ENCODE, false);
}
/**
* ノードのプロパティ値を返す.
*
* @param node
* @param prop
* @return
*/
public static int getPropValue(Node node, int prop) {
if (null == node) {
return 0;
}
Integer propObj = (Integer) node.getProp(prop);
if (null != propObj) {
return propObj.intValue();
}
return 0;
}
/**
* 文字列中、指定された文字の数を返す.
*
* @param word
* @param ch
* @return
*/
public static int count(String word, char ch) {
int count = 0;
for (int i = 0; i < word.length(); i++) {
if (word.charAt(i) == ch) {
count++;
}
}
return count;
}
/**
* ノードを追加する.文字列追加
*
* @param an
* @param pos
* @param str
* @return
*/
public static int addChild(AstNode an, int pos, String str) {
if (null == str) {
return pos;
}
Word child = new Word(pos, str);
return addChild(an, child, 0, 0);
}
/**
* ノートを追加する。子ノード追加
*
* @param an
* @param child
* @param depth
* @return
*/
public static int addChild(AstNode an, AstNode child, int depth) {
return addChild(an, child, depth, 0);
}
/**
* ノードを追加する.子ノード追加
*
* @param an
* @param child
* @param depth
* @param indent
* @return
*/
public static int addChild(AstNode an, AstNode child, int depth, int indent) {
return addChild(an, child, depth, indent, false);
}
/**
* ノードを追加する.子ノード追加
*
* @param an
* @param child
* @param depth
* @param indent
* @param trim
* @return
*/
public static int addChild(AstNode an, AstNode child, int depth, int indent, boolean trim) {
// an.addChild(child);
an.addChildToBack(child);
int positionBackup = child.getPosition();
child.setParent(an);
child.setPosition(positionBackup);
child.putProp(Constants.DEPTH, depth);
child.putProp(Constants.INDENT, indent);
if (trim) {
child.putProp(Constants.TRIM, trim);
}
return child.getPosition() + child.getLength();
}
/**
* ノードを追加する.
*
* @param an
* @param pos
* @param children
* @param depth
* @return
*/
public static <T> int addChildren(AstNode an, int pos, List<T> children, int depth) {
return addChildren(an, pos, children, depth, false);
}
/**
* 複数のノードを追加する.
*
* @param an
* @param pos
* @param children
* @param depth
* @param ln
* @return
*/
public static <T> int addChildren(AstNode an, int pos, List<T> children, int depth, boolean ln) {
if (null == children || 0 == children.size()) {
return pos;
}
int i = 0;
for (T childT : children) {
AstNode child = (AstNode) childT;
if (i++ != 0) {
if (ln) {
pos = addChild(an, pos, ",");
} else {
pos = addChild(an, pos, ", ");
}
}
if (ln) {
pos = addChild(an, pos, "\n");
int newDepth = depth + 1;
pos = addChild(an, child, newDepth, newDepth);
} else {
pos = addChild(an, child, depth);
}
}
if (ln) {
pos = addChild(an, pos, "\n");
pos = addChild(an, pos, Util.makeIndent(depth));
}
return pos;
}
/**
* 複数のver句を追加する.
*
* @param an
* @param pos
* @param children
* @param depth
* @param ln
* @return
*/
public static <T> int addChildrenForVariables(AstNode an, int pos, List<T> children, int depth, boolean ln) {
if (null == children || 0 == children.size()) {
return pos;
} else if (1 == children.size()) {
return addChild(an, (AstNode) children.get(0), depth);
} else {
int i = 0;
int newDepth = depth + 1;
for (T childT : children) {
AstNode child = (AstNode) childT;
if (i != 0) {
if (ln) {
pos = addChild(an, pos, ",");
} else {
pos = addChild(an, pos, ", ");
}
}
if (ln) {
if (i == 0) {
pos = addChild(an, child, newDepth, 0);
} else {
pos = addChild(an, pos, "\n");
pos = addChild(an, child, newDepth, newDepth);
}
} else {
pos = addChild(an, child, depth);
}
i++;
}
return pos;
}
}
public static boolean isVSDoc(String str) {
return StringUtils.startsWith(str, "///");
}
}