Skip to content

Commit c71efdb

Browse files
committed
Add @ethdebug/bug-playground package to monorepo
Migrate the BUG language playground from the separate bugc repository. This is a Vite-based React app for interactive BUG code compilation and visualization. Changes: - Copy packages/playground with React components for editor and visualization (AST, IR, CFG, Bytecode views) - Change dev server port from 3000 to 3001 to avoid collision with Docusaurus - Update example paths to reference packages/bugc/examples/ - Add playground watch to bin/start - Exclude playground from vitest coverage (no tests) - Fix lint error in CfgView.tsx (case block braces) - Mark as private package (not published) Run with: yarn workspace @ethdebug/bug-playground start
1 parent 6c82720 commit c71efdb

40 files changed

+4396
-26
lines changed

bin/start

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ else
1010
fi
1111

1212
# Run the commands with concurrently
13-
concurrently --names=format,pointers,bugc,web,tests \
13+
concurrently --names=format,pointers,bugc,playground,web,tests \
1414
"cd ./packages/format && yarn watch" \
1515
"cd ./packages/pointers && yarn watch" \
1616
"cd ./packages/bugc && yarn watch" \
17+
"cd ./packages/playground && yarn watch" \
1718
"cd ./packages/web && yarn start $DOCUSAURUS_NO_OPEN" \
1819
"sleep 5 && yarn test --ui --watch --coverage $VITEST_NO_OPEN"
1920

packages/playground/.eslintrc.cjs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module.exports = {
2+
root: true,
3+
env: { browser: true, es2020: true },
4+
extends: [
5+
"eslint:recommended",
6+
"plugin:@typescript-eslint/recommended",
7+
"plugin:react-hooks/recommended",
8+
],
9+
ignorePatterns: ["dist", ".eslintrc.cjs"],
10+
parser: "@typescript-eslint/parser",
11+
plugins: ["react-refresh"],
12+
rules: {
13+
"react-refresh/only-export-components": [
14+
"warn",
15+
{ allowConstantExport: true },
16+
],
17+
"@typescript-eslint/no-explicit-any": "error",
18+
"@typescript-eslint/explicit-function-return-type": "off",
19+
"@typescript-eslint/explicit-module-boundary-types": "off",
20+
"no-console": "off",
21+
},
22+
};

packages/playground/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app.bundle.js

packages/playground/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# @ethdebug/bug-playground
2+
3+
A web-based playground for the BUG language, built with React, TypeScript, and Vite.
4+
5+
## Features
6+
7+
- **Monaco Editor**: Full-featured code editor with BUG syntax highlighting
8+
- **Live Compilation**: See AST, IR (optimized and unoptimized), and bytecode output
9+
- **Optimization Levels**: Choose from 4 optimization levels (0-3)
10+
- **Example Programs**: Automatically loaded from the `examples/` directory
11+
- **Error Highlighting**: Clear error messages and warnings from the compiler
12+
13+
## Development
14+
15+
Install dependencies:
16+
17+
```bash
18+
yarn install
19+
```
20+
21+
Start the development server:
22+
23+
```bash
24+
yarn dev
25+
```
26+
27+
Build for production:
28+
29+
```bash
30+
yarn build
31+
```
32+
33+
## Scripts
34+
35+
- `yarn start` - Start development server
36+
- `yarn build` - Build for production
37+
- `yarn preview` - Preview production build
38+
- `yarn typecheck` - Run TypeScript type checking
39+
- `yarn lint` - Run ESLint
40+
41+
## Architecture
42+
43+
The playground is organized by domain/logical concerns:
44+
45+
- `playground/` - Main playground UI and example programs
46+
- `editor/` - Monaco editor integration and BUG language definition
47+
- `compiler/` - Compiler integration and output visualization
48+
- `visualization/` - AST, IR, and bytecode visualizations
49+
50+
## Technologies
51+
52+
- React 18
53+
- TypeScript 5
54+
- Vite 5
55+
- Monaco Editor
56+
- @ethdebug/bugc (BUG Compiler)

