Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions skiplang/compiler/src/Config.sk
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ private class Config{
preambles: Array<String>,
canonize_paths: Bool,
cwd: WorkingDirectory,
batch_mode: Bool = false,
} {
static fun make(results: Cli.ParseResults): this {
optConfig = Optimize.Config::make(
Expand Down Expand Up @@ -279,6 +280,18 @@ private class Config{
fun isWasm(): Bool {
this.target.startsWith("wasm32");
}

fun withInputFiles(files: Array<String>): this {
this with {input_files => files}
}

fun withOutput(out: String): this {
this with {output => out}
}

fun withBatchMode(): this {
this with {batch_mode => true}
}
}

value class WorkingDirectory{
Expand Down
134 changes: 100 additions & 34 deletions skiplang/compiler/src/compile.sk
Original file line number Diff line number Diff line change
Expand Up @@ -135,22 +135,38 @@ fun link(
Array["-no-pie"]
};

runShell(
Array[
"clang++",
`-O${config.optLevel}`,
"-o",
config.output,
llFile,
].concat(flags)
.concat(linker_args)
.concat(static_libs),
config.verbose,
);
oFile = config.output + ".o";
runCompilerPhase("llvm", () -> {
runShell(
Array["clang++", `-O${config.optLevel}`, "-c", "-o", oFile, llFile],
config.verbose,
config.batch_mode,
)
});

runCompilerPhase("link", () -> {
runShell(
Array[
"clang++",
`-O${config.optLevel}`,
"-o",
config.output,
oFile,
].concat(flags)
.concat(linker_args)
.concat(static_libs),
config.verbose,
config.batch_mode,
)
});
}
}

fun runShell(args: Array<String>, verbose: Bool = false): void {
fun runShell(
args: Array<String>,
verbose: Bool = false,
batch_mode: Bool = false,
): void {
if (verbose) {
print_error(">> " + args.join(" "))
};
Expand All @@ -168,6 +184,12 @@ fun runShell(args: Array<String>, verbose: Bool = false): void {
},
).fromSuccess();
if (!p.success()) {
if (batch_mode) {
throw SkipError.CompileFailureException{
message => p.stderr,
exit_code => 1,
}
};
if (!verbose) {
print_error_raw(p.stderr)
};
Expand Down Expand Up @@ -237,12 +259,31 @@ fun getOrInitializeBackend(context: mutable SKStore.Context): SKStore.EagerDir {
context.getGlobal("ERRORS") match {
| None() -> void
| Some(errors) ->
SkipError.printErrorsAndExit(
SkipError.ErrorsFile::type(errors).value.reversed().toArray(),
file -> {
FileCache.fileDir.unsafeGetArray(context, file)[0].value
},
)
// Clear ERRORS to prevent leakage across batch compilations.
context.setGlobal("ERRORS", SkipError.ErrorsFile(List[]));
get_file = file -> {
FileCache.fileDir.unsafeGetArray(context, file)[0].value
};
if (conf.batch_mode) {
// In batch mode, store error message in a global instead of
// throwing — throwing from inside a reactive computation leaves
// the SKStore context in a broken state.
msg = SkipError.errorsToString(
SkipError.ErrorsFile::type(errors)
.value.reversed()
.map(x -> x.errors)
.flatten()
.collect(Vector),
get_file,
);
context.setGlobal("BATCH_ERROR_MSG", SKStore.StringFile(msg));
return void
} else {
SkipError.printErrorsAndExit(
SkipError.ErrorsFile::type(errors).value.reversed().toArray(),
get_file,
)
}
};

if (conf.check) {
Expand Down Expand Up @@ -291,16 +332,18 @@ fun getOrInitializeBackend(context: mutable SKStore.Context): SKStore.EagerDir {
)))
);

env = OuterIstToIR.createIR(
context,
conf,
shouldDisasm,
shouldRuntimeExport,
outerIst,
converter,
constsProj,
defsProj,
);
env = runCompilerPhase("frontend+ir", () -> {
OuterIstToIR.createIR(
context,
conf,
shouldDisasm,
shouldRuntimeExport,
outerIst,
converter,
constsProj,
defsProj,
)
});

!env = createOptimizedFunctions(context, env, conf);
defs = runCompilerPhase("native/create_asm_graph", () -> {
Expand Down Expand Up @@ -351,11 +394,23 @@ fun compile(
fileNames: Array<String>,
): void {
if (fileNames.isEmpty() && config.dependencies.isEmpty()) {
if (config.batch_mode) {
throw SkipError.CompileFailureException{
message => "fatal error: no input files",
exit_code => 4,
}
};
print_error("fatal error: no input files\n");
skipExit(4); // Exit code used by g++ for no input files
};

ensureCompatibleLLVMVersion();
if (!config.batch_mode) {
ensureCompatibleLLVMVersion()
};

if (config.batch_mode) {
SkipError.setBatchMode(context)
};

getOrInitializeBackend(context).writeArray(
context,
Expand All @@ -379,7 +434,20 @@ fun compile(
make_input_source_path,
);

context.update()
context.update();

// In batch mode, check if the backend mapper stored a deferred error.
if (config.batch_mode) {
context.getGlobal("BATCH_ERROR_MSG") match {
| Some(msgFile) ->
context.setGlobal("BATCH_ERROR_MSG", SKStore.StringFile(""));
msg = SKStore.StringFile::type(msgFile).value;
if (!msg.isEmpty()) {
throw SkipError.CompileFailureException{message => msg}
}
| None() -> void
}
}
}

fun compile_llvm_ir(
Expand All @@ -402,9 +470,7 @@ fun compile_binary(
AsmOutput.writeOutputFiles(defs, conf.input_files, llFile, conf)
});

runCompilerPhase("native/link", () -> {
link(llFile, conf, exports)
})
link(llFile, conf, exports)
}

fun compile_sklib(context: mutable SKStore.Context, conf: Config.Config): void {
Expand Down
9 changes: 6 additions & 3 deletions skiplang/compiler/src/main.sk
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

fun main(): void {
results = Cli.Command("skc")
fun skcCommand(): Cli.Command {
Cli.Command("skc")
.about("Skip compiler")
.help()
.arg(Cli.Arg::bool("disasm-all"))
Expand Down Expand Up @@ -88,7 +88,10 @@ fun main(): void {
),
)
.arg(Cli.Arg::string("files").positional().repeatable())
.parseArgs();
}

fun main(): void {
results = skcCommand().parseArgs();

results.error match {
| Some(exn) ->
Expand Down
56 changes: 47 additions & 9 deletions skiplang/compiler/src/skipError.sk
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,26 @@ fun printErrorsAndExit<T>(
skipExit(2)
}

class CompileFailureException{
message: String,
exit_code: Int = 2,
} extends Exception {
fun getMessage(): String {
this.message
}
}

fun printErrorsAndThrow<T>(
errors: Array<SkipErrorException>,
get_file: FileCache.InputSource -> String,
): T {
msg = errorsToString(
errors.map(x -> x.errors).flatten().collect(Vector),
get_file,
);
throw CompileFailureException{message => msg}
}

class ErrorsFile(value: List<SkipErrorException>) extends SKStore.File

fun keepErrors(
Expand All @@ -123,10 +143,15 @@ fun keepErrors(
}

fun catchErrors(
_phase: Int,
phase: Int,
context: mutable SKStore.Context,
f: () -> void,
): void {
// In batch mode, accumulate errors like keepErrors instead of exiting.
if (isBatchMode(context)) {
keepErrors(phase, context, f);
return void;
};
try {
f()
} catch {
Expand All @@ -140,6 +165,16 @@ fun catchErrors(
}
}

const kBatchModeGlobal: String = "BATCH_MODE";

fun setBatchMode(context: mutable SKStore.Context): void {
context.setGlobal(kBatchModeGlobal, ErrorsFile(List[]))
}

fun isBatchMode(context: mutable SKStore.Context): Bool {
context.getGlobal(kBatchModeGlobal).isSome()
}

fun doWithError<T>(f: () -> T): Result<T, Vector<Error>> {
try {
(Success(f()) : Result<T, Vector<SkipError.Error>>);
Expand Down Expand Up @@ -379,14 +414,17 @@ fun fatalError<T>(
msg: String,
fix: ?Fix = None(),
): T {
printErrorsAndExit(
Array[
SkipErrorException{
errors => Vector[Error{traces => List[(pos, msg)], fix}],
},
],
file -> FileCache.fileDir.unsafeGetArray(context, file)[0].value,
);
errors = Array[
SkipErrorException{
errors => Vector[Error{traces => List[(pos, msg)], fix}],
},
];
get_file = file -> FileCache.fileDir.unsafeGetArray(context, file)[0].value;
if (isBatchMode(context)) {
printErrorsAndThrow(errors, get_file)
} else {
printErrorsAndExit(errors, get_file)
};
}

fun errorl<T>(traces: List<(FileRange, String)>, fix: ?Fix = None()): T {
Expand Down
40 changes: 8 additions & 32 deletions skiplang/compiler/src/skipUtils.sk
Original file line number Diff line number Diff line change
Expand Up @@ -71,38 +71,14 @@ fun shouldDebugSymbol(_symbolName: String): Bool {
// value
// }

fun runCompilerPhase<T>(_phaseName: String, phase: () -> T): T {
// if (config.debug || config.profile) {
// reportMemoryStatistics(`${phaseName} start`);
// (elapsedTime, result) = timeOperation(phase);
// reportMemoryStatistics(`${phaseName} end`);
// print_error_ln(
// `Elapsed time (in ms) for phase ${phaseName}: ` + elapsedTime,
// );
// if (config.debug) {
// if (
// config.debugPhase.isNone() ||
// phaseName.contains(config.debugPhase.fromSome())
// ) {
// print_error_ln(`Results of pass: ${phaseName}`);
// debug(result);
// } else if (config.debugPhase.isSome()) {
// print_error_ln(
// `Not printing results of pass: ${phaseName} due to ` +
// `filter ${config.debugPhase.fromSome()}.`,
// );
// }
// };
// result;
//
// TODO: Add support for exiting after a phase.
// } else {
// config.profilePath match {
// | Some(dir) -> recordPhaseRuntime(dir, phaseName, phase)
// | None() -> phase()
// }
// }
phase()
fun runCompilerPhase<T>(phaseName: String, phase: () -> T): T {
start = Time.time_ms();
result = phase();
elapsed = Time.time_ms() - start;
if (Environ.varOpt("SKC_TIME_PHASES").isSome()) {
print_error(`##TIME## ${phaseName} ${elapsed}`)
};
result
}

/*
Expand Down
Loading