Rhinoを利用してJavaScriptの文法を確認する

# はじめに

[Rhino](https://github.com/mozilla/rhino)は、Javaで記述されたJavaScriptのオープンソースな実装のことで、Javaアプリケーション環境へ組み込むことでエンドユーザによるスクリプトの記述が可能になります。

![Rhino](https://qiita-image-store.s3.amazonaws.com/0/3862/04c1454a-4072-56c8-9324-d7f1c31d235b.jpeg)

Rhinoを利用してJavaScriptの文法が正しいか確認します。

# サンプルコード

Rhinoをダウンロードしてパスを追加します。
文法が正しいとき構文木を出力するようにします。

```java:Main.java
import java.io.BufferedReader;
import java.io.FileReader;
import org.mozilla.javascript.*;
import org.mozilla.javascript.ast.AstRoot;

public class Main {
	public static void main(String args[]) 
	{
		String source = Main.fileReader("test.js");
		try {
			AstRoot astRoot = new Parser().parse(source, "", 1);
			System.out.println(astRoot.debugPrint());
		}catch(org.mozilla.javascript.EvaluatorException e) {
			e.printStackTrace();
			System.err.println(e.lineNumber());
		}
	}
	
	public static String fileReader(String fileName)
	{
		StringBuilder sb = new StringBuilder(""); 
		try {
			@SuppressWarnings("resource")
			BufferedReader reader = new BufferedReader(new FileReader(fileName));
			String line;
			while((line = reader.readLine()) != null)
				sb.append(line + System.getProperty("line.separator"));
		}catch(Exception e) {
			System.err.println("No such file or directory");
			System.exit(0);
		}
		return sb.toString();
	}
}

```

`test.js` の内容は以下のとおりです。

```js:test.js
function sum(a, b)
{
	return a + b;
}

var a = 1;
sum(a, 2);
```

# 実行結果

文法が正しいので、構文木が出力されます。

```
0	SCRIPT 0 60
0	  FUNCTION 0 37
9	    NAME 9 3 sum
13	    NAME 13 1 a
16	    NAME 16 1 b
19	    BLOCK 19 18
22	      RETURN 3 13
29	        ADD 7 5
29	          NAME 0 1 a
33	          NAME 4 1 b
39	  VAR 39 10
43	    VAR 4 5
43	      NAME 0 1 a
47	      NUMBER 4 1
50	  EXPR_RESULT 50 10
50	    CALL 0 9
50	      NAME 0 3 sum
54	      NAME 4 1 a
57	      NUMBER 7 1
```

# 例外

`test.js` を書き換えてわざと例外を発生させます。

```js:test.js
function sum(a, b)
{
	return a +
}

var a = 1;
sum(a, 2);
```

例外が発生しました。
`System.err.println(e.lineNumber());`で行番号を表示します。
この場合、4行目付近に文法の誤りがあることがわかります。

```
org.mozilla.javascript.EvaluatorException: syntax error (#4)
	at org.mozilla.javascript.DefaultErrorReporter.runtimeError(DefaultErrorReporter.java:77)
	at org.mozilla.javascript.DefaultErrorReporter.error(DefaultErrorReporter.java:64)
	at org.mozilla.javascript.Parser.addError(Parser.java:188)
	at org.mozilla.javascript.Parser.addError(Parser.java:166)
	at org.mozilla.javascript.Parser.reportError(Parser.java:223)
	at org.mozilla.javascript.Parser.reportError(Parser.java:210)
	at org.mozilla.javascript.Parser.reportError(Parser.java:203)
	at org.mozilla.javascript.Parser.primaryExpr(Parser.java:2837)
	at org.mozilla.javascript.Parser.memberExpr(Parser.java:2418)
	at org.mozilla.javascript.Parser.unaryExpr(Parser.java:2316)
	at org.mozilla.javascript.Parser.mulExpr(Parser.java:2241)
	at org.mozilla.javascript.Parser.addExpr(Parser.java:2230)
	at org.mozilla.javascript.Parser.shiftExpr(Parser.java:2206)
	at org.mozilla.javascript.Parser.relExpr(Parser.java:2181)
	at org.mozilla.javascript.Parser.eqExpr(Parser.java:2153)
	at org.mozilla.javascript.Parser.bitAndExpr(Parser.java:2142)
	at org.mozilla.javascript.Parser.bitXorExpr(Parser.java:2131)
	at org.mozilla.javascript.Parser.bitOrExpr(Parser.java:2120)
	at org.mozilla.javascript.Parser.andExpr(Parser.java:2109)
	at org.mozilla.javascript.Parser.orExpr(Parser.java:2098)
	at org.mozilla.javascript.Parser.condExpr(Parser.java:2062)
	at org.mozilla.javascript.Parser.assignExpr(Parser.java:2033)
	at org.mozilla.javascript.Parser.expr(Parser.java:2012)
	at org.mozilla.javascript.Parser.returnOrYield(Parser.java:1636)
	at org.mozilla.javascript.Parser.statementHelper(Parser.java:999)
	at org.mozilla.javascript.Parser.statement(Parser.java:901)
	at org.mozilla.javascript.Parser.parseFunctionBody(Parser.java:634)
	at org.mozilla.javascript.Parser.function(Parser.java:795)
	at org.mozilla.javascript.Parser.parse(Parser.java:533)
	at org.mozilla.javascript.Parser.parse(Parser.java:478)
	at Main.main(Main.java:11)
4
```