Normative compiler contract: phases, lowering model, outputs, and recommended host interfaces.
Implementation (partial): RoboSharpCompiler.Compile (parse → bind → lower), IlLowerer, RoboExecutable. Opcode names in code are RoboSharp.IL.RoboOpcode (e.g. PushInt rather than a separate PushConstant id pool in v1).
Related: compilation-pipeline, syntax-to-il-lowering, il-generation, pipeline boundaries.
The compiler turns one RoboSharp project into:
- diagnostics
- inspectable intermediate artifacts
- a compiled
.roboexe
The compiler must be:
- deterministic
- phase-based
- inspectable
- explicit about failure boundaries
The compiler does not execute code. It only transforms source into validated executable form.
The compiler pipeline is:
Project Load
→ Source Load
→ Lexing
→ Parsing
→ Syntax Tree
→ Symbol Collection
→ Semantic Analysis / Binding
→ Bound Program
→ Lowering to IL
→ Executable Packaging
→ Artifact Emission
This refines the already-established source → syntax → semantic → IL pipeline into concrete compiler stages.
Input:
.robosharpproject file- referenced
.robosource files - active builtin profile name
- optional world metadata path
Output:
- resolved project model
- absolute/normalized source file list
- build settings
Failure conditions:
- invalid project format
- missing startup file
- missing source file
- unsupported project version
Compilation stops here on failure.
Each .robo source file is lexed independently.
Output:
- token stream
- trivia if preserved
- lexical diagnostics
Lexing must continue after bad tokens where possible.
Lexing never resolves meaning.
Each source file is parsed into syntax.
Output:
CompilationUnitSyntax- parse diagnostics
The parser must recover and continue so downstream tools can still inspect syntax trees. That matches the earlier parser direction.
Before full semantic binding, the compiler collects global declarations:
- user-defined function names
- function signatures
- source locations of declarations
This phase also imports built-ins from the active builtin profile into the global function space. Profile-based builtin availability was already established earlier.
Rules:
- no overloads in v1
- no duplicate function names
- no shadowing built-in names
- function declarations are global only
If symbol collection has errors, semantic analysis may continue, but IL generation must not proceed.
Binding transforms syntax into a typed, symbol-resolved bound form.
Output:
SemanticModelBoundProgram- semantic diagnostics
Binding rules follow the already-defined symbol, scope, and type model:
- lexical scopes
- bound expressions/statements
- builtin resolution
- array typing
- return validation
- assignment legality
Compilation may continue through this phase to gather diagnostics, but IL generation only proceeds if there are no errors.
This is the first missing major spec.
Input:
- fully valid
BoundProgram
Output:
- constant pool
- compiled function table
- instruction list
- debug mapping metadata
Lowering is deterministic and must not perform additional type reasoning beyond what semantic analysis already established.
- assign function ids
- assign local slots
- assign a single compiled function that holds top-level statements (implementation name:
TopLevel) - emit instructions in execution order
- generate branch targets / labels
- produce instruction-to-source mapping
- produce local-slot-to-name debug metadata
Top-level statements lower into one compiled function so the runtime has a normal call frame to start from. The stable implementation name for that function is TopLevel; hosts and learner-facing text should describe it as top-level statements or program entry, not as a user-defined procedure.
A valid program must contain at least one top-level statement. The name main is not a user entry point; declaring main is a semantic error.
Each compiled function gets contiguous local slots.
Rule:
- parameters occupy the first slots in declaration order
- local variables occupy subsequent slots in declaration order of first appearance in bound form
Example:
integer add(integer a, integer b)
{
integer c = a + b
return c
}
Lowered slot layout:
slot 0 = a
slot 1 = b
slot 2 = c
No slot reuse in v1.
That keeps debug behavior simple.
Literal values used in IL are interned into a project-level constant pool.
Allowed constant kinds:
- integer
- number
- string
- bool
Duplicate constants may be deduplicated, but this is optional in v1.
5
→
PushConstant { constantId = ... }
x
→
LoadLocal { slot = x }
x = expr
→
...expr...
StoreLocal { slot = x }
a + b
→
...a...
...b...
Add
move()
→
CallBuiltin { builtinId = Move }
add(1, 2)
→
PushConstant 1
PushConstant 2
Call { functionId = add }
[1, 2, 3]
→
NewArray { elementType = integer }
PushConstant 1
ArrayAdd
PushConstant 2
ArrayAdd
PushConstant 3
ArrayAdd
values[0]
→
LoadLocal values
PushConstant 0
ArrayGet
values[1] = 42
→
LoadLocal values
PushConstant 1
PushConstant 42
ArraySet
integer x = 5
→
PushConstant 5
StoreLocal x
print(x)
→
LoadLocal x
CallBuiltin Print
if (cond) thenStmt else elseStmt
→
...cond...
JumpIfFalse elseLabel
...then...
Jump endLabel
elseLabel:
...else...
endLabel:
while (cond) body
→
loopStart:
...cond...
JumpIfFalse loopEnd
...body...
Jump loopStart
loopEnd:
return expr
→
...expr...
Return
For no-value return in the top-level entry function (TopLevel), emit Return with no required stack value.
Successful compilation produces:
.roboexe- optionally
.roboast.json - optionally
.robobind.json - optionally
.roboil.json - optionally
.robo.pdb.json
That output model is already aligned with the file-format direction.
IL generation and packaging must not run if any diagnostic with severity Error exists after semantic analysis.
Warnings may still allow build success.
Recommended shape:
public interface IProjectCompiler
{
ValueTask<CompilationResult> CompileAsync(
RoboSharpProject project,
CancellationToken cancellationToken = default);
}public sealed record CompilationResult(
bool Success,
IReadOnlyList<Diagnostic> Diagnostics,
CompilationArtifacts? Artifacts);public sealed record CompilationArtifacts(
RoboExecutable Executable,
SyntaxArtifactCollection SyntaxArtifacts,
BoundArtifact? BoundArtifact,
IlArtifact? IlArtifact,
RoboDebugSymbols? DebugSymbols);