1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

組込み向けJSインタプリタEspruinoをRaspberryPi上で試す

Last updated at Posted at 2020-05-30

組込み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 は問題なくいけます

hello.js
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は未対応でした

promise.js
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は未対応

async.js
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

cl.js
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では「そんなモジュールない!」と怒られます

emit.js
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

emit-espruino.js
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ファイルを用意したとき

exp.js
class exp {
  constructor() {
    console.log('exp constructor');
  }

  hello() {
    console.log('hello');
  }
}

module.exports = exp;
req.js
const exp = require('./exp');
const e = new exp();
e.hello();

Node.jsでは問題なく実行できるが

Node.js
$ node req.js
exp constructor
hello

espruinoではexpファイルなんてものはないと怒られる

espruino
$ ./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 のファイルの中身

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 STM32F401REFlash 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
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?