1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
import { tokenize, Parser, Environment } from "./tabloid.js";
import { SAMPLE_PROGRAMS } from "./samples.js";
class TabloidRunner {
run(code) {
const stdout = [];
const stderr = [];
if (!code) {
stderr.push("No code to execute.");
return { stdout, stderr };
}
try {
const tokens = tokenize(code);
const nodes = new Parser(tokens).parse();
const env = new Environment({
print: (msg) => stdout.push(String(msg)),
input: (promptText) => window.prompt(promptText) ?? ""
});
env.run(nodes);
} catch (error) {
stderr.push(error.message || error.toString());
}
return { stdout, stderr };
}
}
export class TabloidPlayground {
constructor() {
this.runner = new TabloidRunner();
this.programLookup = new Map(SAMPLE_PROGRAMS.map((program) => [program.id, program]));
this.activeProgramId = this.defaultProgramId = SAMPLE_PROGRAMS[0].id;
this.stdoutElement = document.getElementById("stdout-content");
this.errorElement = document.getElementById("error-content");
this.programSelect = document.getElementById("program-select");
this.runButton = document.getElementById("run-button");
this.clearButton = document.getElementById("clear-button");
this.editor = adelieEditor.init("#code-editor", {
language: "tabloid"
});
this.init();
}
init() {
this.populateProgramSelect();
this.registerEvents();
this.loadProgram(this.activeProgramId);
}
populateProgramSelect() {
if (!this.programSelect) {
return;
}
this.programSelect.innerHTML = "";
SAMPLE_PROGRAMS.forEach((program) => {
const option = document.createElement("option");
option.value = program.id;
option.textContent = program.label;
this.programSelect.appendChild(option);
});
this.programSelect.value = this.activeProgramId;
}
registerEvents() {
this.runButton.addEventListener("click", () => this.runCode());
this.clearButton.addEventListener("click", () => this.resetOutput());
this.programSelect.addEventListener("change", () => {
this.loadProgram(this.programSelect.value);
});
document.addEventListener("keydown", (event) => {
if (event.ctrlKey && event.key === "Enter") {
event.preventDefault();
this.runCode();
}
});
}
setEditorContent(content) {
const length = this.editor.state.doc.toString().length;
this.editor.dispatch({
changes: { from: 0, to: length, insert: content }
});
}
loadProgram(programId = this.defaultProgramId) {
const selectedProgram = this.programLookup.get(programId);
if (!selectedProgram) {
return;
}
this.activeProgramId = selectedProgram.id;
this.setEditorContent(selectedProgram.code);
this.resetOutput();
if (this.programSelect) {
this.programSelect.value = this.activeProgramId;
}
}
resetOutput() {
this.stdoutElement.textContent = "";
this.errorElement.textContent = "";
}
runCode() {
const code = this.editor.state.doc.toString();
const result = this.runner.run(code);
this.stdoutElement.textContent = result.stdout.join("\n");
this.errorElement.textContent = result.stderr.join("\n");
}
}
|