Slang/slang.html
Alex A. Naanou aa6c6f342a added the files back, oops)))
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2018-06-03 04:32:54 +03:00

280 lines
5.9 KiB
HTML

<!DOCTYPE html>
<html manifest="slang.appcache">
<head>
<title>Slang</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="manifest" href="manifest.json">
</head>
<style>
#bootstrap {
display: none;
}
#bootstrap[shown] {
display: block;
}
.command {
padding-left: 5px;
padding-right: 5px;
}
.command:hover {
background: #eee;
cursor: hand;
}
.command:empty:after {
content: "input code here...";
opacity: 0.5;
}
.command:focus:before {
position: absolute;
content: "ctrl+enter to run";
opacity: 0.3;
right: 15px;
}
.command:focus:after {
opacity: 0.2;
}
.command:last-child {
border: red 2px solid;
border-radius: 5px;
box-shadow: 2px 2px 5px 0px silver;
}
.error {
color: red;
font-style: italic;
}
.output {
font-weight: bold;
}
.error:before,
.output:before {
content: ">";
color: red;
font-weight: bold;
margin: 5px;
}
.output:before {
color: blue;
}
#words {
font-family: monospace;
}
.word[word-type=constant] {
font-weight: bold;
color: red;
}
.word[word-type=builtin] {
font-style: italic;
color: blue;
}
#stack {
opacity: 0.8;
}
/* syntax... */
pre .comment {
font-style: italic;
color: gray;
}
pre :not(.comment) {
font-weight: bold;
}
pre :not(.comment) .string {
font-style: italic;
color: blue;
}
pre :not(.comment) .word {
font-weight: bold;
color: blue;
}
</style>
<script src="slang.js"></script>
<script>
function stringifySlangCode(code){
if(code == null){
return code
}
if(typeof(code) == typeof('str') && /\s/.test(code)){
return '\''+code+'\''
} else if(code && code.constructor.name == 'Array'){
return '[ '+code.map(stringifySlangCode).join(' ')+' ]'
}
return code
}
function runCommand(){
var stack = document.getElementById('stack')
var console = document.getElementById('console')
var commands = document.getElementsByClassName('command')
var command = commands[commands.length-1]
command.removeAttribute('contenteditable')
command.addEventListener('click', function(e){
var commands = document.getElementsByClassName('command')
var c = commands[commands.length-1]
c.innerText = command.innerText
c.focus()
window.scrollTo(0,document.body.scrollHeight)
}, false)
try{
stack.innerText = 'stack: ' + stringifySlangCode(slang(command.innerText))
} catch(e) {
stack.innerText = 'stack: ' + stringifySlangCode(CONTEXT.stack)
var err = document.createElement('div')
err.classList.add('error')
if(e.message != null){
err.innerText = e.message
} else {
err.innerText = e
}
console.appendChild(err)
}
// create the next element...
var next = document.createElement('div')
next.classList.add('command')
next.setAttribute('contenteditable', true)
console.appendChild(next)
next.focus()
window.scrollTo(0,document.body.scrollHeight)
}
NAMESPACE.print = function(context){
var c = document.getElementById('console')
var o = context.stack[context.stack.length-1]
console.log('>>>', o)
var data = document.createElement('div')
data.classList.add('output')
data.innerHTML = stringifySlangCode(o)
c.appendChild(data)
}
// XXX should this break exec?
NAMESPACE.err = function(context){
var c = document.getElementById('console')
var e = context.stack[context.stack.length-1]
console.error('>>>', e)
var err = document.createElement('div')
err.classList.add('error')
if(e.message != null){
err.innerText = e.message
} else {
err.innerText = e
}
c.appendChild(err)
}
function toggleBootstrapCode(){
var bootstrap = document.getElementById('bootstrap')
if(bootstrap.hasAttribute('shown')){
bootstrap.removeAttribute('shown')
} else {
bootstrap.setAttribute('shown', true)
}
}
function showAvailableWords(){
document.getElementById('words').innerHTML = Object.keys(NAMESPACE)
.sort()
.filter(function(e){
// skip words starting with '_'...
if(e[0] == '_'){
return false
}
return true
})
.map(function(e){
var code = NAMESPACE[e]
var type
if(code && code.constructor.name == 'Array'){
type = 'word'
code = stringifySlangCode(code)
} else if(typeof(code) == typeof(function(){})){
type = 'builtin'
} else {
type = 'constant'
}
return '<span class="word" word-type="'+type+'" title="'+code+'">'+e+'</span>'
})
.join(' ')
}
</script>
<body>
<h1>Slang</h1>
<a href="#" onclick="toggleBootstrapCode()">Toggle bootstrap code view...</a>
<div id="bootstrap"></div>
<h2>Available words</h2>
<p>
This section includes constants (red) and constant-like
words (words that allways yield the same value),
built-in words (blue), and 2'nd gen words (black):
</p>
<p id="words"></p>
<h2>Slang Console</h2>
<div id="console">
<div class="command" contenteditable="true"></div>
</div>
<div id="stack"></div>
</body>
<script>
var bootstrap = BOOTSTRAP
// basic HTML compatibility stuff...
.replace(/&/g, '&amp;')
.replace(/>/g, '&gt;')
.replace(/</g, '&lt;')
// very basic syntax highlighting...
// comments...
.replace(/(\(.*)-(.*\))/g, '<span class="comment">$1&minus;$2</span>')
.replace(/(\([^\)]*\))/g, '<span class="comment">$1</span>')
.replace(/(\s*--.*\n)/g, '<span class="comment">$1</span>')
/*
Object.keys(NAMESPACE).forEach(function(k){
bootstrap = bootstrap.replace(
RegExp('('+k
.replace('&', '&amp;')
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace(/([\|\[\]\.\*\/\\\?\+\-])/g, '\\$1')+')', 'g'),
'<span class="word">$1</span>')
})
*/
document.getElementById('bootstrap').innerHTML='<pre>'+bootstrap+'</pre>'
document.getElementById('console')
.addEventListener("keyup", function(e) {
if(e.keyCode == 13 && e.ctrlKey){
runCommand()
showAvailableWords()
}
}, false);
showAvailableWords()
</script>
</html>