packages/playground/index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>BUG Playground</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

packages/playground/package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "@ethdebug/bug-playground",
3+
"version": "0.1.0-0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"start": "vite",
8+
"build": "tsc && vite build",
9+
"watch": "vite build --watch",
10+
"preview": "vite preview",
11+
"typecheck": "tsc --noEmit",
12+
"lint": "eslint . --ext .ts,.tsx",
13+
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
14+
"format:check": "prettier --check \"src/**/*.{ts,tsx}\""
15+
},
16+
"dependencies": {
17+
"@ethdebug/bugc": "^0.1.0-0",
18+
"@monaco-editor/react": "^4.6.0",
19+
"@types/dagre": "^0.7.52",
20+
"dagre": "^0.8.5",
21+
"monaco-editor": "^0.52.2",
22+
"react": "^18.2.0",
23+
"react-dom": "^18.2.0",
24+
"react-flow-renderer": "^10.3.17",
25+
"vis-network": "^9.1.9"
26+
},
27+
"devDependencies": {
28+
"@types/react": "^18.2.43",
29+
"@types/react-dom": "^18.2.17",
30+
"@typescript-eslint/eslint-plugin": "^6.14.0",
31+
"@typescript-eslint/parser": "^6.14.0",
32+
"@vitejs/plugin-react": "^4.2.1",
33+
"eslint": "^8.55.0",
34+
"eslint-plugin-react-hooks": "^4.6.0",
35+
"eslint-plugin-react-refresh": "^0.4.5",
36+
"typescript": "^5.2.2",
37+
"vite": "^5.0.8"
38+
}
39+
}

