JScript の REPL 作ってみた
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ REPL
この記事の内容のために作りました
REPL ってすごく便利ですよね
このコードで結果がどうなるのかちょっと確認したいとか 返り値のデータ構造を実行しながら見ていきたいとか
REPL があるかないかでその言語の理解のしやすさが一気に変わります
今回は JScript でエクセル操作してみようかな というところで エクセルのオブジェクトとかを これで動くのかとか適当に REPL で試しながら使えると楽そうなので作りました
デフォルトの JScript は IE7 くらいのエンジンなのですごく古くて使う気になりません
なので Windows10 限定になりますが Edge のエンジンを使って REPL を作ります
Gist
Gist
というのも 前に作ってたのを忘れてて 新しく作ったんですよね
2つ目が新しい方です
この時調べてた方法だと stdin.AtEndOfStream を使ってた例があったので使ってみました
boolean 値を返すだけのように書かれていますが 参照するとここでキーボード入力を待機になります
stdin.ReadLine() で待機すると思っていたのでちゃんと動かずちょっとハマりました
プロンプト 「>」 を表示するなら ReadLine() の直前でなく AtEndOfStream の直前にする必要があります
また 1 つ目は単純にやってるので 短いですが eval されるスコープで参照出来るものが多いです
2 つ目では generator を使って yield と next() でデータの受け渡しをして eval するスコープで参照可能なものは最小限にしてます
どちらも while ループの中で try catch をしている都合上 ブロックスコープの const や let は毎回クリアされます
使うなら 1 回の実行で定義と使用をしてしまう必要アリです
1 つめだと 「\」 2 つめだと 「\n」 で実行せずに複数行入力になります
「\」 だと単に複数行書けるだけで改行はしないように見えますが セミコロン無しで書くために内部的には改行になります
そこが 「\」 と直感に反するかなということで 新しい方は 「\n」 にしました
ちょっと書く時大変ですが わかりやすさをとりました
基本的にはこれくらい
シンプルな REPL です
実行例のところにあるように Edge エンジンを使うために Edge の CLSID を指定しないといけません
これを忘れると IE 並の機能しか使えません
まぁこれが原因でせっかく作った REPL が…………になったのですが そこは元記事のほうをみてください
REPL ってすごく便利ですよね
このコードで結果がどうなるのかちょっと確認したいとか 返り値のデータ構造を実行しながら見ていきたいとか
REPL があるかないかでその言語の理解のしやすさが一気に変わります
今回は JScript でエクセル操作してみようかな というところで エクセルのオブジェクトとかを これで動くのかとか適当に REPL で試しながら使えると楽そうなので作りました
デフォルトの JScript は IE7 くらいのエンジンなのですごく古くて使う気になりません
なので Windows10 限定になりますが Edge のエンジンを使って REPL を作ります
REPL
let acc = ""
while(true){
WScript.StdOut.Write("> ")
const input = WScript.StdIn.ReadLine()
if(input === "exit"){
break
}
if(input.endsWith("\\")){
acc += input.slice(0, -1) + "\n"
continue
}
const source = acc + input
acc = ""
try{
const [result = "undefined" ] = [eval(source)]
WScript.Echo(result)
}catch(err){
WScript.Echo(err.message)
WScript.Echo(err.stack)
}
}
while(true){
WScript.StdOut.Write("> ")
const input = WScript.StdIn.ReadLine()
if(input === "exit"){
break
}
if(input.endsWith("\\")){
acc += input.slice(0, -1) + "\n"
continue
}
const source = acc + input
acc = ""
try{
const [result = "undefined" ] = [eval(source)]
WScript.Echo(result)
}catch(err){
WScript.Echo(err.message)
WScript.Echo(err.stack)
}
}
C:\Users\user\Desktop>cscript //E:{1b7cd997-e5ff-4932-a7a6-2a9e636da385} repl.js
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
> if(true){\
> 1\
> }
1
> var a = 10
undefined
> a
10
> exit
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
> if(true){\
> 1\
> }
1
> var a = 10
undefined
> a
10
> exit
Gist
REPL(2)
const g = function*(___){
while(true)
try {
___ = eval(yield ___)
} catch(error) {
___ = {error}
}
}()
g.next()
!function(){
const stdin = WScript.StdIn
const stdout = WScript.StdOut
let str = ""
let neos = true
while (neos){
stdout.Write("> ")
if (neos = !stdin.AtEndOfStream) {
str += stdin.ReadLine()
if (str.endsWith("\\n")) {
str = str.replace(/\\n$/, "\n")
continue
}
const result = g.next(str).value
if (result && result.error) {
stdout.WriteLine(result.error.message)
} else {
try {
stdout.WriteLine(result)
} catch (err) {
stdout.WriteLine("Cannot print")
}
}
str = ""
} else {
stdout.WriteLine("Bye.")
}
}
}()
while(true)
try {
___ = eval(yield ___)
} catch(error) {
___ = {error}
}
}()
g.next()
!function(){
const stdin = WScript.StdIn
const stdout = WScript.StdOut
let str = ""
let neos = true
while (neos){
stdout.Write("> ")
if (neos = !stdin.AtEndOfStream) {
str += stdin.ReadLine()
if (str.endsWith("\\n")) {
str = str.replace(/\\n$/, "\n")
continue
}
const result = g.next(str).value
if (result && result.error) {
stdout.WriteLine(result.error.message)
} else {
try {
stdout.WriteLine(result)
} catch (err) {
stdout.WriteLine("Cannot print")
}
}
str = ""
} else {
stdout.WriteLine("Bye.")
}
}
}()
C:\Users\user\Desktop>cscript jsconsole.js //E:{1b7cd997-e5ff-4932-a7a6-2a9e636da385}
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
> var a = 1
> a
1
> const b = 2
> b
'b' is undefined
> const b = 10;a + b
11
> let c = 100\n
> let d = 200\n
> c*d
20000
> ^Z
Bye.
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
> var a = 1
> a
1
> const b = 2
> b
'b' is undefined
> const b = 10;a + b
11
> let c = 100\n
> let d = 200\n
> c*d
20000
> ^Z
Bye.
Gist
2つあった
2つありますというのも 前に作ってたのを忘れてて 新しく作ったんですよね
2つ目が新しい方です
この時調べてた方法だと stdin.AtEndOfStream を使ってた例があったので使ってみました
boolean 値を返すだけのように書かれていますが 参照するとここでキーボード入力を待機になります
stdin.ReadLine() で待機すると思っていたのでちゃんと動かずちょっとハマりました
プロンプト 「>」 を表示するなら ReadLine() の直前でなく AtEndOfStream の直前にする必要があります
また 1 つ目は単純にやってるので 短いですが eval されるスコープで参照出来るものが多いです
2 つ目では generator を使って yield と next() でデータの受け渡しをして eval するスコープで参照可能なものは最小限にしてます
どちらも while ループの中で try catch をしている都合上 ブロックスコープの const や let は毎回クリアされます
使うなら 1 回の実行で定義と使用をしてしまう必要アリです
1 つめだと 「\」 2 つめだと 「\n」 で実行せずに複数行入力になります
「\」 だと単に複数行書けるだけで改行はしないように見えますが セミコロン無しで書くために内部的には改行になります
そこが 「\」 と直感に反するかなということで 新しい方は 「\n」 にしました
ちょっと書く時大変ですが わかりやすさをとりました
基本的にはこれくらい
シンプルな REPL です
実行例のところにあるように Edge エンジンを使うために Edge の CLSID を指定しないといけません
これを忘れると IE 並の機能しか使えません
まぁこれが原因でせっかく作った REPL が…………になったのですが そこは元記事のほうをみてください