start .
me .
HTML Document File : editor.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> SBUL: Simple Basic Uniform Language </title>
</head>
<body>
<div><a href="https://github.com/arkenidar/sbul">github.com/arkenidar/sbul</a>
SBUL: a Simple Basic Uniform Language.
an exploration of JSON-based and HTML based software making.
</div>
<button onclick="location.reload()">reload this</button>
<hr>
<div id="stdout"></div>
<hr>
<button onclick="next_step()">Go!</button>
Current step <span id="UI_current_step">?</span>.
<label> <input type="checkbox" id="UI_stop_at_every_step" checked="true">stop at every step.</label>
<button onclick="next_step()">next step</button>
breakpoints list. e.g. : "2,4".
<input type="text" value="" id="UI_breakpoints_list" placeholder="breakpoints e.g. 5,6,7">
<label> <input type="checkbox" id="UI_ignore_breakpoints_list">ignore the break-points in the list.</label>
<hr>
<button onclick="if(parse(program_text.textContent)) console_write('Current program was parsed fine.\n')">Parse
program.</button>
<style>
.area {
border: 1px solid black;
padding: 5px;
}
</style>
<div id="UI_program_parse_errors" contenteditable="" class="area"></div>
<pre id="program_text" contenteditable="" class="area" oninput="program_input()">
[
"program",
["ignored note", ["json", "test 1\n"]],
["set contextual variable", ["json", "text output"], ["json", ""]],
["append text", ["json", "text output"], ["json", "count ( "]],
["append text", ["json", "text output"], ["sequence size", ["json", [1, 2, 3, 4]]]],
["append text", ["json", "text output"], ["json", " )\n"]],
["write message", ["contextual variable", ["json", "text output"]]],
["if then",
["json", true],
["procedure", ["json", "message"], ["json", "it works!"]]
],
["procedure", ["json", "message"], ["procedure", ["json", "question"],
["json", "enter integer"],
["json", "10"]
]]
]
</pre>
<hr>
<script>
var program_json_example0 = [
"code_block",
["console_log", ["json", "step 1.\n"]],
["console_log", ["json", "step 2.\n"]],
["console_log", ["json", "step 3.\n"]],
["console_log", ["json", "step 4.\n"]],
["console_log", ["json", "step 5.\n"]],
["console_log", ["json", "end.\n"]]
]
var program_json_example1 = [
"code_block",
["comment", ["json", "test 1\n"]],
["local_variable_set", ["json", "string_output"], ["json", ""]],
["append", ["json", "string_output"], ["json", "count ( "]],
["append", ["json", "string_output"], ["array_count", ["json", [1, 2, 3, 4]]]],
["append", ["json", "string_output"], ["json", " )\n"]],
["console_log", ["local_variable_get", ["json", "string_output"]]],
["if_then",
["json", true],
["js_function", ["json", "alert"], ["json", "it works!"]]
],
["js_function", ["json", "alert"], ["js_function", ["json", "prompt"],
["json", "enter integer"],
["json", "10"]
]]
]
//program_text.textContent = JSON.stringify(program_json_example0, null, 1)
function js_function_call_list(call_list) {
return globalThis[call_list[0]].call(globalThis, ...call_list.slice(1))
}
function console_write(...parameters) {
console.log(...parameters)
var text = parameters.join("|")
stdout.innerHTML += text.replace("\n", "<br>")
}
function evaluate(item, namespace) {
var type = item[0]
if (type in types) {
var type_function = types[type]
return type_function(item, namespace)
}
else {
console_write("error! type_function not found: " + type + "\n")
}
}
var types = {}
types.comment = function () { }
types.json = function (item) { return item[1] }
types.js_function = function (item, namespace) {
var call_list = item.slice(1).map((item, namespace) => evaluate(item, namespace))
return js_function_call_list(call_list)
}
types.console_log = function (item, namespace) {
var what = item[1]
var text = evaluate(what, namespace)
console_write(text)
}
var code_blocks = []
function next_step() {
setTimeout(step_of_code_block, 0)
}
function step_of_code_block() {
var code_block = code_blocks.at(-1)
if (!code_block) {
console_write("INFO: starting program.\n")
execute(parse(program_text.textContent))
return
}
function code_block_has_ended() {
code_blocks.pop()
if (!code_blocks.length) console_write("INFO: program ended.\n<hr>")
}
if (code_block.current_step >= code_block.steps.length) {
code_block_has_ended()
return
}
var step = code_block.steps[code_block.current_step]
evaluate(step, code_block.namespace)
code_block.current_step++
//alert(identifier_of_current_step())
program_input()
document.all.UI_current_step.innerText = code_block.current_step
if (code_block.current_step >= code_block.steps.length) {
code_block_has_ended()
return
}
var stop_at_every_step = document.all.UI_stop_at_every_step.checked
var current_is_breakpoint = document.all.UI_breakpoints_list.value.split(",").indexOf(code_block.current_step.toString()) != -1
var ignore_breakpoints = document.all.UI_ignore_breakpoints_list.checked
var stop_condition = stop_at_every_step || (!ignore_breakpoints && current_is_breakpoint)
if (!stop_condition) next_step()
}
types.code_block = function (item, namespace) {
var code_block = {}
code_block.current_step = 0
code_block.steps = item.slice(1)
code_block.namespace = namespace
code_blocks.push(code_block)
next_step()
}
types.if_then = function (item, namespace) {
if (evaluate(item[1], namespace)) {
return evaluate(item[2], namespace)
}
}
types.if_then_else = function (item, namespace) {
if (evaluate(item[1], namespace)) {
return evaluate(item[2], namespace)
} else {
return evaluate(item[3], namespace)
}
}
types.case_that_is_equal_to = function (item, namespace) {
var cases = item.slice(2)
for (var case_current of cases) {
var equal_to_this = evaluate(item[1], namespace)
if (equal_to_this == evaluate(case_current[0], namespace))
return evaluate(case_current[1], namespace)
}
}
types.local_variable_get = function (item, namespace) {
return namespace[evaluate(item[1], namespace)]
}
types.local_variable_set = function (item, namespace) {
var value = evaluate(item[2], namespace)
namespace[evaluate(item[1], namespace)] = value
}
types.array_count = function (item, namespace) {
var array = evaluate(item[1], namespace)
return array.length
}
types.append = function (item, namespace) {
namespace[evaluate(item[1], namespace)] += evaluate(item[2], namespace)
}
function parse(program_code) {
try {
return JSON.parse(program_code)
} catch (err) {
console_write(err.stack + "\n")
}
}
function execute(program_json) {
evaluate(program_json, {})
}
</script>
<hr>
<button onclick="next_step()">next step</button>
<hr>
<div id="UI_program_display"></div>
<script>
types["program"] = types.code_block
types["ignored note"] = types.comment
types["set contextual variable"] = types.local_variable_set
types["append text"] = types.append
types["sequence size"] = types.array_count
types["write message"] = types.console_log
types["contextual variable"] = types.local_variable_get
types["if then"] = types.if_then
types["procedure"] = types.js_function
message = alert
question = prompt
/*
"code_block",
["comment", ["json", "test 1\n"]],
["local_variable_set", ["json", "string_output"], ["json", ""]],
["append", ["json", "string_output"], ["json", "count ( "]],
["append", ["json", "string_output"], ["array_count", ["json", [1, 2, 3, 4]]]],
["append", ["json", "string_output"], ["json", " )\n"]],
["console_log", ["local_variable_get", ["json", "string_output"]]],
["if_then",
["json", true],
["js_function", ["json", "alert"], ["json", "it works!"]]
],
["js_function", ["json", "alert"], ["js_function", ["json", "prompt"],
["json", "enter integer"],
["json", "10"]
]]
*/
var program_json_example2 = [
"program",
["ignored note", ["json", "test 1\n"]],
["set contextual variable", ["json", "text output"], ["json", ""]],
["append text", ["json", "text output"], ["json", "count ( "]],
["append text", ["json", "text output"], ["sequence size", ["json", [1, 2, 3, 4]]]],
["append text", ["json", "text output"], ["json", " )\n"]],
["write message", ["contextual variable", ["json", "text output"]]],
["if then",
["json", true],
["procedure", ["json", "message"], ["json", "it works!"]]
],
["procedure", ["json", "message"], ["procedure", ["json", "question"],
["json", "enter integer"],
["json", "10"]
]]
]
document.all.UI_program_display.innerHTML = display_html(program_json_example1, "1")
for (var program of document.querySelectorAll(".UI_program_identifier")) {
program.onclick = function (event) {
var dom_element = event.target//.parentElement
//alert(dom_element.dataset.program_identifier)
alert(dom_element.innerHTML)
event.stopPropagation()
}
}
function identifier_of_current_step() {
var levels = [1]
for (var code_block of code_blocks) {
levels.push(code_block.current_step)
}
return levels.join(",")
}
function display_html(program_json, program_identifier) {
var button_next = ""
var button_class = ""
if (identifier_of_current_step() == program_identifier) {
button_next = `<button onclick="next_step()">next step</button> `
button_class = "current_step"
}
var html = `<div class="program" data-program_identifier="${program_identifier}"><button class="UI_program_identifier ${button_class}">${program_identifier}</button> ${button_next}`
if (program_json[0] == "json") {
html += `<i>${JSON.stringify(program_json[1])}</i>.</div>\n`
return html
}
var sub_programs = program_json.slice(1).map((program_json, index) => display_html(program_json, program_identifier + "," + (index + 1)))
html += `<b>${program_json[0]}:</b> {{${sub_programs.join("<br>\n")}}}.</div>\n`
return html
}
///
program_input()
function program_input() {
try {
var program_json = JSON.parse(program_text.textContent)
if (program_json) {
document.all.UI_program_parse_errors.textContent = "no parse errors now."
document.all.UI_program_display.innerHTML = display_html(program_json, "1")
}
} catch (err) {
///console_write(err.stack + "\n")
document.all.UI_program_parse_errors.textContent = err.stack
}
}
</script>
<style>
.program>.program {
padding-left: 5em;
}
.program>b {
text-transform: capitalize;
}
.current_step {
background-color: red;
}
</style>
<hr>
<script src="https://arkenidar.com/web/show-source.js" data-href="?show-source"></script>
</body>
</html>