-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcd.html
More file actions
290 lines (255 loc) · 15.6 KB
/
Copy pathcd.html
File metadata and controls
290 lines (255 loc) · 15.6 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Py2JS Transpiler</title>
<!-- Load Tailwind CSS for a modern, responsive UI -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Custom styles for the code areas */
body {
font-family: 'Times New Roman', Times, serif; /* Changed to Times New Roman */
background-color: #1e293b; /* Deep Cobalt Background */
color: #f1f5f9; /* Light text */
}
.code-area {
font-family: 'Fira Code', 'Courier New', monospace;
min-height: 450px;
padding: 1.5rem;
border-radius: 0.75rem;
resize: none;
transition: all 0.3s ease-in-out;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2); /* Stronger shadow for depth */
line-height: 1.5;
background-color: #334155; /* Slightly lighter card background */
color: #e2e8f0; /* Off-white code text */
border: 1px solid #475569; /* Subtle border */
}
.code-area:focus {
outline: none;
}
/* Custom scrollbar to match the dark theme */
.code-area::-webkit-scrollbar {
width: 8px;
}
.code-area::-webkit-scrollbar-thumb {
background-color: #475569;
border-radius: 10px;
}
</style>
</head>
<body class="p-4 sm:p-8 lg:p-12">
<div class="max-w-7xl mx-auto">
<header class="text-center mb-12 p-8 bg-slate-700 rounded-2xl shadow-2xl shadow-slate-900/70 border border-slate-600">
<h1 class="text-4xl sm:text-5xl font-extrabold tracking-tight text-white">
<span class="text-sky-400">Py</span><span class="text-yellow-400">2</span><span class="text-sky-400">JS</span> <span class="text-white">Compiler Workbench</span>
</h1>
<p class="text-slate-400 mt-2 text-md sm:text-lg font-medium">
The Core of Compiler Design: AST Traversal and Code Generation
</p>
</header>
<!-- Main Workspace: Side-by-Side starting on small screens (sm:flex-row) -->
<div class="flex flex-col sm:flex-row gap-6 lg:gap-8">
<!-- Python Input Panel (Left) - Electric Blue Branding -->
<div class="flex-1 bg-slate-700 rounded-xl shadow-2xl border-t-4 border-sky-500">
<div class="p-6">
<label for="python-input" class="block text-xl font-bold mb-4 text-sky-400 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6 h-6 mr-3 text-sky-400">
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 7.5l3 3m0 0l3 3m-3-3l-3 3m3-3v9" />
<path stroke-linecap="round" stroke-linejoin="round" d="M12.75 21v-4.5h3.375c.621 0 1.125-.504 1.125-1.125V12.75a1.125 1.125 0 00-1.125-1.125h-3.375V6.75a1.125 1.125 0 00-1.125-1.125H10.5M5.625 5.625A2.625 2.625 0 018.25 3h7.5A2.625 2.625 0 0118.375 5.625V18.375A2.625 2.625 0 0115.75 21h-7.5A2.625 2.625 0 015.625 18.375V5.625z" />
</svg>
Python Source (Input)
</label>
<textarea id="python-input" class="code-area w-full focus:border-sky-400 focus:shadow-sky-500/30 focus:ring-4 focus:ring-sky-500/30" placeholder="Enter your Python code here (e.g., function definitions, loops, conditionals, etc.)."></textarea>
</div>
</div>
<!-- JavaScript Output Panel (Right) - Vibrant Orange Branding -->
<div class="flex-1 bg-slate-700 rounded-xl shadow-2xl border-t-4 border-amber-500">
<div class="p-6">
<label for="javascript-output" class="block text-xl font-bold mb-4 text-amber-400 flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-6 h-6 mr-3 text-amber-500">
<path stroke-linecap="round" stroke-linejoin="round" d="M17.25 6.75L20.25 12l-3 5.25m-10.5-5.25L3.75 12l3-5.25m7.5-3l1.268 3.967A4.5 4.5 0 0115 10.5a4.5 4.5 0 01-1.982 3.868L11.25 18" />
</svg>
JavaScript Target (Output)
</label>
<textarea id="javascript-output" class="code-area w-full focus:border-amber-400 focus:shadow-amber-500/30 focus:ring-4 focus:ring-amber-500/30" readonly placeholder="Transpiled JavaScript will appear here."></textarea>
</div>
</div>
</div>
<!-- Transpile Button -->
<div class="mt-12 flex justify-center">
<button id="transpile-button" class="py-4 px-16 bg-sky-600 hover:bg-sky-500 text-white text-xl font-extrabold rounded-full shadow-2xl shadow-sky-400/50 transition duration-300 transform hover:scale-[1.03] active:scale-95 flex items-center space-x-3 uppercase tracking-wider">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6">
<path fill-rule="evenodd" d="M4.5 5.653c0-1.427 1.529-2.33 2.779-1.643l11.54 6.416c1.26 0.701 1.26 2.507 0 3.208l-11.54 6.416c-1.25 0.687-2.779-0.236-2.779-1.643V5.653z" clip-rule="evenodd" />
</svg>
<span>Compile & Generate</span>
</button>
</div>
<!-- Notification Area -->
<div id="notification-area" class="mt-8 p-4 text-center text-lg rounded-xl shadow-lg hidden transition duration-300 font-medium border text-white"></div>
</div>
<script>
const pythonInput = document.getElementById('python-input');
const jsOutput = document.getElementById('javascript-output');
const notificationArea = document.getElementById('notification-area');
const transpileButton = document.getElementById('transpile-button');
// ==============================================================================
// THE CORE TRANSPILER LOGIC (Simplified Structure Mimicking AST Translation)
// ==============================================================================
// This is a highly simplified translator that uses basic string manipulation and
// regex/structured search. In a real compiler project, you would use a full
// tokenizer/parser (like the 'ast' module does) before this translation step.
function JavaScriptTranspiler(pythonCode) {
// Clean up and split code into lines for processing
let lines = pythonCode.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0 && !line.startsWith('#'));
let js_code = [];
// State for handling control flow blocks (like if/while)
let in_block = false;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
let next_line = lines[i + 1] || "";
let converted_line = line;
try {
// --- 1. Function Definition (def -> function) ---
if (line.startsWith('def ')) {
// Converts 'def func(a, b):' to 'function func(a, b) {'
converted_line = line.replace(/def\s+(\w+)\s*\(([^)]*)\)\s*:/, 'function $1($2) {');
in_block = true;
}
// --- 2. Print Statement (print(...) -> console.log(...)) ---
else if (line.startsWith('print(')) {
converted_line = line.replace(/print\s*\(([^)]*)\)/, 'console.log($1);');
}
// --- 3. Assignment (Variable Declaration) ---
else if (/^(\w+)\s*=[^=]/.test(line)) {
// Simple assignment 'a = 10' becomes 'let a = 10;'
// This is an oversimplification; real AST is needed to distinguish assignments vs. re-assignments
converted_line = 'let ' + line + ';';
}
// --- 4. F-String (f'...' -> `...${...}`) ---
converted_line = converted_line.replace(/f['"](.*?)['"]/g, (match, p1) => {
// Convert {variable} to ${variable}
let template = p1.replace(/{([^}]*)}/g, '${$1}');
return '`' + template + '`';
});
// --- 5. WHILE Loop (while condition: -> while (condition) { ) ---
if (line.startsWith('while ')) {
// Converts 'while condition:' to 'while (condition) {'
converted_line = line.replace(/while\s+(.*?):/, 'while ($1) {');
in_block = true;
}
// --- 6. IF/ELIF/ELSE Statements ---
if (line.startsWith('if ')) {
// Converts 'if condition:' to 'if (condition) {'
converted_line = line.replace(/if\s+(.*?):/, 'if ($1) {');
in_block = true;
} else if (line.startsWith('elif ')) {
// Converts 'elif condition:' to '} else if (condition) {'
converted_line = '} else ' + line.replace(/elif\s+(.*?):/, 'if ($1) {');
in_block = true;
} else if (line.startsWith('else:')) {
// Converts 'else:' to '} else {'
converted_line = '} else {';
in_block = true;
}
// --- 7. Block Closure (Detecting the end of a block) ---
// This is the trickiest part without indentation parsing.
// We assume a block closes when the next line is the start of a new, major block or a return statement.
if (in_block) {
// Close block if next line is a function def, an if/while, or the end of code.
if (!next_line.startsWith('if ') && !next_line.startsWith('elif ') && !next_line.startsWith('else:') && !next_line.startsWith('while ') && (i === lines.length - 1 || next_line.startsWith('def '))) {
// Only close if it's not part of an if/elif/else chain
if (!line.startsWith('if ') && !line.startsWith('elif ') && !line.startsWith('else:') && !line.startsWith('while ') && !next_line.startsWith('return')) {
// Add a closing brace if the current line is the last in the body
if (!line.includes('return')) {
js_code.push(converted_line);
js_code.push('}'); // Assume block closes here
in_block = false;
}
}
}
}
// --- 8. Return Statement (return a -> return a;) ---
if (line.startsWith('return ')) {
converted_line = line + ';';
// Add a closing brace after the return statement for the function
js_code.push(converted_line);
if (i + 1 < lines.length && lines[i+1].startsWith('def ')) {
js_code.push('}');
in_block = false;
} else if (i === lines.length - 1) {
js_code.push('}');
in_block = false;
}
continue; // Skip the default push below
}
// Add the converted line (if not already added by a special case)
if (converted_line.length > 0) {
js_code.push(converted_line);
}
} catch (e) {
// In a real transpiler, detailed error handling would be here
throw new Error(`Syntax Error near line: ${line}. Error: ${e.message}`);
}
}
// Final closing brace if something was left open (e.g., function call block)
if (in_block) {
js_code.push('}');
}
return js_code.join('\n');
}
// ==============================================================================
// UI LOGIC
// ==============================================================================
function showNotification(message, isError = false) {
notificationArea.textContent = message;
notificationArea.classList.remove('hidden', 'bg-red-900', 'text-red-200', 'shadow-red-700/50', 'border-red-600', 'bg-green-900', 'text-green-200', 'shadow-green-700/50', 'border-green-600', 'bg-blue-900', 'text-blue-200', 'shadow-blue-700/50', 'border-blue-600');
// Set styles based on success/error/warning
if (isError) {
notificationArea.classList.add('bg-red-900', 'text-red-200', 'shadow-red-700/50', 'border-red-600');
} else if (message.includes('successful')) {
notificationArea.classList.add('bg-green-900', 'text-green-200', 'shadow-green-700/50', 'border-green-600');
} else {
notificationArea.classList.add('bg-blue-900', 'text-blue-200', 'shadow-blue-700/50', 'border-blue-600');
}
notificationArea.classList.remove('hidden');
}
/**
* Core transpilation function.
*/
function transpileCode() {
const pythonCode = pythonInput.value.trim();
jsOutput.value = '';
// Clear notification area when button is clicked
notificationArea.classList.add('hidden');
if (!pythonCode) {
// If code is empty, we don't need to show a success message, just clear the output
jsOutput.value = '';
showNotification("Awaiting Python code input.", false);
return;
}
try {
const javascriptCode = JavaScriptTranspiler(pythonCode);
jsOutput.value = javascriptCode;
showNotification("Transpilation successful! JavaScript code generated.", false);
} catch (e) {
jsOutput.value = '';
showNotification(`COMPILER ERROR: ${e.message}`, true);
}
}
// --- Event Listener for Button Click (Manual Compilation Only) ---
transpileButton.addEventListener('click', transpileCode);
// --- NEW LOGIC: Clear Output if Input becomes empty (Non-Compile Action) ---
pythonInput.addEventListener('input', () => {
// Check if the input field is empty (ignoring whitespace for robustness)
if (pythonInput.value.trim() === '') {
jsOutput.value = '';
notificationArea.classList.add('hidden');
}
});
</script>
</body>
</html>