playground: add ability to run code
This commit is contained in:
43
playground/samples/Hello.newt
Normal file
43
playground/samples/Hello.newt
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
module Main
|
||||||
|
|
||||||
|
-- Monad
|
||||||
|
|
||||||
|
class Monad (m : U → U) where
|
||||||
|
bind : {a b} → m a → (a → m b) → m b
|
||||||
|
pure : {a} → a → m a
|
||||||
|
|
||||||
|
infixl 1 _>>=_ _>>_
|
||||||
|
_>>=_ : {m} {{Monad m}} {a b} -> (m a) -> (a -> m b) -> m b
|
||||||
|
ma >>= amb = bind ma amb
|
||||||
|
|
||||||
|
_>>_ : {m} {{Monad m}} {a b} -> m a -> m b -> m b
|
||||||
|
ma >> mb = mb
|
||||||
|
|
||||||
|
-- I don't want to use an empty type because it would be a proof of void
|
||||||
|
ptype World
|
||||||
|
|
||||||
|
data IORes : U -> U where
|
||||||
|
MkIORes : {a : U} -> a -> World -> IORes a
|
||||||
|
|
||||||
|
IO : U -> U
|
||||||
|
IO a = World -> IORes a
|
||||||
|
|
||||||
|
|
||||||
|
data Unit : U where
|
||||||
|
MkUnit : Unit
|
||||||
|
|
||||||
|
|
||||||
|
instance Monad IO where
|
||||||
|
bind ma mab = \ w => case ma w of
|
||||||
|
MkIORes a w => mab a w
|
||||||
|
pure a = \ w => MkIORes a w
|
||||||
|
|
||||||
|
ptype String
|
||||||
|
pfunc putStrLn : String -> IO Unit := "(s) => (w) => {
|
||||||
|
console.log(s)
|
||||||
|
return MkIORes(Unit,MkUnit,w)
|
||||||
|
}"
|
||||||
|
|
||||||
|
main : IO Unit
|
||||||
|
main = do
|
||||||
|
putStrLn "hello, world"
|
||||||
29
playground/samples/frame.html
Normal file
29
playground/samples/frame.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
realLog = console.log
|
||||||
|
messages = []
|
||||||
|
console.log = (...args) => {
|
||||||
|
messages.push(args.join(' '))
|
||||||
|
realLog(...args)
|
||||||
|
}
|
||||||
|
window.addEventListener('message', (ev) => {
|
||||||
|
realLog('got', ev)
|
||||||
|
let {cmd, src} = ev.data
|
||||||
|
if (cmd === 'exec') {
|
||||||
|
try {
|
||||||
|
eval(src)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.parent.postMessage({messages}, '*')
|
||||||
|
messages = []
|
||||||
|
})
|
||||||
|
realLog('IFRAME INITIALIZED')
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -10,11 +10,31 @@ monaco.languages.setMonarchTokensProvider("newt", newtTokens);
|
|||||||
monaco.languages.setLanguageConfiguration("newt", newtConfig);
|
monaco.languages.setLanguageConfiguration("newt", newtConfig);
|
||||||
|
|
||||||
const newtWorker = new Worker("worker.js"); //new URL("worker.js", import.meta.url))
|
const newtWorker = new Worker("worker.js"); //new URL("worker.js", import.meta.url))
|
||||||
|
const iframe = document.createElement("iframe");
|
||||||
|
iframe.src = "frame.html";
|
||||||
|
iframe.style.display = "none";
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
|
||||||
function run(src: string) {
|
function run(src: string) {
|
||||||
newtWorker.postMessage({ src });
|
newtWorker.postMessage({ src });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runOutput() {
|
||||||
|
const src = state.javascript.value
|
||||||
|
console.log("RUN", iframe.contentWindow);
|
||||||
|
try {
|
||||||
|
iframe.contentWindow?.postMessage({ cmd: "exec", src }, "*");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onmessage = (ev) => {
|
||||||
|
console.log("window got", ev.data);
|
||||||
|
if (ev.data.messages)
|
||||||
|
state.messages.value = ev.data.messages;
|
||||||
|
};
|
||||||
|
|
||||||
newtWorker.onmessage = (ev) => {
|
newtWorker.onmessage = (ev) => {
|
||||||
state.output.value = ev.data.output;
|
state.output.value = ev.data.output;
|
||||||
state.javascript.value = ev.data.javascript;
|
state.javascript.value = ev.data.javascript;
|
||||||
@@ -30,6 +50,7 @@ self.MonacoEnvironment = {
|
|||||||
const state = {
|
const state = {
|
||||||
output: signal(""),
|
output: signal(""),
|
||||||
javascript: signal(""),
|
javascript: signal(""),
|
||||||
|
messages: signal<string[]>([]),
|
||||||
editor: signal<monaco.editor.IStandaloneCodeEditor | null>(null),
|
editor: signal<monaco.editor.IStandaloneCodeEditor | null>(null),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,19 +131,35 @@ function Result() {
|
|||||||
return h("div", { id: "result" }, text);
|
return h("div", { id: "result" }, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Console() {
|
||||||
|
const messages = state.messages.value ?? []
|
||||||
|
return h(
|
||||||
|
"div",
|
||||||
|
{ id: "console" },
|
||||||
|
messages.map((msg) => h("div", { className: "message" }, msg))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const RESULTS = "Output";
|
const RESULTS = "Output";
|
||||||
const JAVASCRIPT = "JS";
|
const JAVASCRIPT = "JS";
|
||||||
|
const CONSOLE = "Console";
|
||||||
|
|
||||||
function Tabs() {
|
function Tabs() {
|
||||||
const [selected, setSelected] = useState(RESULTS);
|
const [selected, setSelected] = useState(localStorage.tab ?? RESULTS);
|
||||||
|
|
||||||
const Tab = (label: string) => {
|
const Tab = (label: string) => {
|
||||||
let onClick = () => setSelected(label);
|
let onClick = () => {
|
||||||
|
setSelected(label);
|
||||||
|
localStorage.tab = label
|
||||||
|
}
|
||||||
let className = "tab";
|
let className = "tab";
|
||||||
if (label == selected) className += " selected";
|
if (label == selected) className += " selected";
|
||||||
return h("div", { className, onClick }, label);
|
return h("div", { className, onClick }, label);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (state.messages.value) setSelected(CONSOLE)
|
||||||
|
}, [state.messages.value])
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
switch (selected) {
|
switch (selected) {
|
||||||
case RESULTS:
|
case RESULTS:
|
||||||
@@ -131,6 +168,9 @@ function Tabs() {
|
|||||||
case JAVASCRIPT:
|
case JAVASCRIPT:
|
||||||
body = h(JavaScript, {});
|
body = h(JavaScript, {});
|
||||||
break;
|
break;
|
||||||
|
case CONSOLE:
|
||||||
|
body = h(Console, {});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
body = h("div", {});
|
body = h("div", {});
|
||||||
}
|
}
|
||||||
@@ -138,13 +178,14 @@ function Tabs() {
|
|||||||
return h(
|
return h(
|
||||||
"div",
|
"div",
|
||||||
{ className: "tabPanel right" },
|
{ className: "tabPanel right" },
|
||||||
h("div", { className: "tabBar" }, Tab(RESULTS), Tab(JAVASCRIPT)),
|
h("div", { className: "tabBar" }, Tab(RESULTS), Tab(JAVASCRIPT), Tab(CONSOLE)),
|
||||||
h("div", { className: "tabBody" }, body)
|
h("div", { className: "tabBody" }, body)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAMPLES = [
|
const SAMPLES = [
|
||||||
"Tour.newt",
|
"Tour.newt",
|
||||||
|
"Hello.newt",
|
||||||
"DSL.newt",
|
"DSL.newt",
|
||||||
"Tree.newt",
|
"Tree.newt",
|
||||||
"Reasoning.newt",
|
"Reasoning.newt",
|
||||||
@@ -180,12 +221,18 @@ function EditWrap({vertical, toggle}: {vertical: boolean, toggle: () => void}) {
|
|||||||
h("option", { value: "" }, "choose sample"),
|
h("option", { value: "" }, "choose sample"),
|
||||||
options
|
options
|
||||||
),
|
),
|
||||||
h('div', {style: {flex: '1 1'}}),
|
h("div", { style: { flex: "1 1" } }),
|
||||||
h('button', {onClick: toggle},
|
h("button", { onClick: runOutput
|
||||||
h('svg', {width:20, height: 20},
|
}, "⏵"),
|
||||||
h('path',{d,fill:'none',stroke:'black'})
|
h(
|
||||||
)
|
"button",
|
||||||
|
{ onClick: toggle },
|
||||||
|
h(
|
||||||
|
"svg",
|
||||||
|
{ width: 20, height: 20 },
|
||||||
|
h("path", { d, fill: "none", stroke: "black" })
|
||||||
)
|
)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
h("div", { className: "tabBody" }, h(Editor, { initialValue: value }))
|
h("div", { className: "tabBody" }, h(Editor, { initialValue: value }))
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user