33using System . Text . Json . Serialization ;
44using MiniLang . Semantic ;
55using MiniLang . Syntax ;
6+ using MiniLang . Wasm ;
67
78public class Program
89{
@@ -77,6 +78,8 @@ public static void Main(string[] args)
7778 return ;
7879 }
7980
81+ var lineStarts = SourceMapping . ComputeLineStarts ( sourceCode ) ;
82+
8083 TextWriter writer = outputFile != null
8184 ? new StreamWriter ( outputFile , false , new UTF8Encoding ( false ) )
8285 : Console . Out ;
@@ -91,18 +94,24 @@ public static void Main(string[] args)
9194 } ;
9295
9396 IReadOnlyList < Token > tokens ;
97+ IReadOnlyDictionary < int , List < Token > > tokensByLine ;
9498 try
9599 {
96100 tokens = new Lexer ( sourceCode ) . ScanTokens ( ) ;
101+ tokensByLine = SourceMapping . BuildTokenLineMap ( tokens ) ;
97102 }
98103 catch ( SyntaxError le )
99104 {
100- var lexErr = new Diagnostic ( Stage . Lex , le . Line , le . Message , Severity . Error ) ;
101- var output = new PipelineOutput ( Array . Empty < Token > ( ) , null , new SemanticReport ( Array . Empty < Diagnostic > ( ) , Array . Empty < Diagnostic > ( ) ) , null , lexErr , null , null ) ;
105+ var startOffset = SourceMapping . LineColumnToOffset ( le . Line , le . Column , lineStarts , sourceCode ) ;
106+ var endOffset = startOffset . HasValue ? Math . Min ( startOffset . Value + 1 , sourceCode . Length ) : ( int ? ) null ;
107+ var lexErr = new Diagnostic ( Stage . Lex , le . Line , le . Message , Severity . Error , startOffset , endOffset ) ;
108+ var output = new PipelineOutput ( Array . Empty < Token > ( ) , null , new SemanticReport ( Array . Empty < Diagnostic > ( ) , Array . Empty < Diagnostic > ( ) ) , null , lexErr , null , null , null ) ;
102109 writer . WriteLine ( JsonSerializer . Serialize ( output , options ) ) ;
103110 return ;
104111 }
105112
113+
114+
106115 ProgramAst ? ast = null ;
107116 try
108117 {
@@ -111,33 +120,51 @@ public static void Main(string[] args)
111120 }
112121 catch ( SyntaxError pe )
113122 {
114- var parseErr = new Diagnostic ( Stage . Parse , pe . Line , pe . Message , Severity . Error ) ;
115- var output = new PipelineOutput ( tokens , null , new SemanticReport ( Array . Empty < Diagnostic > ( ) , Array . Empty < Diagnostic > ( ) ) , null , parseErr , null , null ) ;
123+ var startOffset = SourceMapping . LineColumnToOffset ( pe . Line , pe . Column , lineStarts , sourceCode ) ;
124+ var endOffset = startOffset . HasValue ? Math . Min ( startOffset . Value + 1 , sourceCode . Length ) : ( int ? ) null ;
125+ var parseErr = new Diagnostic ( Stage . Parse , pe . Line , pe . Message , Severity . Error , startOffset , endOffset ) ;
126+ var output = new PipelineOutput ( tokens , null , new SemanticReport ( Array . Empty < Diagnostic > ( ) , Array . Empty < Diagnostic > ( ) ) , null , parseErr , null , null , null ) ;
116127 writer . WriteLine ( JsonSerializer . Serialize ( output , options ) ) ;
117128 return ;
118129 }
119130
120131 var sema = new SemanticAnalyzer ( ) ;
121- var report = sema . Analyze ( ast , sourceCode ) ;
132+ var report = sema . Analyze ( ast , sourceCode , tokens ) ;
122133
123134 ProgramAst ? optimized = null ;
124135 List < Optimizer . OptimizationStep > ? steps = null ;
125136 string ? optimizedSource = null ;
126- try
137+ string ? wasmModuleBase64 = null ;
138+ Diagnostic ? stageError = null ;
139+ var res = Optimizer . OptimizeWithReport ( ast ) ;
140+ optimized = res . Program ;
141+ steps = res . Steps ;
142+ optimizedSource = optimized != null ? CodePrinter . PrintProgram ( optimized ) : null ;
143+ if ( steps != null )
127144 {
128- var res = Optimizer . OptimizeWithReport ( ast ) ;
129- optimized = res . Program ;
130- steps = res . Steps ;
131- optimizedSource = optimized != null ? CodePrinter . PrintProgram ( optimized ) : null ;
145+ steps = steps . Select ( step =>
146+ {
147+ var hint = step . Hint ?? ExtractHint ( step . Before ) ;
148+ var resolvedLine = SourceMapping . ResolveLine ( step . Line , hint , tokensByLine ) ?? step . Line ;
149+ var ( startOffset , endOffset ) = SourceMapping . ResolveSpan ( resolvedLine , hint , sourceCode , lineStarts , tokensByLine ) ;
150+ return step with { Line = resolvedLine , Start = startOffset , End = endOffset } ;
151+ } ) . ToList ( ) ;
132152 }
133- catch
153+ if ( optimized != null )
134154 {
135- optimized = null ;
136- steps = null ;
137- optimizedSource = null ;
155+ try
156+ {
157+ var wasmBytes = WasmCompiler . Compile ( optimized ) ;
158+ wasmModuleBase64 = Convert . ToBase64String ( wasmBytes ) ;
159+ }
160+ catch ( Exception ex )
161+ {
162+ wasmModuleBase64 = null ;
163+ stageError = new Diagnostic ( Stage . Optimize , 0 , ex . Message , Severity . Error ) ;
164+ }
138165 }
139166
140- var result = new PipelineOutput ( tokens , ast , report , optimized , null , steps , optimizedSource ) ;
167+ var result = new PipelineOutput ( tokens , ast , report , optimized , stageError , steps , optimizedSource , wasmModuleBase64 ) ;
141168 writer . WriteLine ( JsonSerializer . Serialize ( result , options ) ) ;
142169 }
143170 catch ( Exception e )
@@ -151,4 +178,34 @@ public static void Main(string[] args)
151178 writer . Dispose ( ) ;
152179 }
153180 }
181+
182+ private static string ? ExtractHint ( string ? before )
183+ {
184+ if ( string . IsNullOrWhiteSpace ( before ) )
185+ return null ;
186+
187+ var trimmed = before . TrimStart ( ) ;
188+ var newlineIndex = trimmed . IndexOfAny ( new [ ] { '\r ' , '\n ' } ) ;
189+ if ( newlineIndex >= 0 )
190+ trimmed = trimmed [ ..newlineIndex ] ;
191+
192+ if ( trimmed . Length == 0 )
193+ return null ;
194+
195+ var start = 0 ;
196+ while ( start < trimmed . Length && ! char . IsLetter ( trimmed [ start ] ) && trimmed [ start ] != '_' )
197+ start ++ ;
198+
199+ if ( start >= trimmed . Length )
200+ return null ;
201+
202+ var end = start ;
203+ while ( end < trimmed . Length && ( char . IsLetterOrDigit ( trimmed [ end ] ) || trimmed [ end ] == '_' ) )
204+ end ++ ;
205+
206+ if ( end == start )
207+ return null ;
208+
209+ return trimmed [ start ..end ] ;
210+ }
154211}
0 commit comments