Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion backend/src/simples_backend/services/execution_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ def _reader() -> None:
while len(buf) >= 8:
stream_id = buf[0]
if stream_id not in (1, 2):
output_queue.put(("stdout", buf))
buf = b""
break
payload_len = int.from_bytes(buf[4:8], "big")
frame_size = 8 + payload_len
Expand Down Expand Up @@ -172,7 +174,10 @@ def _reader() -> None:
if t == "stdin":
data = msg.get("data", "")
if data:
sock._sock.sendall(data.encode("utf-8"))
try:
sock._sock.sendall(data.encode("utf-8"))
except OSError:
pass
elif t == "stop":
try:
container.kill(signal="SIGTERM")
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/components/TerminalPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ export const TerminalPanel = forwardRef<TerminalPanelHandle, TerminalPanelProps>

const handleData = useCallback(
(data: string) => {
const term = terminalRef.current
if (term) {
for (const ch of data) {
if (ch === '\r') {
term.write('\r\n')
} else if (ch === '\x7f' || ch === '\b') {
term.write('\b \b')
} else if (ch === '\t') {
term.write('\t')
} else if (ch >= ' ') {
term.write(ch)
}
}
}
onStdin?.(data)
},
[onStdin],
Expand Down
41 changes: 38 additions & 3 deletions frontend/src/components/Toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import { useRef, useState } from 'react'
import { EXAMPLES, type Example } from '../lib/examples'

interface ToolbarProps {
code?: string
onRun?: (code: string) => void
onStop?: () => void
isRunning: boolean
onExampleSelect?: (example: Example) => void
onClear?: () => void
}

export function Toolbar({ code, onRun, onStop, isRunning }: ToolbarProps) {
export function Toolbar({ code, onRun, onStop, isRunning, onExampleSelect, onClear }: ToolbarProps) {
const [open, setOpen] = useState(false)
const dropdownRef = useRef<HTMLDivElement>(null)

function handleRun() {
const source = code ?? ''
onRun?.(source)
}

function handleSelect(example: Example) {
setOpen(false)
onExampleSelect?.(example)
}

return (
<div className="mx-6 flex items-center gap-3">
<button
Expand All @@ -34,20 +47,42 @@ export function Toolbar({ code, onRun, onStop, isRunning }: ToolbarProps) {
<button
className="rounded-xl border border-white/[0.06] bg-white/[0.02] px-4 py-2 text-sm text-white/30 transition hover:border-white/10 hover:text-white/50"
type="button"
onClick={onClear}
>
Limpar
</button>

<div className="ml-auto">
<div className="relative ml-auto" ref={dropdownRef}>
<button
className="flex items-center gap-1 rounded-xl border border-white/[0.06] bg-white/[0.02] px-4 py-2 text-sm text-white/30 transition hover:border-white/10 hover:text-white/50"
type="button"
onClick={() => setOpen(!open)}
>
exemplos
<svg className="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<svg className={`h-3 w-3 transition ${open ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>

{open && (
<>
<div className="fixed inset-0 z-40" onClick={() => setOpen(false)} />
<div className="absolute right-0 z-50 mt-2 w-52 overflow-hidden rounded-xl border border-white/[0.08] bg-[#0a0a0f]/95 backdrop-blur-xl">
<div className="max-h-72 overflow-y-auto py-1">
{EXAMPLES.map((ex) => (
<button
key={ex.name}
className="flex w-full items-center px-4 py-2 text-left text-sm text-white/60 transition hover:bg-white/[0.04] hover:text-white/90"
type="button"
onClick={() => handleSelect(ex)}
>
{ex.label}
</button>
))}
</div>
</div>
</>
)}
</div>
</div>
)
Expand Down
223 changes: 223 additions & 0 deletions frontend/src/lib/examples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
export interface Example {
name: string
label: string
code: string
}

const hello: Example = {
name: 'hello',
label: 'Hello World',
code: `programa hello
inicio
escreval "Ola, mundo!";
fim`,
}

const fatorial: Example = {
name: 'fatorial',
label: 'Fatorial',
code: `procedimento inteiro fatorial(inteiro n)
inicio
inteiro i, resultado;
resultado <- 1;
para i de 2 ate n passo 1 faca
resultado <- resultado * i;
fimpara
retorna resultado;
fim

programa demo
inteiro x;
inicio
escreva "digite o numero: ";
leia x;
escreva "fatorial de ";
escreva x;
escreva " = ";
escreval fatorial(x);
fim`,
}

const fibonacci: Example = {
name: 'fibonacci',
label: 'Fibonacci',
code: `procedimento inteiro fibonacci(inteiro n)
inicio
inteiro i, a, b, tmp;
a <- 0;
b <- 1;
se n = 0 entao
retorna 0;
senao
se n = 1 entao
retorna 1;
senao
para i de 2 ate n passo 1 faca
tmp <- a + b;
a <- b;
b <- tmp;
fimpara
retorna b;
fimse
fimse
fim

programa demo
inteiro n, i;
inicio
escreva "digite o numero: ";
leia n;
se n > 46 entao
escreval "numero muito grande";
senao
escreva "fibonacci ate ";
escreva n;
escreval ":";
para i de 0 ate n passo 1 faca
escreva fibonacci(i);
se i < n entao
escreva " ";
fimse
fimpara
escreval "";
fimse
fim`,
}

const tabuada: Example = {
name: 'tabuada',
label: 'Tabuada',
code: `programa tabuada
inteiro n, i;
inicio
escreva "digite um numero: ";
leia n;
para i de 1 ate 10 passo 1 faca
escreva n;
escreva " x ";
escreva i;
escreva " = ";
escreval n * i;
fimpara
fim`,
}

const ifExample: Example = {
name: 'if',
label: 'Se / Entao / Senao',
code: `programa demo
inteiro x;
inicio
x <- -1;
se x > 0 entao
escreval x;
senao
escreval 0;
fimse
fim`,
}

const forExample: Example = {
name: 'for',
label: 'Para (for)',
code: `programa demo
inteiro i, total;
inicio
total <- 0;
para i de 1 ate 5 passo 1 faca
total <- total + i;
fimpara
escreval total;
fim`,
}

const whileExample: Example = {
name: 'while',
label: 'Enquanto (while)',
code: `programa demo
inteiro x;
inicio
x <- 0;
enquanto x < 3 faca
x <- x + 1;
escreva x;
fimenquanto
fim`,
}

const readExample: Example = {
name: 'read',
label: 'Leia / Escreva',
code: `programa demo
inteiro x;
inicio
escreva "digite um numero: ";
leia x;
escreval "voce digitou: ", x;
fim`,
}

const stringEcho: Example = {
name: 'string',
label: 'String',
code: `programa demo
string nome[16];
inicio
escreva "digite seu nome: ";
leia nome;
escreval "ola, ", nome;
fim`,
}

const vectorSum: Example = {
name: 'vector',
label: 'Vetor',
code: `programa demo
inteiro nums[4], i, total;
inicio
nums[0] <- 1;
nums[1] <- 2;
nums[2] <- 3;
nums[3] <- 4;
total <- 0;
para i de 0 ate 3 passo 1 faca
total <- total + nums[i];
fimpara
escreval total;
fim`,
}

const determinante2x2: Example = {
name: 'determinante',
label: 'Matriz 2x2',
code: `procedimento inteiro determinante2(inteiro m[2][2])
inicio
retorna m[0][0] * m[1][1] - m[0][1] * m[1][0];
fim

programa demo
inteiro m[2][2], d;
inicio
m[0][0] <- 1;
m[0][1] <- 2;
m[1][0] <- 3;
m[1][1] <- 4;

d <- determinante2(m);
escreval d;
fim`,
}

export const EXAMPLES: Example[] = [
hello,
fatorial,
fibonacci,
tabuada,
ifExample,
forExample,
whileExample,
readExample,
stringEcho,
vectorSum,
determinante2x2,
]
14 changes: 13 additions & 1 deletion frontend/src/pages/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { NasmPanel } from '../components/NasmPanel'
import { TerminalPanel, type TerminalPanelHandle } from '../components/TerminalPanel'
import { Toolbar } from '../components/Toolbar'
import { useRunWebSocket } from '../hooks/useRunWebSocket'
import type { Example } from '../lib/examples'

export function AppShell() {
const navigate = useNavigate()
Expand Down Expand Up @@ -91,6 +92,17 @@ export function AppShell() {
setCode(newCode)
}, [])

const handleClear = useCallback(() => {
terminalRef.current?.clear()
}, [])

const handleExampleSelect = useCallback((example: Example) => {
setCode(example.code)
setNasmOutput(undefined)
setCompileMarkers([])
terminalRef.current?.clear()
}, [])

const handleRun = useCallback(
(source: string) => {
ws.start(source)
Expand Down Expand Up @@ -130,7 +142,7 @@ export function AppShell() {
</header>

<div className="flex flex-1 flex-col overflow-hidden py-4">
<Toolbar code={code} onRun={handleRun} onStop={ws.stop} isRunning={isRunning} />
<Toolbar code={code} onRun={handleRun} onStop={ws.stop} isRunning={isRunning} onExampleSelect={handleExampleSelect} onClear={handleClear} />

<div className="mx-6 mt-3 min-h-0 flex-1">
<Group orientation="vertical" className="h-full">
Expand Down
Loading