Skip to content

Commit 074d861

Browse files
authored
Kaleidoscope Chapter 5 docs (#56)
1 parent 837f7cc commit 074d861

File tree

5 files changed

+224
-34
lines changed

5 files changed

+224
-34
lines changed

Samples/Kaleidoscope/Chapter5/CodeGenerator.cs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,19 @@ internal sealed class CodeGenerator
2929
, IDisposable
3030
, IKaleidoscopeCodeGenerator<Value>
3131
{
32+
// <Initialization>
3233
public CodeGenerator( DynamicRuntimeState globalState )
3334
{
3435
RuntimeState = globalState;
3536
Context = new Context( );
37+
JIT = new KaleidoscopeJIT( );
3638
InitializeModuleAndPassManager( );
3739
InstructionBuilder = new InstructionBuilder( Context );
38-
JIT = new KaleidoscopeJIT( );
3940
FunctionPrototypes = new PrototypeCollection( );
4041
FunctionModuleMap = new Dictionary<string, IJitModuleHandle>( );
4142
NamedValues = new ScopeStack<Value>( );
4243
}
44+
// </Initialization>
4345

4446
public bool DisableOptimizations { get; set; }
4547

@@ -82,7 +84,7 @@ public override Value VisitVariableExpression( [NotNull] VariableExpressionConte
8284

8385
public override Value VisitFunctionCallExpression( [NotNull] FunctionCallExpressionContext context )
8486
{
85-
var function = GetFunction( context.CaleeName );
87+
var function = FindCallTarget( context.CaleeName );
8688
if( function == null )
8789
{
8890
throw new CodeGeneratorException( $"function '{context.CaleeName}' is unknown" );
@@ -102,13 +104,16 @@ public override Value VisitFunctionPrototype( [NotNull] FunctionPrototypeContext
102104
return GetOrDeclareFunction( new Prototype( context ) );
103105
}
104106

107+
// <VisitFunctionDefinition>
105108
public override Value VisitFunctionDefinition( [NotNull] FunctionDefinitionContext context )
106109
{
107110
return DefineFunction( ( Function )context.Signature.Accept( this )
108111
, context.BodyExpression
109112
).Function;
110113
}
114+
// </VisitFunctionDefinition>
111115

116+
// <VisitTopLevelExpression>
112117
public override Value VisitTopLevelExpression( [NotNull] TopLevelExpressionContext context )
113118
{
114119
var proto = new Prototype( $"anon_expr_{AnonNameIndex++}" );
@@ -118,9 +123,11 @@ public override Value VisitTopLevelExpression( [NotNull] TopLevelExpressionConte
118123

119124
var nativeFunc = JIT.GetDelegateForFunction<AnonExpressionFunc>( proto.Identifier.Name );
120125
var retVal = Context.CreateConstant( nativeFunc( ) );
126+
FunctionModuleMap.Remove( function.Name );
121127
JIT.RemoveModule( jitHandle );
122128
return retVal;
123129
}
130+
// </VisitTopLevelExpression>
124131

125132
public override Value VisitExpression( [NotNull] ExpressionContext context )
126133
{
@@ -135,6 +142,7 @@ public override Value VisitExpression( [NotNull] ExpressionContext context )
135142
return lhs;
136143
}
137144

145+
// <VisitConditionalExpression>
138146
public override Value VisitConditionalExpression( [NotNull] ConditionalExpressionContext context )
139147
{
140148
var condition = context.Condition.Accept( this );
@@ -163,7 +171,7 @@ public override Value VisitConditionalExpression( [NotNull] ConditionalExpressio
163171

164172
InstructionBuilder.Branch( phiMergeBlock );
165173

166-
// capture the insert in case generating thenExpression adds new blocks
174+
// capture the insert in case generating else adds new blocks
167175
thenBlock = InstructionBuilder.InsertBlock;
168176

169177
// generate else block
@@ -188,24 +196,9 @@ public override Value VisitConditionalExpression( [NotNull] ConditionalExpressio
188196
phiNode.AddIncoming( elseValue, elseBlock );
189197
return phiNode;
190198
}
199+
// </VisitConditionalExpression>
191200

192-
/*
193-
// Output for-loop as:
194-
// ...
195-
// start = startexpr
196-
// goto loop
197-
// loop:
198-
// variable = phi [start, loopheader], [nextvariable, loopend]
199-
// ...
200-
// bodyexpr
201-
// ...
202-
// loopend:
203-
// step = stepexpr
204-
// nextvariable = variable + step
205-
// endcond = endexpr
206-
// br endcond, loop, endloop
207-
// outloop:
208-
*/
201+
// <VisitForExpression>
209202
public override Value VisitForExpression( [NotNull] ForExpressionContext context )
210203
{
211204
var function = InstructionBuilder.InsertBlock.ContainingFunction;
@@ -297,6 +290,7 @@ public override Value VisitForExpression( [NotNull] ForExpressionContext context
297290
return Context.DoubleType.GetNullValue( );
298291
}
299292
}
293+
// </VisitForExpression>
300294

301295
protected override Value DefaultResult => null;
302296

@@ -342,19 +336,25 @@ private Value EmitBinaryOperator( Value lhs, BinaryopContext op, IParseTree righ
342336
}
343337
}
344338

339+
// <InitializeModuleAndPassManager>
345340
private void InitializeModuleAndPassManager( )
346341
{
347342
Module = Context.CreateBitcodeModule( );
343+
Module.Layout = JIT.TargetMachine.TargetData;
348344
FunctionPassManager = new FunctionPassManager( Module );
349345
FunctionPassManager.AddInstructionCombiningPass( )
350346
.AddReassociatePass( )
351347
.AddGVNPass( )
352348
.AddCFGSimplificationPass( )
353349
.Initialize( );
354350
}
351+
// </InitializeModuleAndPassManager>
355352

356-
private Function GetFunction( string name )
353+
// <FindCallTarget>
354+
private Function FindCallTarget( string name )
357355
{
356+
// lookup the prototype for the function to get the signature
357+
// and create a declaration in this module
358358
if( FunctionPrototypes.TryGetValue( name, out var signature ) )
359359
{
360360
return GetOrDeclareFunction( signature );
@@ -368,7 +368,9 @@ private Function GetFunction( string name )
368368

369369
return null;
370370
}
371+
// </FindCallTarget>
371372

373+
// <GetOrDeclareFunction>
372374
private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = false )
373375
{
374376
var function = Module.GetFunction( prototype.Identifier.Name );
@@ -396,7 +398,9 @@ private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = f
396398

397399
return retVal;
398400
}
401+
// </GetOrDeclareFunction>
399402

403+
// <DefineFunction>
400404
private (Function Function, IJitModuleHandle JitHandle) DefineFunction( Function function, ExpressionContext body )
401405
{
402406
if( !function.IsDeclaration )
@@ -409,7 +413,7 @@ private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = f
409413
// implementation. This is needed, otherwise both the MCJIT
410414
// and OrcJit engines will resolve to the original module, despite
411415
// claims to the contrary in the official tutorial text. (Though,
412-
// to be fare it may have been true in the original JIT and might
416+
// to be fair it may have been true in the original JIT and might
413417
// still be true for the interpreter)
414418
if( FunctionModuleMap.Remove( function.Name, out IJitModuleHandle handle ) )
415419
{
@@ -446,6 +450,7 @@ private Function GetOrDeclareFunction( Prototype prototype, bool isAnonymous = f
446450
InitializeModuleAndPassManager( );
447451
return (function, jitHandle);
448452
}
453+
// </DefineFunction>
449454

450455
// <PrivateMembers>
451456
private readonly DynamicRuntimeState RuntimeState;

Samples/Kaleidoscope/Chapter5/Program.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
[assembly: SuppressMessage( "StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Sample application" )]
1616

17+
#pragma warning disable SA1512, SA1513, SA1515 // single line comments used to tag regions for extraction into docs
18+
1719
namespace Kaleidoscope
1820
{
1921
public static class Program
@@ -35,6 +37,8 @@ public static void Main( string[ ] args )
3537
using( InitializeLLVM( ) )
3638
{
3739
RegisterNative( );
40+
41+
// <generatorloop>
3842
var parser = new ReplParserStack( LanguageLevel.ControlFlow );
3943
using( var generator = new CodeGenerator( parser.GlobalState ) )
4044
{
@@ -43,12 +47,31 @@ public static void Main( string[ ] args )
4347
var replLoop = new ReplLoop<Value>( generator, parser );
4448
replLoop.ReadyStateChanged += ( s, e ) => Console.Write( e.PartialParse ? ">" : "Ready>" );
4549
replLoop.GeneratedResultAvailable += OnGeneratedResultAvailable;
50+
replLoop.CodeGenerationError += OnGeneratorError;
4651

4752
replLoop.Run( );
4853
}
54+
// </generatorloop>
55+
}
56+
}
57+
58+
// <ErrorHandling>
59+
private static void OnGeneratorError( object sender, CodeGenerationExceptionArgs e )
60+
{
61+
var color = Console.ForegroundColor;
62+
Console.ForegroundColor = ConsoleColor.Red;
63+
try
64+
{
65+
Console.Error.WriteLine( e.Exception.Message );
66+
}
67+
finally
68+
{
69+
Console.ForegroundColor = color;
4970
}
5071
}
72+
// </ErrorHandling>
5173

74+
// <ResultProcessing>
5275
private static void OnGeneratedResultAvailable( object sender, GeneratedResultAvailableArgs<Value> e )
5376
{
5477
var source = ( ReplLoop<Value> )sender;
@@ -69,5 +92,6 @@ private static void OnGeneratedResultAvailable( object sender, GeneratedResultAv
6992
break;
7093
}
7194
}
95+
// </ResultProcessing>
7296
}
7397
}

Samples/Kaleidoscope/Kaleidoscope.Runtime/ScopeStack.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Kaleidoscope.Runtime
1515
/// <remarks>
1616
/// In essence, this is a stack of Dictionaries that is intended for use in code generation.
1717
/// Most languages have some sort of notion of symbol scopes and name lookups. This implements
18-
/// the common case of nested scopes where a new 'local scope may override some of the symbols
18+
/// the common case of nested scopes where a new 'local scope' may override some of the symbols
1919
/// in a parent scope. Any values in any parent not overridden by the child are visible to the
2020
/// child scope.
2121
/// </remarks>

docfx/articles/Samples/Kaleidoscope-ch2.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ binaryop
211211
;
212212
```
213213

214-
##### Initializers
214+
### Initializers
215215
Initializers are a useful re-usable rule to handle a common sequence in the language in multiple different contexts.
216216
(sort of like a function in most programming languages, in fact, ANTLR rules are implemented in the generated parser
217217
as methods).
@@ -225,7 +225,7 @@ initializer
225225
226226
```
227227

228-
##### Primary Expressions (Atoms)
228+
### Primary Expressions (Atoms)
229229
There are a number of primary expressions (also known as 'Atoms') that are not left recursive in their definition.
230230
These are split out to a distinct rule to aid in the support of left recursion and the need for user defined operator
231231
precedence.
@@ -246,7 +246,7 @@ primaryExpression
246246

247247
Let's look at each of these in turn to get a better understanding of the language.
248248

249-
###### ParenExpression
249+
### ParenExpression
250250
```antlr
251251
LPAREN expression[0] RPAREN
252252
```
@@ -256,7 +256,7 @@ tree for that expression looks like this:
256256

257257
![Parse Tree](parsetree-paren-expr.svg)
258258

259-
###### FunctionCallExpression
259+
### FunctionCallExpression
260260
```antlr
261261
Identifier LPAREN (expression[0] (COMMA expression[0])*)? RPAREN
262262
```
@@ -265,7 +265,7 @@ for the call `foo(1, 2, 3);` is:
265265

266266
![Parse Tree](parsetree-func-call.svg)
267267

268-
###### VarInExpression
268+
### VarInExpression
269269
```antlr
270270
VAR initializer (COMMA initializer)* IN expression[0]
271271
```
@@ -274,7 +274,7 @@ variables is that of the expression on the right of the `in` keyword. The `var .
274274
in many ways like a declaration of an inline function. The variables declared are scoped to the internal
275275
implementation of the function. Once the function produces the return value the variables no longer exist.
276276

277-
###### ConditionalExpression
277+
### ConditionalExpression
278278
```antlr
279279
IF expression[0] THEN expression[0] ELSE expression[0]
280280
```
@@ -296,7 +296,7 @@ def fib(x)
296296
else
297297
fib(x-1)+fib(x-2);
298298
```
299-
##### ForInExpression
299+
### ForInExpression
300300
The ForInExpression provides support for classic for loop constructs. In particular it provides a variable scope for a loop
301301
value, a condition to test when to exit the loop and an optional step value for incrementing the loop value (default is 1.0).
302302

0 commit comments

Comments
 (0)