eslang
Version:
A simple & expressive script language, like Espresso.
118 lines (102 loc) • 3.45 kB
JavaScript
module.exports = function shellIn ($void) {
var $ = $void.$
var typeOf = $.type.of
var warn = $void.$warn
var print = $void.$print
var printf = $void.$printf
var isTruthy = $void.isTruthy
var thisCall = $void.thisCall
var safelyAssign = $void.safelyAssign
var context = Object.create(null)
var interpreter = require('./interpreter')($void)
context['test-bootstrap'] = require('../test/test')($void)
context['.loader'] = safelyAssign(Object.create(null), $void.loader.cache.store)
return function shell (stdin, exit) {
var echo = typeof stdin.echo === 'function'
? stdin.echo.bind(stdin)
: print.bind(null, '=')
// create the interpreter
function typeInfoOf (prefix, value) {
var info = '#(' + prefix + thisCall(typeOf(value), 'to-string')
var name = !value ? ''
: typeof value.name === 'string' ? value.name
: ''
return name ? info + ': ' + name + ')# ' : info + ')# '
}
function format (value, prefix) {
return typeInfoOf(prefix || '', value) + thisCall(value, 'to-string')
}
function resolve (value) {
if (!(value instanceof Promise)) {
return echo(format(value))
}
echo('#(promise: waiting ...)#')
value.then(function (result) {
echo(format(result, '... result: '))
}, function (err) {
echo(format(err, '... excuse: '))
})
}
function exiting (code) {
if (typeof code === 'undefined' || code === null) {
code = 0
} else {
if (echoing) {
echo(format(code))
}
code = typeof code === 'number' ? code >> 0 : 1
}
code ? printf('Good luck.\n', 'red')
: printf('See you again.\n', 'green')
stdin.close()
return exit(code)
}
function explain (value, status) {
status === 'exiting' ? echo(exiting(value))
: warn.apply(null, Array.prototype.slice.call(arguments, 2))
}
// toggle on/of the printing of evaluation result.
var echoing = false
context['.echo'] = function echo () {
echoing = !echoing
if (echoing) {
return true
}
printf(' ') // this is only visible on console.
return printf('#(bool)# false\n', 'gray')
}
// display, enable or disable debug output.
context['.debug'] = function debug (enabled) {
var isDebugging = $void.$env('is-debugging')
return typeof enabled === 'undefined' ? isDebugging
: $void.env('is-debugging', isTruthy(enabled))
}
// display or update logging level.
context['.logging'] = function logging (level) {
var loggingLevel = $void.$env('logging-level')
return typeof level !== 'number' ? loggingLevel
: $void.env('logging-level', (level >>= 0) < 0 ? 0
: level > 127 ? 127 : level
)
}
var interpret = interpreter(context, function (value, status) {
if (status) {
explain.apply(null, arguments)
} else if (echoing) {
resolve(value)
}
})
// initialize shell environment
interpret('(var path (import ("$eslang/path").\n')
interpret('(var * (load (path resolve (env "runtime-home"), "profile").\n')
echoing = true
// waiting for input
stdin.prompt()
stdin.on('line', function (input) {
interpret(input)
var depth = interpret('\n')
stdin.prompt(depth > 1 ? '..' : '> ')
})
}
}