| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- const JSZM = require('./jszm-async')
- const defer = () => {
- const deferred = {
- resolve: value => (deferred._resolved = value),
- reject: err => (deferred._rejected = err)
- }
- const promise = new Promise((resolve, reject) => {
- if (deferred.hasOwnProperty('_resolved')) return resolve(deferred._resolved)
- if (deferred.hasOwnProperty('_rejected')) return reject(deferred._rejected)
- deferred.resolve = resolve
- deferred.reject = reject
- })
- deferred.promise = promise
- return deferred
- }
- class VM {
- constructor(data, save) {
- this.zm = new JSZM(data)
- const vm = this
- let printBuffer = []
- const transcript = []
- this.inputBuffer = []
- this.outputBuffer = []
- this.saveData = save
- this.zm.save = function*(buf) {
- vm.saveData = buf
- return true
- }
- this.zm.restore = function*() {
- return this.saveData
- }
- this.zm.highlight = function*(a) {
- //printBuffer.push(`[${a}]`)
- }
- this.zm.print = function*(text, scripting) {
- printBuffer.push(text)
- if (scripting) {
- transcript.push(text)
- }
- }
- const flush = () => {
- const output = printBuffer.join('')
- printBuffer = []
- if (this.outputBuffer.length) {
- const deferred = this.outputBuffer.shift()
- deferred.resolve(output)
- } else {
- this.initialOutput = output
- }
- }
- vm.reader = null
- this.zm.read = async function*(maxlen) {
- flush() // Should only read after done writing, so flush what it's written.
- if (vm.reader) throw new Error('Simultaneous reads')
- if (vm.inputBuffer.length) {
- const text = this.inputBuffer.shift()
- return text
- } else {
- const deferred = defer()
- vm.reader = deferred
- const text = await deferred.promise
- vm.reader = null
- return text
- }
- }
- }
- start() {
- if (this._started) throw new Error('Already started')
- const deferred = defer()
- this.outputBuffer.push(deferred)
- this.zm.run().next()
- return deferred.promise
- }
- play(text) {
- const deferred = defer()
- this.outputBuffer.push(deferred)
- if (this.reader) {
- this.reader.resolve(text)
- } else {
- this.inputBuffer.push(text)
- }
- return deferred.promise
- }
- save() {
- return Buffer.from(this.zm.serialize([], [])).toString('base64')
- }
- restore(save) {
- this.zm.deserialize(Buffer.from(save, 'base64'))
- }
- }
- VM.play = async (data, save, input) => {
- const vm = new VM(data)
- const ret = {}
- ret.output = await vm.start()
- if (save) {
- vm.saveData = Buffer.from(save, 'base64')
- ret.output = vm.zm.deserialize(vm.saveData)
- }
- if (input) {
- ret.output = await vm.play(input)
- }
- ret.save = Buffer.from(vm.zm.serialize([],[])).toString('base64')
- return ret
- }
- module.exports = VM
|