Skip to content

Commit 6eb8096

Browse files
committed
time to merge into main
1 parent a689ce0 commit 6eb8096

2 files changed

Lines changed: 118 additions & 121 deletions

File tree

src/components/InfoComponent.tsx

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,49 @@
1-
import React from 'react'
1+
import React, { useState, useEffect, useRef, useMemo } from 'react'
22
import Image from 'react'
3+
import { renderAlien } from "../language/render/renderAlien";
4+
import { generatePlanetLanguage } from "../language/generator/generatePlanetLanguage";
5+
import { parsePythonWithTreeSitter } from "../language/parse/parsePythonWithTreeSitter";
6+
import type { ProgramNode } from "../language/types";
7+
38
const InfoComponent = () => {
9+
const [exampleAst, setExampleAst] = useState<ProgramNode | null>(null);
10+
const [exampleAlien, setExampleAlien] = useState("");
11+
const [exampleError, setExampleError] = useState("");
12+
const sourcePython = `
13+
nums = [1,2,3]
14+
sum = 0
15+
for i in nums:
16+
sum += i
17+
print(sum)
18+
`.trim();
19+
20+
// Use a fixed seed for this level for now
21+
const lang = useMemo(() => generatePlanetLanguage(2), []);
22+
23+
useEffect(() => {
24+
let cancelled = false;
25+
26+
const parseExample = async () => {
27+
try {
28+
setExampleError("");
29+
30+
const ast = await parsePythonWithTreeSitter(sourcePython);
31+
if (cancelled) return;
32+
33+
setExampleAst(ast);
34+
setExampleAlien(renderAlien(ast, lang));
35+
} catch (err) {
36+
if (cancelled) return;
37+
setExampleError(err instanceof Error ? err.message : String(err));
38+
}
39+
};
40+
41+
parseExample();
42+
43+
return () => {
44+
cancelled = true;
45+
};
46+
}, [sourcePython, lang]);
447
return (
548
<div className="flex-1 bg-[#2a2a2a] rounded-2xl p-3 flex flex-col gap-3">
649

@@ -17,11 +60,7 @@ const InfoComponent = () => {
1760
*** PYTHON CODE ***
1861
</div>
1962
<div className="bg-[#4a8be0] m-2 rounded-xl p-3">
20-
<pre className="text-white text-xs leading-relaxed m-0">{`nums = [1,2,3]
21-
sum = 0
22-
for i in nums:
23-
sum += i
24-
print(sum)`}</pre>
63+
<pre className="text-white text-xs leading-relaxed m-0">{sourcePython}</pre>
2564
</div>
2665
</div>
2766

@@ -31,11 +70,7 @@ print(sum)`}</pre>
3170
*** ALIEN CODE ***
3271
</div>
3372
<div className="bg-[#3a9447] transition m-2 rounded-xl p-3">
34-
<pre className="text-white text-xs leading-relaxed m-0">{`nums eats [1,2,3]
35-
sum eats 0
36-
i eats nums slowly:
37-
sum eats more i
38-
print eats sum`}</pre>
73+
<pre className="text-white text-xs leading-relaxed m-0">{exampleError ? `Error: ${exampleError}` : exampleAlien || "Loading..."}</pre>
3974
</div>
4075
</div>
4176
</div>

src/components/OutputComponent.tsx

Lines changed: 72 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -2,122 +2,84 @@ import React, { useState, useEffect, useRef, useMemo } from 'react'
22
import { generatePlanetLanguage } from "../language/generator/generatePlanetLanguage";
33
import { parseAlien } from "../language/parse/parseAlien";
44
import { renderPython } from "../language/render/renderPython";
5-
import { renderAlien } from "../language/render/renderAlien";
6-
import { parsePythonWithTreeSitter } from "../language/parse/parsePythonWithTreeSitter";
7-
import type { ProgramNode } from "../language/types";
85
import { validateAlienSource } from "../language/validate/validateAlienSource";
96

107
const OutputComponent = () => {
118
const [code, setCode] = useState("")
12-
const [output, setOutput] = useState("")
13-
const [translatedPython, setTranslatedPython] = useState("");
14-
const [exampleAst, setExampleAst] = useState<ProgramNode | null>(null);
15-
const [exampleAlien, setExampleAlien] = useState("");
16-
const [exampleError, setExampleError] = useState("");
17-
const [pyodideReady, setPyodideReady] = useState(false)
18-
const pyodideRef = useRef<any>(null)
19-
const sourcePython = `
20-
nums = [1,2,3]
21-
sum = 0
22-
for i in nums:
23-
sum += i
24-
print(sum)
25-
`.trim();
26-
9+
const [output, setOutput] = useState("")
10+
const [translatedPython, setTranslatedPython] = useState("");
11+
const [pyodideReady, setPyodideReady] = useState(false)
12+
const pyodideRef = useRef<any>(null)
13+
const outputExpected = "5"
2714

28-
// Use a fixed seed for this level for now
29-
const lang = useMemo(() => generatePlanetLanguage(2), []);
30-
31-
useEffect(() => {
32-
const loadPyodide = async () => {
33-
// @ts-ignore
34-
pyodideRef.current = await window.loadPyodide()
35-
setPyodideReady(true)
36-
}
37-
loadPyodide()
38-
}, [])
39-
40-
useEffect(() => {
41-
let cancelled = false;
42-
43-
const parseExample = async () => {
44-
try {
45-
setExampleError("");
46-
47-
const ast = await parsePythonWithTreeSitter(sourcePython);
48-
if (cancelled) return;
49-
50-
setExampleAst(ast);
51-
setExampleAlien(renderAlien(ast, lang));
52-
} catch (err) {
53-
if (cancelled) return;
54-
setExampleError(err instanceof Error ? err.message : String(err));
55-
}
56-
};
57-
58-
parseExample();
59-
60-
return () => {
61-
cancelled = true;
62-
};
63-
}, [sourcePython, lang]);
64-
65-
const runCode = async () => {
66-
if (!pyodideRef.current) return
67-
if (!pyodideRef.current) return;
68-
69-
const validation = validateAlienSource(code, lang);
70-
71-
if (!validation.isValid) {
72-
setTranslatedPython("");
73-
setOutput(
74-
validation.issues
75-
.map(
76-
(issue) =>
77-
`Line ${issue.line}, Col ${issue.column}: ${issue.message}`,
78-
)
79-
.join("\n"),
80-
);
81-
return;
82-
}
83-
try {
84-
// 1. Alien -> AST
85-
const ast = parseAlien(code, lang);
86-
console.log(ast);
87-
// 2. AST -> Python
88-
const pythonCode = renderPython(ast);
89-
setTranslatedPython(pythonCode);
90-
91-
92-
// 3. Reset stdout
93-
await pyodideRef.current.runPythonAsync(`
94-
import sys, io
95-
sys.stdout = io.StringIO()
96-
`);
97-
98-
// 4. Run translated Python
99-
await pyodideRef.current.runPythonAsync(pythonCode);
100-
101-
// 5. Get output
102-
const result = await pyodideRef.current.runPythonAsync(`sys.stdout.getvalue()`);
103-
setOutput(String(result));
104-
} catch (err: any) {
105-
setOutput(err?.message ?? String(err));
106-
}
107-
};
108-
109-
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
110-
if (e.key === "Tab") {
111-
e.preventDefault()
112-
const el = e.target as HTMLTextAreaElement
113-
const { selectionStart, selectionEnd } = el
114-
const newValue = code.slice(0, selectionStart) + " " + code.slice(selectionEnd)
115-
setCode(newValue)
116-
requestAnimationFrame(() => {
117-
el.selectionStart = el.selectionEnd = selectionStart + 4
118-
})
119-
}
15+
// Use a fixed seed for this level for now
16+
const lang = useMemo(() => generatePlanetLanguage(2), []);
17+
18+
useEffect(() => {
19+
const loadPyodide = async () => {
20+
// @ts-ignore
21+
pyodideRef.current = await window.loadPyodide()
22+
setPyodideReady(true)
23+
}
24+
loadPyodide()
25+
}, [])
26+
27+
const runCode = async () => {
28+
if (!pyodideRef.current) return
29+
if (!pyodideRef.current) return;
30+
31+
const validation = validateAlienSource(code, lang);
32+
33+
if (!validation.isValid) {
34+
setTranslatedPython("");
35+
setOutput(
36+
validation.issues
37+
.map(
38+
(issue) =>
39+
`Line ${issue.line}, Col ${issue.column}: ${issue.message}`,
40+
)
41+
.join("\n"),
42+
);
43+
return;
44+
}
45+
try {
46+
// 1. Alien -> AST
47+
const ast = parseAlien(code, lang);
48+
console.log(ast);
49+
// 2. AST -> Python
50+
const pythonCode = renderPython(ast);
51+
setTranslatedPython(pythonCode);
52+
53+
54+
// 3. Reset stdout
55+
await pyodideRef.current.runPythonAsync(`
56+
import sys, io
57+
sys.stdout = io.StringIO()
58+
`);
59+
60+
// 4. Run translated Python
61+
await pyodideRef.current.runPythonAsync(pythonCode);
62+
63+
// 5. Get output
64+
const result = await pyodideRef.current.runPythonAsync(`sys.stdout.getvalue()`);
65+
setOutput(String(result));
66+
} catch (err: any) {
67+
setOutput(err?.message ?? String(err));
68+
}
69+
};
70+
71+
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
72+
if (e.key === "Tab") {
73+
e.preventDefault()
74+
const el = e.target as HTMLTextAreaElement
75+
const { selectionStart, selectionEnd } = el
76+
const newValue = code.slice(0, selectionStart) + " " + code.slice(selectionEnd)
77+
setCode(newValue)
78+
requestAnimationFrame(() => {
79+
el.selectionStart = el.selectionEnd = selectionStart + 4
80+
})
12081
}
82+
}
12183

12284
return (
12385
<div className="flex-1 p-3 flex flex-col gap-3">

0 commit comments

Comments
 (0)