|  | # Chapter 1: Toy Language and AST | 
|  |  | 
|  | [TOC] | 
|  |  | 
|  | ## The Language | 
|  |  | 
|  | This tutorial will be illustrated with a toy language that we’ll call “Toy” | 
|  | (naming is hard...). Toy is a tensor-based language that allows you to define | 
|  | functions, perform some math computation, and print results. | 
|  |  | 
|  | Given that we want to keep things simple, the codegen will be limited to tensors | 
|  | of rank <= 2, and the only datatype in Toy is a 64-bit floating point type (aka | 
|  | ‘double’ in C parlance). As such, all values are implicitly double precision, | 
|  | `Values` are immutable (i.e. every operation returns a newly allocated value), | 
|  | and deallocation is automatically managed. But enough with the long description; | 
|  | nothing is better than walking through an example to get a better understanding: | 
|  |  | 
|  | ```toy | 
|  | def main() { | 
|  | # Define a variable `a` with shape <2, 3>, initialized with the literal value. | 
|  | # The shape is inferred from the supplied literal. | 
|  | var a = [[1, 2, 3], [4, 5, 6]]; | 
|  |  | 
|  | # b is identical to a, the literal tensor is implicitly reshaped: defining new | 
|  | # variables is the way to reshape tensors (element count must match). | 
|  | var b<2, 3> = [1, 2, 3, 4, 5, 6]; | 
|  |  | 
|  | # transpose() and print() are the only builtin, the following will transpose | 
|  | # a and b and perform an element-wise multiplication before printing the result. | 
|  | print(transpose(a) * transpose(b)); | 
|  | } | 
|  | ``` | 
|  |  | 
|  | Type checking is statically performed through type inference; the language only | 
|  | requires type declarations to specify tensor shapes when needed. Functions are | 
|  | generic: their parameters are unranked (in other words, we know these are | 
|  | tensors, but we don't know their dimensions). They are specialized for every | 
|  | newly discovered signature at call sites. Let's revisit the previous example by | 
|  | adding a user-defined function: | 
|  |  | 
|  | ```toy | 
|  | # User defined generic function that operates on unknown shaped arguments. | 
|  | def multiply_transpose(a, b) { | 
|  | return transpose(a) * transpose(b); | 
|  | } | 
|  |  | 
|  | def main() { | 
|  | # Define a variable `a` with shape <2, 3>, initialized with the literal value. | 
|  | var a = [[1, 2, 3], [4, 5, 6]]; | 
|  | var b<2, 3> = [1, 2, 3, 4, 5, 6]; | 
|  |  | 
|  | # This call will specialize `multiply_transpose` with <2, 3> for both | 
|  | # arguments and deduce a return type of <3, 2> in initialization of `c`. | 
|  | var c = multiply_transpose(a, b); | 
|  |  | 
|  | # A second call to `multiply_transpose` with <2, 3> for both arguments will | 
|  | # reuse the previously specialized and inferred version and return <3, 2>. | 
|  | var d = multiply_transpose(b, a); | 
|  |  | 
|  | # A new call with <3, 2> (instead of <2, 3>) for both dimensions will | 
|  | # trigger another specialization of `multiply_transpose`. | 
|  | var e = multiply_transpose(c, d); | 
|  |  | 
|  | # Finally, calling into `multiply_transpose` with incompatible shapes | 
|  | # (<2, 3> and <3, 2>) will trigger a shape inference error. | 
|  | var f = multiply_transpose(a, c); | 
|  | } | 
|  | ``` | 
|  |  | 
|  | ## The AST | 
|  |  | 
|  | The AST from the above code is fairly straightforward; here is a dump of it: | 
|  |  | 
|  | ``` | 
|  | Module: | 
|  | Function | 
|  | Proto 'multiply_transpose' @test/Examples/Toy/Ch1/ast.toy:4:1 | 
|  | Params: [a, b] | 
|  | Block { | 
|  | Return | 
|  | BinOp: * @test/Examples/Toy/Ch1/ast.toy:5:25 | 
|  | Call 'transpose' [ @test/Examples/Toy/Ch1/ast.toy:5:10 | 
|  | var: a @test/Examples/Toy/Ch1/ast.toy:5:20 | 
|  | ] | 
|  | Call 'transpose' [ @test/Examples/Toy/Ch1/ast.toy:5:25 | 
|  | var: b @test/Examples/Toy/Ch1/ast.toy:5:35 | 
|  | ] | 
|  | } // Block | 
|  | Function | 
|  | Proto 'main' @test/Examples/Toy/Ch1/ast.toy:8:1 | 
|  | Params: [] | 
|  | Block { | 
|  | VarDecl a<> @test/Examples/Toy/Ch1/ast.toy:11:3 | 
|  | Literal: <2, 3>[ <3>[ 1.000000e+00, 2.000000e+00, 3.000000e+00], <3>[ 4.000000e+00, 5.000000e+00, 6.000000e+00]] @test/Examples/Toy/Ch1/ast.toy:11:11 | 
|  | VarDecl b<2, 3> @test/Examples/Toy/Ch1/ast.toy:15:3 | 
|  | Literal: <6>[ 1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00] @test/Examples/Toy/Ch1/ast.toy:15:17 | 
|  | VarDecl c<> @test/Examples/Toy/Ch1/ast.toy:19:3 | 
|  | Call 'multiply_transpose' [ @test/Examples/Toy/Ch1/ast.toy:19:11 | 
|  | var: a @test/Examples/Toy/Ch1/ast.toy:19:30 | 
|  | var: b @test/Examples/Toy/Ch1/ast.toy:19:33 | 
|  | ] | 
|  | VarDecl d<> @test/Examples/Toy/Ch1/ast.toy:22:3 | 
|  | Call 'multiply_transpose' [ @test/Examples/Toy/Ch1/ast.toy:22:11 | 
|  | var: b @test/Examples/Toy/Ch1/ast.toy:22:30 | 
|  | var: a @test/Examples/Toy/Ch1/ast.toy:22:33 | 
|  | ] | 
|  | VarDecl e<> @test/Examples/Toy/Ch1/ast.toy:25:3 | 
|  | Call 'multiply_transpose' [ @test/Examples/Toy/Ch1/ast.toy:25:11 | 
|  | var: c @test/Examples/Toy/Ch1/ast.toy:25:30 | 
|  | var: d @test/Examples/Toy/Ch1/ast.toy:25:33 | 
|  | ] | 
|  | VarDecl f<> @test/Examples/Toy/Ch1/ast.toy:28:3 | 
|  | Call 'multiply_transpose' [ @test/Examples/Toy/Ch1/ast.toy:28:11 | 
|  | var: a @test/Examples/Toy/Ch1/ast.toy:28:30 | 
|  | var: c @test/Examples/Toy/Ch1/ast.toy:28:33 | 
|  | ] | 
|  | } // Block | 
|  | ``` | 
|  |  | 
|  | You can reproduce this result and play with the example in the | 
|  | `examples/toy/Ch1/` directory; try running `path/to/BUILD/bin/toyc-ch1 | 
|  | test/Examples/Toy/Ch1/ast.toy -emit=ast`. | 
|  |  | 
|  | The code for the lexer is fairly straightforward; it is all in a single header: | 
|  | `examples/toy/Ch1/include/toy/Lexer.h`. The parser can be found in | 
|  | `examples/toy/Ch1/include/toy/Parser.h`; it is a recursive descent parser. If | 
|  | you are not familiar with such a Lexer/Parser, these are very similar to the | 
|  | LLVM Kaleidoscope equivalent that are detailed in the first two chapters of the | 
|  | [Kaleidoscope Tutorial](https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html). | 
|  |  | 
|  | The [next chapter](Ch-2.md) will demonstrate how to convert this AST into MLIR. |