alan-js-runtime
Advanced tools
Comparing version 0.1.36 to 0.1.37
273
index.js
require('cross-fetch/polyfill') | ||
const EventEmitter = require('events') | ||
const http = require('http') | ||
const net = require('net') | ||
const util = require('util') | ||
@@ -21,2 +22,7 @@ | ||
// JS really doesn't have BigInt equivalents of these? | ||
const BigMin = (a, b) => a < b ? a : b | ||
const BigMax = (a, b) => a > b ? a : b | ||
const BigAbs = a => a > 0n ? a : -a // A six pack? | ||
// Hashing opcodes (hashv is recursive, needs to be defined outside of the export object) | ||
@@ -100,2 +106,5 @@ const hashcore = (hasher, a) => { | ||
// Same justification for the TCP server | ||
const tcpConns = {} | ||
// The shared mutable state for the datastore library | ||
@@ -260,4 +269,4 @@ const ds = {} | ||
const b = rb[1] | ||
if (a > 0n && b < 0n && a > INT32MAX + b) return [false, 'overflow'] | ||
if (a < 0n && b > 0n && a < INT32MIN + b) return [false, 'underflow'] | ||
if (a > 0n && b < 0n && a > INT64MAX + b) return [false, 'overflow'] | ||
if (a < 0n && b > 0n && a < INT64MIN + b) return [false, 'underflow'] | ||
return [true, a - b] | ||
@@ -286,15 +295,15 @@ }, | ||
negi8: a => 0 - a, | ||
negi16: a => 0 - a, | ||
negi32: a => 0 - a, | ||
negi64: a => 0n - a, | ||
negf32: a => 0.0 - a, | ||
negf64: a => 0.0 - a, | ||
negi8: ra => !ra[0] ? ra : (0 - ra[1] <= INT8MAX ? [true, 0 - ra[1]] : [false, 'overflow']), | ||
negi16: ra => !ra[0] ? ra : (0 - ra[1] <= INT16MAX ? [true, 0 - ra[1]] : [false, 'overflow']), | ||
negi32: ra => !ra[0] ? ra : (0 - ra[1] <= INT32MAX ? [true, 0 - ra[1]] : [false, 'overflow']), | ||
negi64: ra => !ra[0] ? ra : (0n - ra[1] <= INT64MAX ? [true, 0n - ra[1]] : [false, 'overflow']), | ||
negf32: ra => !ra[0] ? ra : [true, 0.0 - a], | ||
negf64: ra => !ra[0] ? ra : [true, 0.0 - a], | ||
absi8: a => Math.abs(a), | ||
absi16: a => Math.abs(a), | ||
absi32: a => Math.abs(a), | ||
absi64: a => a > 0n ? a : -a, | ||
absf32: a => Math.abs(a), | ||
absf64: a => Math.abs(a), | ||
absi8: ra => !ra[0] ? ra : (Math.abs(ra[1]) <= INT8MAX ? [true, Math.abs(ra[1])] : [false, 'overflow']), | ||
absi16: ra => !ra[0] ? ra : (Math.abs(ra[1]) <= INT16MAX ? [true, Math.abs(ra[1])] : [false, 'overflow']), | ||
absi32: ra => !ra[0] ? ra : (Math.abs(ra[1]) <= INT32MAX ? [true, Math.abs(ra[1])] : [false, 'overflow']), | ||
absi64: ra => !ra[0] ? ra : (BigAbs(ra[1]) <= INT64MAX ? [true, BigAbs(ra[1])] : [false, 'overflow']), | ||
absf32: ra => !ra[0] ? ra : [true, Math.abs(ra[1])], | ||
absf64: ra => !ra[0] ? ra : [true, Math.abs(ra[1])], | ||
@@ -488,2 +497,138 @@ muli8: (ra, rb) => { | ||
// Saturating arithmetic | ||
saddi8: (a, b) => { | ||
if (a > 0 && b > 0 && a > INT8MAX - b) return INT8MAX | ||
if (a < 0 && b < 0 && a < INT8MIN - b) return INT8MIN | ||
return a + b | ||
}, | ||
saddi16: (a, b) => { | ||
if (a > 0 && b > 0 && a > INT16MAX - b) return INT16MAX | ||
if (a < 0 && b < 0 && a < INT16MIN - b) return INT16MIN | ||
return a + b | ||
}, | ||
saddi32: (a, b) => { | ||
if (a > 0 && b > 0 && a > INT32MAX - b) return INT32MAX | ||
if (a < 0 && b < 0 && a < INT32MIN - b) return INT32MIN | ||
return a + b | ||
}, | ||
saddi64: (a, b) => { | ||
if (a > 0n && b > 0n && a > INT64MAX - b) return INT64MAX | ||
if (a < 0n && b < 0n && a < INT64MIN - b) return INT64MIN | ||
return a + b | ||
}, | ||
saddf32: (a, b) => a + b, | ||
saddf64: (a, b) => a + b, | ||
ssubi8: (a, b) => { | ||
if (a > 0 && b < 0 && a > INT8MAX + b) return INT8MAX | ||
if (a < 0 && b > 0 && a < INT8MIN + b) return INT8MIN | ||
return a - b | ||
}, | ||
ssubi16: (a, b) => { | ||
if (a > 0 && b < 0 && a > INT16MAX + b) return INT16MAX | ||
if (a < 0 && b > 0 && a < INT16MIN + b) return INT16MIN | ||
return a - b | ||
}, | ||
ssubi32: (a, b) => { | ||
if (a > 0 && b < 0 && a > INT32MAX + b) return INT32MAX | ||
if (a < 0 && b > 0 && a < INT32MIN + b) return INT32MIN | ||
return a - b | ||
}, | ||
ssubi64: (a, b) => { | ||
if (a > 0n && b < 0n && a > INT64MAX + b) return INT64MAX | ||
if (a < 0n && b > 0n && a < INT64MIN + b) return INT64MIN | ||
return a - b | ||
}, | ||
ssubf32: (a, b) => a - b, | ||
ssubf64: (a, b) => a - b, | ||
snegi8: a => Math.min(0 - a, INT8MAX), | ||
snegi16: a => Math.min(0 - a, INT16MAX), | ||
snegi32: a => Math.min(0 - a, INT32MAX), | ||
snegi64: a => BigMin(0n - a, INT64MAX), | ||
snegf32: a => 0.0 - a, | ||
snegf64: a => 0.0 - a, | ||
sabsi8: a => Math.min(Math.abs(a), INT8MAX), | ||
sabsi16: a => Math.min(Math.abs(a), INT16MAX), | ||
sabsi32: a => Math.min(Math.abs(a), INT32MAX), | ||
sabsi64: a => BigMin(a > 0n ? a : -a, INT64MAX), | ||
sabsf32: a => Math.abs(a), | ||
sabsf64: a => Math.abs(a), | ||
smuli8: (a, b) => { | ||
if (a > 0 && b > 0 && a > INT8MAX / b) return INT8MAX | ||
if (a < 0 && b < 0 && a < INT8MIN / b) return INT8MIN | ||
return a * b | ||
}, | ||
smuli16: (a, b) => { | ||
if (a > 0 && b > 0 && a > INT16MAX / b) return INT16MAX | ||
if (a < 0 && b < 0 && a < INT16MIN / b) return INT16MIN | ||
return a * b | ||
}, | ||
smuli32: (a, b) => { | ||
if (a > 0 && b > 0 && a > INT32MAX / b) return INT32MAX | ||
if (a < 0 && b < 0 && a < INT32MIN / b) return INT32MIN | ||
return a * b | ||
}, | ||
smuli64: (a, b) => { | ||
if (a > 0n && b > 0n && a > INT64MAX / b) return INT64MAX | ||
if (a < 0n && b < 0n && a < INT64MIN / b) return INT64MIN | ||
return a * b | ||
}, | ||
smulf32: (a, b) => a * b, | ||
smulf64: (a, b) => a * b, | ||
sdivi8: (a, b) => { | ||
if (b === 0) return a > 0 ? INT8MAX : INT8MIN | ||
return Math.floor(a / b) | ||
}, | ||
sdivi16: (a, b) => { | ||
if (b === 0) return a > 0 ? INT16MAX : INT16MIN | ||
return Math.floor(a / b) | ||
}, | ||
sdivi32: (a, b) => { | ||
if (b === 0) return a > 0 ? INT32MAX : INT32MIN | ||
return Math.floor(a / b) | ||
}, | ||
sdivi64: (a, b) => { | ||
if (b === 0n) return a > 0n ? INT64MAX : INT64MIN | ||
return a / b | ||
}, | ||
sdivf32: (a, b) => a / b, | ||
sdivf64: (a, b) => a / b, | ||
spowi8: (a, b) => { | ||
if (a > 0 && b > 1 && a > INT8MAX ** (1 / b)) return INT8MAX | ||
if (a < 0 && b > 1 && a < INT8MIN ** (1 / b)) return INT8MIN | ||
return Math.floor(a ** b) | ||
}, | ||
spowi16: (a, b) => { | ||
if (a > 0 && b > 1 && a > INT16MAX ** (1 / b)) return INT16MAX | ||
if (a < 0 && b > 1 && a < INT16MIN ** (1 / b)) return INT16MIN | ||
return Math.floor(a ** b) | ||
}, | ||
spowi32: (a, b) => { | ||
if (a > 0 && b > 1 && a > INT32MAX ** (1 / b)) return INT32MAX | ||
if (a < 0 && b > 1 && a < INT32MIN ** (1 / b)) return INT32MIN | ||
return Math.floor(a ** b) | ||
}, | ||
spowi64: (a, b) => { | ||
if (a > 0 && b > 1n) { | ||
const af = parseFloat(a.toString()) | ||
const bf = parseFloat(b.toString()) | ||
const maxf = parseFloat(INT64MAX.toString()) | ||
if (af > maxf ** (1 / bf)) return INT64MAX | ||
} | ||
if (a < 0n && b > 1n) { | ||
const af = parseFloat(a.toString()) | ||
const bf = parseFloat(b.toString()) | ||
const minf = parseFloat(INT64MIN.toString()) | ||
if (af < minf ** (1 / bf)) return INT64MIN | ||
} | ||
return a ** b | ||
}, | ||
spowf32: (a, b) => a ** b, | ||
spowf64: (a, b) => a ** b, | ||
// Boolean and bitwise opcodes | ||
@@ -999,3 +1144,3 @@ andi8: (a, b) => a & b, | ||
} else { | ||
console.error(`HTTP server failed to listen to port 8000: ${e}`) | ||
console.error(`HTTP server failed to listen to port 8000: ${listenResult}`) | ||
} | ||
@@ -1029,2 +1174,100 @@ }, | ||
}, | ||
tcplsn: async () => { | ||
const server = net.createServer((c) => { | ||
// To allow the `tcpConn` event to set up anything it needs | ||
c.pause() | ||
const connId = Number(hashf(Math.random().toString())) | ||
const context = [connId, undefined, { | ||
c, | ||
dataArr: [], | ||
state: 'paused', | ||
}] | ||
tcpConns[connId] = context | ||
c.on('data', (buf) => { | ||
context[2].dataArr.push(buf) | ||
e.emit('chunk', context) | ||
}) | ||
c.on('error', () => context[2].state = 'error') | ||
c.on('timeout', () => { | ||
context[2].state = 'timeout' | ||
c.end() // Node.js doesn't automatically do this on timeout for some reason? | ||
}) | ||
c.on('close', () => { | ||
if (context[2].state === 'open') context[2].state = 'closed' | ||
e.emit('tcpClose', context) | ||
delete tcpConns[connId] | ||
}) | ||
e.emit('tcpConn', connId) | ||
}) | ||
const listenResult = await new Promise(resolve => { | ||
server.on('error', e => resolve(e)) | ||
server.listen({ | ||
port: 8000, | ||
}, () => resolve(true)) | ||
}) | ||
if (listenResult === true) { | ||
console.log("TCP server listening on port 8000") | ||
} else { | ||
console.error(`TCP server failed to listen on port 8000: ${listenResult}`) | ||
} | ||
}, | ||
tcpconn: async (host, port) => { | ||
return new Promise(resolve => { | ||
const c = net.createConnection(port, host, () => { | ||
const connId = Number(hashf(Math.random().toString())) | ||
const context = [connId, undefined, { | ||
connId, | ||
c, | ||
dataArr: [], | ||
state: 'paused', | ||
}] | ||
tcpConns[connId] = context | ||
c.on('data', (buf) => { | ||
context[2].dataArr.push(buf) | ||
e.emit('chunk', context) | ||
}) | ||
c.on('error', () => context[2].state = 'error') | ||
c.on('timeout', () => { | ||
context[2].state = 'timeout' | ||
c.end() // Node.js doesn't automatically do this on timeout for some reason | ||
}) | ||
c.on('close', () => { | ||
if (context[2].state === 'open') context[2].state = 'closed' | ||
e.emit('tcpClose', context) | ||
delete tcpConns[connId] | ||
}) | ||
resolve(connId) | ||
}) | ||
// To allow the setup of everything needed | ||
c.pause() | ||
}) | ||
}, | ||
tcpAddC: (connId, context) => { | ||
tcpConns[connId][1] = context | ||
return connId | ||
}, | ||
tcpReady: (connId) => { | ||
const channel = tcpConns[connId] | ||
if (!channel) return connId | ||
channel[2].state = 'open' | ||
channel[2].c.resume() | ||
return connId | ||
}, | ||
tcpRead: (connId) => { | ||
const channel = tcpConns[connId] | ||
if (!channel) return new Buffer() | ||
const chunk = channel[2].dataArr.shift() | ||
return chunk | ||
}, | ||
tcpWrite: (connId, chunk) => { | ||
const channel = tcpConns[connId] | ||
if (!channel) return connId | ||
channel[2].c.write(chunk) | ||
return connId | ||
}, | ||
tcpTerm: (connId) => { | ||
const channel = tcpConns[connId] | ||
if (!channel) return undefined | ||
channel[2].c.end() | ||
}, | ||
@@ -1031,0 +1274,0 @@ // "Special" opcodes |
{ | ||
"name": "alan-js-runtime", | ||
"version": "0.1.36", | ||
"version": "0.1.37", | ||
"description": "The runtime component for alan-js. Separately licensed from the compiler.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
50425
1218
4