8989 margin-top : 0.5rem ;
9090 font-size : 0.98rem ;
9191 color : var (--tx-2 );
92+ white-space : pre-wrap;
9293 }
9394
9495 .status .error {
@@ -195,6 +196,14 @@ <h2 style="margin: 0;">Output</h2>
195196
196197 const STORAGE_KEY = 'brainfuck-interpreter-code' ;
197198
199+ class BrainfuckTimeoutError extends Error {
200+ constructor ( message , debugInfo ) {
201+ super ( message ) ;
202+ this . name = 'BrainfuckTimeoutError' ;
203+ this . debugInfo = debugInfo ;
204+ }
205+ }
206+
198207 function updateStatus ( message , isError = false ) {
199208 statusEl . textContent = message ;
200209 statusEl . classList . toggle ( 'error' , isError ) ;
@@ -304,6 +313,26 @@ <h2 style="margin: 0;">Output</h2>
304313 return map ;
305314 }
306315
316+ function formatTapeWindow ( tape , pointer ) {
317+ const windowSize = Math . min ( 30 , tape . length || 1 ) ;
318+ const halfWindow = Math . floor ( windowSize / 2 ) ;
319+ let start = Math . max ( 0 , pointer - halfWindow ) ;
320+ let end = Math . min ( tape . length - 1 , start + windowSize - 1 ) ;
321+
322+ if ( end - start + 1 < windowSize ) {
323+ start = Math . max ( 0 , end - windowSize + 1 ) ;
324+ }
325+
326+ const leftEllipsis = start > 0 ;
327+ const rightEllipsis = end < tape . length - 1 ;
328+ const cells = tape . slice ( start , end + 1 ) . map ( ( value , index ) => {
329+ const absoluteIndex = start + index ;
330+ return absoluteIndex === pointer ? `[${ value } ]` : `${ value } ` ;
331+ } ) ;
332+
333+ return `${ leftEllipsis ? '… ' : '' } ${ cells . join ( ' ' ) } ${ rightEllipsis ? ' …' : '' } ` ;
334+ }
335+
307336 function runProgram ( program , inputs ) {
308337 const commands = program . replace ( / [ ^ \> \< \+ \- \. \, \[ \] ] / g, '' ) ;
309338 const jumpMap = buildJumpMap ( commands ) ;
@@ -313,8 +342,19 @@ <h2 style="margin: 0;">Output</h2>
313342 let inputIndex = 0 ;
314343 let ip = 0 ;
315344 const output = [ ] ;
345+ const timeoutMs = 3000 ;
346+ const startTime = performance . now ( ) ;
316347
317348 while ( ip < commands . length ) {
349+ if ( performance . now ( ) - startTime > timeoutMs ) {
350+ const debugInfo = [
351+ `Tape length: ${ tape . length } ` ,
352+ `Pointer position: ${ pointer } ` ,
353+ `Tape window: ${ formatTapeWindow ( tape , pointer ) } ` ,
354+ ] . join ( '\n' ) ;
355+ throw new BrainfuckTimeoutError ( 'Execution timed out after 3 seconds.' , debugInfo ) ;
356+ }
357+
318358 const instruction = commands [ ip ] ;
319359 switch ( instruction ) {
320360 case '>' :
@@ -382,7 +422,10 @@ <h2 style="margin: 0;">Output</h2>
382422 renderOutput ( output ) ;
383423 updateStatus ( `Program ran successfully. Output length: ${ output . length } byte${ output . length === 1 ? '' : 's' } .` ) ;
384424 } catch ( error ) {
385- updateStatus ( error . message , true ) ;
425+ const debugDetails = error instanceof BrainfuckTimeoutError && error . debugInfo
426+ ? `${ error . message } \n\nDebug info:\n${ error . debugInfo } `
427+ : error . message ;
428+ updateStatus ( debugDetails , true ) ;
386429 outputAscii . textContent = '(no output)' ;
387430 outputBytes . textContent = '(no output)' ;
388431 }
0 commit comments