組込みCPUでも動作するJavaScriptインタプリタEspruinoを触ってみます。
ECMAScriptにどれくらい対応してるのか実際に動かしてチェックしてみます。
Espruino公式ではEspruino対応しているボード等色々あります
http://www.espruino.com/
前半はRPiターゲットにコンパイルしてES対応チェック
後半で組込みCPUターゲットにコンパイルしてバイナリサイズを確認してみます。
Espruino version : 2v05.118
RPiターゲットでコンパイル
RPiターゲットでコンパイルします
$ git clone git@github.com:espruino/Espruino.git
$ cd Espruino
$ BOARD=RASPBERRYPI make
ファイルサイズは3.4MBくらいになりました。RPi上で実行してみます。
$ ./espruino
espruino: Interactive mode.
espruino: Size of JsVar is now 28 bytes
espruino: Size of JsVarRef is now 4 bytes
espruino: Added SIGINT hook
espruino: Added SIGHUP hook
espruino: Added SIGTERM hook
____ _
| __|___ ___ ___ _ _|_|___ ___
| __|_ -| . | _| | | | | . |
|____|___| _|_| |___|_|_|_|___|
|_| espruino.com
2v05.118 (c) 2019 G.Williams
Espruino is Open Source. Our work is supported
only by sales of official boards and donations:
http://espruino.com/Donate
>
問題なく動作
ESの対応状況
Espruino公式が出しているES対応表はこちら
http://www.espruino.com/Features
基本的にはES5、ES6の一部対応してるようす
アロー関数
アロー関数、 const 、let は問題なくいけます
const hello = () => { console.log('hello'); }
let world = () => { console.log('world'); }
hello();
world();
$ ./espruino hello.js
____ _
| __|___ ___ ___ _ _|_|___ ___
| __|_ -| . | _| | | | | . |
|____|___| _|_| |___|_|_|_|___|
|_| espruino.com
2v05.118 (c) 2019 G.Williams
Espruino is Open Source. Our work is supported
only by sales of official boards and donations:
http://espruino.com/Donate
hello
world
※実行すると毎回キャプションが出ますが以下カット
Promise
Promiseも対応OK
finallyはES9仕様ですがついでに対応してないかなと確認してみたところ、finallyは未対応でした
function pr(err) {
return new Promise((resolve, reject) => {
if(err) { reject(new Error('!!!error!!!')); }
else { resolve('hello'); }
});
}
pr(false)
.then( res => { console.log(res); } )
.catch( e => { console.log('error : '+e.message); } );
pr(true)
.then( res => { console.log(res); } )
.catch( e => { console.log('error : '+e.message); } );
$ ./espruino promise.js
hello
error : !!!error!!!
async/await
async/awaitは未対応
function pr(err) {
return new Promise((resolve, reject) => {
if(err) { reject(new Error('!!!error!!!')); }
else { resolve('hello'); }
});
}
async function foo() {
const ret = await pr(false);
console.log(ret);
}
foo();
$ ./espruino async.js
Uncaught ReferenceError: "async" is not defined
class
classは対応OK
class cl {
constructor() {
console.log('cl constructor');
}
pr(err) {
return new Promise((resolve, reject) => {
if(err) { reject(new Error('!!!error!!!')); }
else { resolve('hello'); }
});
}
}
const c = new cl();
c.pr(false)
.then( res => { console.log(res); } );
$ ./espruino cl.js
cl constructor
hello
EventEmitter
Node.jsのノリで require('events')
すると、Espruinoでは「そんなモジュールない!」と怒られます
const EventEmitter = require('events');
const em = new EventEmitter();
em.on('foo', (val) => { console.log('hello', val); });
em.emit('foo', 'world');
$ ./espruino emit.js
Uncaught Error: Module events not found
公式を調べてみると、on/emitはObjectクラスの組込み関数として扱われている様子
https://www.espruino.com/Reference#Object
Object.on('foo', (val) => { console.log('hello', val); });
Object.emit('foo', 'world');
$ ./espruino emit-espruino.js
hello world
requireでファイルロード
組込み系は基本的にはファイルシステムの概念がないので
Node.jsのようにrequireで自前のファイルをロードするという方法はEspruinoでは取っておらず
基本的に1ファイルにフラット化して実行しましょうというスタンスらしい
例えば以下2ファイルを用意したとき
class exp {
constructor() {
console.log('exp constructor');
}
hello() {
console.log('hello');
}
}
module.exports = exp;
const exp = require('./exp');
const e = new exp();
e.hello();
Node.jsでは問題なく実行できるが
$ node req.js
exp constructor
hello
espruinoではexpファイルなんてものはないと怒られる
$ ./espruino req.js
Uncaught Error: Module ./exp not found
そこで、requireのファイル依存関係をなくすためにbrowserifyを使います
$ sudo npm install -g browserify
$ browserify req.js -o req.bundle.js
browserify された req.bundle.js を espruino に流すと実行できるようになりました
$ ./espruino req.bundle.js
exp constructor
hello
browserifyで自動生成された req.bundle.js のファイルの中身
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
class exp {
constructor() {
console.log('exp constructor');
}
hello() {
console.log('hello');
}
}
module.exports = exp;
},{}],2:[function(require,module,exports){
const exp = require('./exp');
const e = new exp();
e.hello();
},{"./exp":1}]},{},[2]);
組込みCPUターゲット時のバイナリサイズ
最後に、組込みCPUをターゲットにしたときのバイナリサイズはどれくらいになるのかが気になったので確認しました。
評価ボード NUCLEO-F401RE をターゲットにしたときのバイナリサイズを確認。
組込みCPU STM32F401RE のFlash 512KB に対して Espruino 356KB とかなり容量取られてます。
ドライバ全部入りになってるはずなので削ることができればもう少し減らせるかも。
$ sudo apt install -y binutils-arm-none-eabi gcc-arm-none-eabi
$ make clean
$ BOARD=NUCLEOF401RE make
$ ls -lh
-rwxr-xr-x 1 pi pi 356K May 30 15:45 espruino_2v05.118_nucleof401re.bin