packages/playground/src/App.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Playground } from "./playground/Playground";
2+
3+
export function App() {
4+
return (
5+
<div className="app">
6+
<Playground />
7+
</div>
8+
);
9+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.compiler-output {
2+
display: flex;
3+
flex-direction: column;
4+
height: 100%;
5+
background-color: #1e1e1e;
6+
}
7+
8+
.output-tabs {
9+
display: flex;
10+
background-color: #2d2d30;
11+
border-bottom: 1px solid #3e3e42;
12+
overflow-x: auto;
13+
}
14+
15+
.output-tab {
16+
padding: 0.5rem 1rem;
17+
background: none;
18+
border: none;
19+
border-bottom: 2px solid transparent;
20+
color: #969696;
21+
font-size: 0.875rem;
22+
cursor: pointer;
23+
white-space: nowrap;
24+
transition:
25+
color 0.2s,
26+
border-color 0.2s;
27+
}
28+
29+
.output-tab:hover:not(:disabled) {
30+
color: #cccccc;
31+
}
32+
33+
.output-tab.active {
34+
color: #ffffff;
35+
border-bottom-color: #0e639c;
36+
}
37+
38+
.output-tab:disabled {
39+
opacity: 0.5;
40+
cursor: not-allowed;
41+
}
42+
43+
.output-content {
44+
flex: 1;
45+
overflow: auto;
46+
padding: 1rem;
47+
}
48+
49+
.output-warnings {
50+
background-color: #332b00;
51+
border-top: 1px solid #665500;
52+
padding: 1rem;
53+
color: #ffcc00;
54+
}
55+
56+
.output-warnings h3 {
57+
margin: 0 0 0.5rem 0;
58+
font-size: 0.875rem;
59+
font-weight: 600;
60+
}
61+
62+
.output-warnings ul {
63+
margin: 0;
64+
padding-left: 1.5rem;
65+
}
66+
67+
.output-warnings li {
68+
font-size: 0.813rem;
69+
line-height: 1.5;
70+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { useState } from "react";
2+
import type { CompileResult } from "./types";
3+
import { AstView } from "../visualization/AstView";
4+
import { IrView } from "../visualization/IrView";
5+
import { CfgView } from "../visualization/CfgView";
6+
import { BytecodeView } from "../visualization/BytecodeView";
7+
import { ErrorView } from "./ErrorView";
8+
import type { SourceRange } from "../visualization/debugUtils";
9+
import "./CompilerOutput.css";
10+
11+
interface CompilerOutputProps {
12+
result: CompileResult;
13+
onOpcodeHover?: (ranges: SourceRange[]) => void;
14+
}
15+
16+
type TabType = "ast" | "ir" | "cfg" | "bytecode" | "error";
17+
18+
export function CompilerOutput({ result, onOpcodeHover }: CompilerOutputProps) {
19+
const [activeTab, setActiveTab] = useState<TabType>(
20+
result.success ? "ast" : "error",
21+
);
22+
23+
if (!result.success) {
24+
return <ErrorView error={result.error} warnings={result.warnings} />;
25+
}
26+
27+
const tabs: { id: TabType; label: string; disabled?: boolean }[] = [
28+
{ id: "ast", label: "AST" },
29+
{ id: "ir", label: "IR" },
30+
{ id: "cfg", label: "CFG" },
31+
{ id: "bytecode", label: "Bytecode" },
32+
];
33+
34+
return (
35+
<div className="compiler-output">
36+
<div className="output-tabs">
37+
{tabs.map((tab) => (
38+
<button
39+
key={tab.id}
40+
className={`output-tab ${activeTab === tab.id ? "active" : ""}`}
41+
onClick={() => setActiveTab(tab.id)}
42+
disabled={tab.disabled}
43+
>
44+
{tab.label}
45+
</button>
46+
))}
47+
</div>
48+
49+
<div className="output-content">
50+
{activeTab === "ast" && <AstView ast={result.ast} />}
51+
{activeTab === "ir" && (
52+
<IrView ir={result.ir} onOpcodeHover={onOpcodeHover} />
53+
)}
54+
{activeTab === "cfg" && <CfgView ir={result.ir} />}
55+
{activeTab === "bytecode" && (
56+
<BytecodeView
57+
bytecode={result.bytecode}
58+
onOpcodeHover={onOpcodeHover}
59+
/>
60+
)}
61+
</div>
62+
63+
{result.warnings.length > 0 && (
64+
<div className="output-warnings">
65+
<h3>Warnings:</h3>
66+
<ul>
67+
{result.warnings.map((warning, i) => (
68+
<li key={i}>{warning}</li>
69+
))}
70+
</ul>
71+
</div>
72+
)}
73+
</div>
74+
);
75+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.error-view {
2+
padding: 1rem;
3+
height: 100%;
4+
overflow: auto;
5+
}
6+
7+
.error-content {
8+
background-color: #5a1d1d;
9+
border: 1px solid #f48771;
10+
border-radius: 4px;
11+
padding: 1rem;
12+
margin-bottom: 1rem;
13+
}
14+
15+
.error-content h3 {
16+
color: #f48771;
17+
margin: 0 0 0.5rem 0;
18+
font-size: 1rem;
19+
}
20+
21+
.error-message {
22+
color: #ffcccc;
23+
margin: 0;
24+
font-family: "Consolas", "Monaco", "Courier New", monospace;
25+
font-size: 0.875rem;
26+
line-height: 1.5;
27+
white-space: pre-wrap;
28+
}
29+
30+
.error-warnings {
31+
background-color: #332b00;
32+
border: 1px solid #665500;
33+
border-radius: 4px;
34+
padding: 1rem;
35+
color: #ffcc00;
36+
}
37+
38+
.error-warnings h4 {
39+
margin: 0 0 0.5rem 0;
40+
font-size: 0.875rem;
41+
}
42+
43+
.error-warnings ul {
44+
margin: 0;
45+
padding-left: 1.5rem;
46+
}
47+
48+
.error-warnings li {
49+
font-size: 0.813rem;
50+
line-height: 1.5;
51+
}

0 commit comments

Comments
 (0)