@@ -437,8 +437,7 @@ <h1>Null-Safe C Playground</h1>
437437 </ button >
438438
439439 < select id ="examplesSelect " class ="examples-select ">
440- < option value =""> Load Example...</ option >
441- < option value ="null-check "> Null Check Example</ option >
440+ < option value ="null-check " selected > Null Check Example</ option >
442441 < option value ="array "> Array Safety</ option >
443442 < option value ="function "> Function Parameters</ option >
444443 </ select >
@@ -573,58 +572,73 @@ <h1>Null-Safe C Playground</h1>
573572 'null-check' : `#include <stdio.h>
574573#include <stdlib.h>
575574
576- // Null Check Example
575+ // Pointers are nullable by default
576+ // The compiler tracks null checks!
577+
577578int main(void) {
578- // Declaring a nullable pointer
579- int * _Nullable ptr = NULL;
579+ int *ptr = NULL;
580580
581- // ERROR: Dereferencing potentially null pointer
581+ // WARNING: might be null!
582582 *ptr = 42;
583583
584- // CORRECT: Check before dereferencing
584+ // After null check, compiler knows it's safe
585585 if (ptr != NULL) {
586- *ptr = 42; // OK
586+ *ptr = 42; // OK - compiler knows ptr is non-null here
587587 }
588588
589589 return 0;
590590}` ,
591591 'array' : `#include <stdio.h>
592592#include <stdlib.h>
593593
594- // Array Safety Example
594+ // malloc can return NULL if allocation fails
595+
595596int main(void) {
596- // Nullable array pointer
597- int * _Nullable arr = malloc(10 * sizeof(int));
597+ int *arr = malloc(10 * sizeof(int));
598598
599- // ERROR: Using without null check
599+ // WARNING: arr might be NULL
600600 arr[0] = 42;
601601
602- // CORRECT: Check first
602+ // SAFE: check before use
603603 if (arr != NULL) {
604- arr[0] = 42; // OK
604+ arr[0] = 42;
605+ arr[1] = 100;
606+ printf("arr[0] = %d\\n", arr[0]);
605607 free(arr);
608+ } else {
609+ printf("Allocation failed!\\n");
606610 }
607611
608612 return 0;
609613}` ,
610614 'function' : `#include <stdio.h>
611615
612- // Function with nullable parameter
613- void process(int * _Nullable ptr) {
614- // ERROR: Unsafe dereference
615- int value = *ptr;
616+ // Parameters are nullable by default
617+ void process(int *data) {
618+ // WARNING: data might be null
619+ *data = 42;
620+ }
616621
617- // CORRECT: Check first
618- if (ptr != NULL ) {
619- int value = *ptr; // OK
620- printf("Value: %d\\n", value);
622+ // Safe version with null check
623+ void process_safe(int *data ) {
624+ if (data != NULL) {
625+ *data = 42; // OK - compiler knows data is non-null
621626 }
622627}
623628
629+ // Explicitly non-null parameter
630+ void guaranteed(int * _Nonnull data) {
631+ *data = 42; // Always safe - caller must pass non-null
632+ }
633+
624634int main(void) {
625635 int x = 42;
626- process(&x);
627- process(NULL);
636+ int *ptr = &x;
637+
638+ process(ptr); // Works but ptr might be null
639+ process_safe(ptr); // Safe - checks for null
640+ guaranteed(ptr); // OK - ptr is non-null here
641+
628642 return 0;
629643}`
630644 } ;
@@ -678,7 +692,7 @@ <h1>Null-Safe C Playground</h1>
678692 editor . value = examples [ example ] ;
679693 updateHighlight ( ) ; // Update highlighting
680694 showToast ( 'Example loaded!' ) ;
681- e . target . value = '' ;
695+ // Don't reset - keep the selection showing
682696 }
683697 } ) ;
684698
@@ -699,6 +713,10 @@ <h1>Null-Safe C Playground</h1>
699713 showToast ( 'Output cleared' ) ;
700714 } ) ;
701715
716+ let capturedStdout = '' ;
717+ let capturedStderr = '' ;
718+ let captureOutput = false ;
719+
702720 async function initCompiler ( ) {
703721 status . textContent = 'Loading compiler (64MB)...' ;
704722 status . className = 'status' ;
@@ -708,24 +726,51 @@ <h1>Null-Safe C Playground</h1>
708726 // Configure Module before loading clang.js
709727 window . Module = {
710728 print : function ( text ) {
711- console . log ( '[stdout]' , text ) ;
729+ if ( captureOutput ) {
730+ capturedStdout += text + '\n' ;
731+ console . log ( '[captured stdout]' , text ) ;
732+ } else {
733+ console . log ( '[stdout]' , text ) ;
734+ }
712735 } ,
713736 printErr : function ( text ) {
714- console . log ( '[stderr]' , text ) ;
737+ if ( captureOutput ) {
738+ capturedStderr += text + '\n' ;
739+ console . log ( '[captured stderr]' , text ) ;
740+ } else {
741+ console . log ( '[stderr]' , text ) ;
742+ }
715743 } ,
716744 noInitialRun : true ,
745+ noExitRuntime : true , // Keep runtime alive
746+ // Set up command line arguments
747+ arguments : [ ] ,
717748 onRuntimeInitialized : function ( ) {
718749 ClangModule = window . Module ;
719750 console . log ( 'Runtime initialized!' ) ;
720751 console . log ( 'Module has FS:' , ! ! window . Module . FS ) ;
721- console . log ( 'All Module keys:' , Object . keys ( window . Module ) ) ;
752+ console . log ( 'Module has callMain:' , ! ! window . Module . callMain ) ;
753+
754+ // Check all properties for main/call-related and exported functions
755+ const mainFuncs = Object . keys ( window . Module ) . filter ( k =>
756+ k . toLowerCase ( ) . includes ( 'main' ) || k . toLowerCase ( ) . includes ( 'call' ) || k . startsWith ( '_' )
757+ ) ;
758+ console . log ( 'Main/call/exported functions:' , mainFuncs ) ;
759+
760+ // Check wasmExports
761+ if ( window . Module . asm ) {
762+ console . log ( 'Module.asm keys:' , Object . keys ( window . Module . asm ) . slice ( 0 , 50 ) ) ;
763+ }
722764
723765 status . textContent = 'Ready to compile' ;
724766 status . className = 'status ready' ;
725767 compileBtn . disabled = false ;
726768 loadingBar . classList . remove ( 'active' ) ;
727769 showToast ( 'Compiler loaded successfully!' ) ;
728770 console . log ( 'Clang WASM module loaded successfully' ) ;
771+
772+ // Auto-compile the initial example
773+ setTimeout ( ( ) => compile ( ) , 500 ) ;
729774 }
730775 } ;
731776
@@ -813,57 +858,74 @@ <h1>Null-Safe C Playground</h1>
813858 async function compileCode ( code ) {
814859 return new Promise ( ( resolve , reject ) => {
815860 try {
816- console . log ( 'Starting compilation, Module available:' , ! ! window . Module ) ;
817- console . log ( 'Module.FS available:' , ! ! window . Module ?. FS ) ;
818- console . log ( 'Global FS available:' , ! ! window . FS ) ;
819- console . log ( 'Module keys:' , window . Module ? Object . keys ( window . Module ) . slice ( 0 , 30 ) : 'none' ) ;
861+ const inputFile = 'input.c' ; // Try relative path
820862
821- const inputFile = '/input.c' ;
822-
823- // Try to find FS - it might be global or on Module
863+ // Get FS
824864 const FS = window . Module ?. FS || window . FS ;
825-
826865 if ( ! FS ) {
827- throw new Error ( 'FS is not available - Module.FS: ' + ! ! window . Module ?. FS + ', window.FS: ' + ! ! window . FS ) ;
866+ throw new Error ( 'FS is not available' ) ;
828867 }
829868
869+ // Write the file
830870 FS . writeFile ( inputFile , code ) ;
831871
832- let stdout = '' ;
833- let stderr = '' ;
872+ // Verify file exists
873+ try {
874+ const fileContent = FS . readFile ( inputFile , { encoding : 'utf8' } ) ;
875+ console . log ( 'File written successfully, size:' , fileContent . length ) ;
876+ console . log ( 'File content preview:' , fileContent . substring ( 0 , 100 ) ) ;
877+ } catch ( e ) {
878+ console . error ( 'Cannot read back file:' , e ) ;
879+ }
834880
835- const oldPrint = Module . print ;
836- const oldPrintErr = Module . printErr ;
881+ // List files in root
882+ try {
883+ const files = FS . readdir ( '/' ) ;
884+ console . log ( 'Files in root:' , files ) ;
885+ } catch ( e ) {
886+ console . error ( 'Cannot list files:' , e ) ;
887+ }
837888
838- Module . print = ( text ) => {
839- stdout += text + '\n' ;
840- } ;
841- Module . printErr = ( text ) => {
842- stderr += text + '\n' ;
843- } ;
889+ // Reset and enable capture
890+ capturedStdout = '' ;
891+ capturedStderr = '' ;
892+ captureOutput = true ;
844893
845894 try {
846- Module . callMain ( [
847- '-fsyntax-only' ,
848- '-Xclang' , '-verify' ,
849- inputFile
850- ] ) ;
895+ // Emscripten doesn't pass Module.arguments to an already-running main
896+ // We need to set up ENV and call differently
897+ const oldArgs = Module . arguments ;
898+
899+ // Try setting arguments before calling _main
900+ Module [ 'arguments' ] = [ '-fsyntax-only' , 'input.c' ] ;
901+
902+ console . log ( 'Calling clang with Module.arguments:' , Module . arguments ) ;
903+
904+ // Try calling with argc/argv = 0, Emscripten should use Module.arguments
905+ // But it seems like it doesn't work for subsequent calls
906+ // Let's try passing actual argc
907+ const argc = 2 ; // Program name + our args
908+ const exitCode = Module . _main ( argc , 0 ) ;
909+ console . log ( 'Clang exit code:' , exitCode ) ;
910+
911+ Module . arguments = oldArgs ;
851912 } catch ( e ) {
852- // Clang may throw on errors, that's okay
853- console . log ( 'Clang execution completed (may have thrown):' , e ) ;
913+ console . log ( 'Clang execution error:' , e ) ;
854914 }
855915
856- Module . print = oldPrint ;
857- Module . printErr = oldPrintErr ;
916+ // Disable capture
917+ captureOutput = false ;
858918
859919 try {
860920 FS . unlink ( inputFile ) ;
861921 } catch ( e ) {
862- // File might not exist
922+ // Ignore
863923 }
864924
865- resolve ( { stdout, stderr } ) ;
925+ console . log ( 'Compilation result:' , { stdout : capturedStdout , stderr : capturedStderr } ) ;
926+ resolve ( { stdout : capturedStdout , stderr : capturedStderr } ) ;
866927 } catch ( error ) {
928+ captureOutput = false ;
867929 console . error ( 'compileCode error:' , error ) ;
868930 reject ( error ) ;
869931 }
0 commit comments