143 lines
4.4 KiB
Go
143 lines
4.4 KiB
Go
package tsc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"runtime"
|
|
"time"
|
|
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/collections"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/compiler"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tsoptions"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
)
|
|
|
|
func GetTraceWithWriterFromSys(w io.Writer, testing CommandLineTesting) func(msg string) {
|
|
if testing == nil {
|
|
return func(msg string) {
|
|
fmt.Fprintln(w, msg)
|
|
}
|
|
} else {
|
|
return testing.GetTrace(w)
|
|
}
|
|
}
|
|
|
|
type EmitInput struct {
|
|
Sys System
|
|
ProgramLike compiler.ProgramLike
|
|
Program *compiler.Program
|
|
Config *tsoptions.ParsedCommandLine
|
|
ReportDiagnostic DiagnosticReporter
|
|
ReportErrorSummary DiagnosticsReporter
|
|
Writer io.Writer
|
|
WriteFile compiler.WriteFile
|
|
CompileTimes *CompileTimes
|
|
Testing CommandLineTesting
|
|
TestingMTimesCache *collections.SyncMap[tspath.Path, time.Time]
|
|
}
|
|
|
|
func EmitAndReportStatistics(input EmitInput) (CompileAndEmitResult, *Statistics) {
|
|
var statistics *Statistics
|
|
result := EmitFilesAndReportErrors(input)
|
|
if result.Status != ExitStatusSuccess {
|
|
// compile exited early
|
|
return result, nil
|
|
}
|
|
result.times.totalTime = input.Sys.SinceStart()
|
|
|
|
if input.Config.CompilerOptions().Diagnostics.IsTrue() || input.Config.CompilerOptions().ExtendedDiagnostics.IsTrue() {
|
|
var memStats runtime.MemStats
|
|
// GC must be called twice to allow things to settle.
|
|
runtime.GC()
|
|
runtime.GC()
|
|
runtime.ReadMemStats(&memStats)
|
|
|
|
statistics = statisticsFromProgram(input, &memStats)
|
|
statistics.Report(input.Writer, input.Testing)
|
|
}
|
|
|
|
if result.EmitResult.EmitSkipped && len(result.Diagnostics) > 0 {
|
|
result.Status = ExitStatusDiagnosticsPresent_OutputsSkipped
|
|
} else if len(result.Diagnostics) > 0 {
|
|
result.Status = ExitStatusDiagnosticsPresent_OutputsGenerated
|
|
}
|
|
return result, statistics
|
|
}
|
|
|
|
func EmitFilesAndReportErrors(input EmitInput) (result CompileAndEmitResult) {
|
|
result.times = input.CompileTimes
|
|
ctx := context.Background()
|
|
|
|
allDiagnostics := compiler.GetDiagnosticsOfAnyProgram(
|
|
ctx,
|
|
input.ProgramLike,
|
|
nil,
|
|
false,
|
|
func(ctx context.Context, file *ast.SourceFile) []*ast.Diagnostic {
|
|
// Options diagnostics include global diagnostics (even though we collect them separately),
|
|
// and global diagnostics create checkers, which then bind all of the files. Do this binding
|
|
// early so we can track the time.
|
|
bindStart := input.Sys.Now()
|
|
diags := input.ProgramLike.GetBindDiagnostics(ctx, file)
|
|
result.times.bindTime = input.Sys.Now().Sub(bindStart)
|
|
return diags
|
|
},
|
|
func(ctx context.Context, file *ast.SourceFile) []*ast.Diagnostic {
|
|
checkStart := input.Sys.Now()
|
|
diags := input.ProgramLike.GetSemanticDiagnostics(ctx, file)
|
|
result.times.checkTime = input.Sys.Now().Sub(checkStart)
|
|
return diags
|
|
},
|
|
)
|
|
|
|
emitResult := &compiler.EmitResult{EmitSkipped: true, Diagnostics: []*ast.Diagnostic{}}
|
|
if !input.ProgramLike.Options().ListFilesOnly.IsTrue() {
|
|
emitStart := input.Sys.Now()
|
|
emitResult = input.ProgramLike.Emit(ctx, compiler.EmitOptions{
|
|
WriteFile: input.WriteFile,
|
|
})
|
|
result.times.emitTime = input.Sys.Now().Sub(emitStart)
|
|
}
|
|
if emitResult != nil {
|
|
allDiagnostics = append(allDiagnostics, emitResult.Diagnostics...)
|
|
}
|
|
if input.Testing != nil {
|
|
input.Testing.OnEmittedFiles(emitResult, input.TestingMTimesCache)
|
|
}
|
|
|
|
allDiagnostics = compiler.SortAndDeduplicateDiagnostics(allDiagnostics)
|
|
for _, diagnostic := range allDiagnostics {
|
|
input.ReportDiagnostic(diagnostic)
|
|
}
|
|
|
|
listFiles(input, emitResult)
|
|
|
|
input.ReportErrorSummary(allDiagnostics)
|
|
result.Diagnostics = allDiagnostics
|
|
result.EmitResult = emitResult
|
|
result.Status = ExitStatusSuccess
|
|
return result
|
|
}
|
|
|
|
func listFiles(input EmitInput, emitResult *compiler.EmitResult) {
|
|
if input.Testing != nil {
|
|
input.Testing.OnListFilesStart(input.Writer)
|
|
defer input.Testing.OnListFilesEnd(input.Writer)
|
|
}
|
|
options := input.Program.Options()
|
|
if options.ListEmittedFiles.IsTrue() {
|
|
for _, file := range emitResult.EmittedFiles {
|
|
fmt.Fprintln(input.Writer, "TSFILE: ", tspath.GetNormalizedAbsolutePath(file, input.Program.GetCurrentDirectory()))
|
|
}
|
|
}
|
|
if options.ExplainFiles.IsTrue() {
|
|
input.Program.ExplainFiles(input.Writer)
|
|
} else if options.ListFiles.IsTrue() || options.ListFilesOnly.IsTrue() {
|
|
for _, file := range input.Program.GetSourceFiles() {
|
|
fmt.Fprintln(input.Writer, file.FileName())
|
|
}
|
|
}
|
|
}
|