# FizzBuzz ## The Prelude String Now that we have our `fizzbuzz.tms` file we can create our first program. Start by adding a prelude sting to the top of your file. ```swift "My FizzBuzz Program" ``` This string is required at the top of every `tms` file. It must come before everything other than comments. You can define strings using backticks, single quotes, or double quotes like seen below. ```js 'Single Quote String' "Double Quote String" `Backtick String` ``` > There is no requirements on what can be in the prelude string; it can even be an empty string, but it is suggested that the prelude string should begin with the name of your program on the first line with information on the time of creation, if applicable, on the second line preceded by `Created`. Any other important information should be placed on the following lines. Here is an example of a good prelude string: ```swift " My FizzBuzz Program Created Fri Sep 6, 2024 FizzbBuzz test program created for practice. - No command line arguments - No dependencies " ``` ## Comments Before we go any further it would be wise to take a detour and look at comments. Code comments are simply lines that are ignored when running the program. In termslang we defign comments using the pound or number symbol: `#`. Here is a quick example of how to create a comment: ```py # This comment is above the prelude string # The program works anyway "My Comment Test" # This comment is after # The program still works ``` > Although comments are important for clarification, it is not suggested to use them abundantly, or more accurately redundantly. Your code should be self documenting by use of intuitive function, struct, and variable names. If you need further clarification from there, then a comment may be warrented. There is one exception to this guideline: equations and algorithms. Writing an equation formula or an explination in comment at the start of a function is concidered good practice in TermsLang. ## @main Function Now that we have our prelude string we can create our program entry. The entry point for any TermsLang program is the `@main` function. To defign a function you use the following format: ```swift func RETURN_TYPE NAME: ARGS { } ``` For our `@main` function, we do not want to return anyting, so our return type will be `null`. This function must also take one argument: a list of strings that we are going to call `args`. That is defined as follows: `str[] args`. Our entry function will look like this: ```swift func null @main: str[] args { } ``` ## Println Now that we have our program entry, let us get a hello world program running. To print to the terminal we use the `println` keyword. `println` expects a single string to be provided. If you want to print something other than a string you must first convert it to a string. Here is how to use the `println` keyword: ```go println "Hello World" ~ ``` Note that the line is ended with a tilde `~`. A tilde denotes the end of a line. It is required for the program to run. If the tilde is not found the program will fail. > The space between the end of the line content and the tilde is not required but is suggested. The autoformatter will insert this if it is non existant. Now let us put our `println` line into our `@main` function. Your code should now look like this: ```swift " My FizzBuzz Program Created Fri Sep 6, 2024 FizzbBuzz test program created for practice. - No command line arguments - No dependencies " func null @main: str[] args { println "Hello World" ~ } ``` You can run this code using termslang: ``` termslang fizzbuzz.tms ``` You should get the following result: ``` Hello World ``` ## Structs Now we can create our first `struct`. To create a struct we use the `struct` keyword followed by the struct name and curly brackets. Here is an example: ```swift struct FizzBuzz {} ``` Inside of our struct we want a field of type `int` called `iters`. We can create this using the let keyword. ```swift struct FizzBuzz { let int iters ~ } ``` ## Methods & Constructors We also want a constructor for our struct. Our constructor will be a method with the name `@new` and a return type of `null`. It should take one `int` argument named `iters` that we will use to initialize our field. ```swift struct FizzBuzz { let int iters ~ func null @new: int iters { } } ``` To initialize the `iters` field using the argument we need to access the field using the `@this` variable. This variable is automatically defined in all struct methods. ```swift func null @new: int iters { updt @this.iters = iters ~ } ``` For now do not worry about the `updt` keyword in front of the variable. We will talk about this later. Note if we do not initialize a struct field it will automatically take on the `null` value. Now we can create the method to run the fizzbuzz program. It should be a method of the `FizzBuzz` struct and take two arguments, `_3Word` & `_5Word`, both of type `str`. The function should return the number of iterations we ran; therefore, the return type will be `int`. Our struct should now look like this: ```swift struct FizzBuzz { let int iters ~ func null @new: int iters { @this.iters = iters ~ } func int run: str _3Word, str _5Word { } } ``` ## Loops To get our run function to work we first need to create a loop. All loops in TermsLang are created using the `loop` keyword. This is followed by a counter variable name then a loop conditional. In this situation we are going to name our counter variable `idx`. `idx` will automaticly be of type `int`. ```rust func int run: str _3Word, str _5Word { loop idx: idx < @this.iters { } } ``` This creates a loop that will increment `idx` while `idx < @this.iters`. This loop is comparable to a for loop in many other languages. A while loop is created in the same manor. ## Variables The first thing we want to do in our loop is create our `result` variable to create a variable we use the `let` keyword followed by a type, name, and value. Our result variable should have the type `str`. Our variable declaration should look like this: ```rust let str result = "" ~ ``` Because we want our FizzBuzz program to start counting at one and not zero, we also want to redefine `idx` as `idx + 1`. Note that we are **NOT** updating `idx` because this would affect our loop conditional. The redefinition should look like this: ```rust let int idx = idx + 1 ~ ``` Our run function should now look like this: ```rust func int run: str _3Word, str _5Word { loop idx: idx < @this.iters { let str result = "" ~ let int idx = idx + 1 ~ } } ``` ## Conditionals Now we need to add the conditionals to our loop. To create a conditional we use the `if`, `else`, & `else if` keywords. Our first conditional needs to check if `idx` is evenly divisable by three. To do this we should use a modulo equality. The equality would be as follows: ``` idx modulo 3 = 0 ``` In TermsLang, and most other programming languages, modulo is expressed as a percent sign, `%`, and equality is expressed as double equal signs, `==` Therefore our equality would be expressed as follows: ```js idx % 3 == 0 ~ ``` We can use the modulo operator to create our first two conditionals. ```rust loop idx: idx < @this.iters { let str result = "" ~ let int idx = idx + 1 ~ if idx % 3 == 0 { } if idx % 5 == 0 { } } ``` Our last conditional should check if our result is an empty string, `""`. ```rust loop idx: idx < @this.iters { let str result = "" ~ let int idx = idx + 1 ~ if idx % 3 == 0 { } if idx % 5 == 0 { } if result == "" { } } ``` ## Updating Variables Inside each of our conditionals we need to update the `result` variable. When updating a variable we use the `updt` keyword. The `updt` keyword tells the parser that we want to change the value of the variable and not overwrite it. For our first two conditionals, we want to set `result` to the values of `_3Word` and `_5Word` respectively. ```rust if idx % 3 == 0 { updt result += _3Word ~ } if idx % 5 == 0 { updt result += _5Word ~ } ``` ## Calling Methods For our last conditional, we want want to set the value of `result` to the value of `idx`. Because `idx` is of type `int` and result is of type `str` we want to convert `idx` into a string before setting `result` to `idx`. We can convert an integer to a string using the `@str` method. To call a method we start by accessing the method using dot notation; in this case `idx.@str`. Next we use a dot followed by parethesis to call it, `.()`. Our last conditional should look like this: ```swift if result == "" { updt result += idx.@str.() ~ } ``` After our last conditional we can print the result variable using the `println` keyword. At this point our code should be as follows: ```swift struct FizzBuzz { let int iters ~ func null @new: int iters { @this.iters = iters ~ } func int run: str _3Word, str _5Word { loop idx: idx < @this.iters { let str result = "" ~ let int idx = idx + 1 ~ if idx % 3 == 0 { updt result += _3Word ~ } if idx % 5 == 0 { updt result += _5Word ~ } if result == "" { updt result += idx.@str.() ~ } println result ~ } } } ``` ## Returning From a Function Currently our function expects us to return an integer. To return a value from a function we use the `return` keyword followed by what we would like to return. in our case we would like to return the number of iterations run. The number of iterations is stored in the `iters` field of our `FizzBuzz` struct. To return the iterations we would write this line: ```swift return @this.iters ~ ``` We can append this to the end of our run function. ```swift func int run: str _3Word, str _5Word { loop idx: idx < @this.iters { let str result = "" ~ let int idx = idx + 1 ~ if idx % 3 == 0 { updt result += _3Word ~ } if idx % 5 == 0 { updt result += _5Word ~ } if result == "" { updt result += idx.@str.() ~ } println result ~ } return @this.iters ~ } ``` ## Creating an Instance Now that our `FizzBuzz` struct is complete, we need to make it so it runs. We first need an instance of `FizzBuzz`. To create an instance we use the dollar sign, `$`, followed by parenthesis then the type. In our case: `$() FizzBuzz`. We are going to name our instance of `FizzBuzz` `fizzy`. ```swift func null @main: str[] args { println "Hello World" ~ let FizzBuzz fizzy = $() FizzBuzz ~ } ``` If you remember, the constructor for `FizzBuzz` takes in one integer object, `iters`. We are going to set `iters` to `20`. We can pass this into the parenthesis. ```swift func null @main: str[] args { println "Hello World" ~ let FizzBuzz fizzy = $(20) FizzBuzz ~ } ``` > A space between the `$` and parenthesis is allowed but should be avoided as it is not suggested. We can then call the `run` function, passing `"Fizz"` and `Buzz` as arguments, capturing the return in a variable `iters`. ```swift func null @main: str[] args { println "Hello World" ~ let FizzBuzz fizzy = $(20) FizzBuzz ~ let int iters = fizzy.run.("Fizz", "Buzz") ~ } ``` ## String % Interpolation We want one more method, `printResults`, to print a final message to the terminal. We will create this method above the `@main` function. It should take in one `int`, `iters`, and have a return type of `null`. ```swift func null printResults: int iters { } ``` Inside this method we will print the number of iterations in a message. To do this we can use a special notation with strings. ```go println "FizzBuzz Program Complete %/% iterations run." % iters.@str.() ~ ``` This will replace any instance of `%` in the string with `iters.@str.()`. So our `printResults` method should look like this: ```go func null printResults: int iters { println "FizzBuzz Program Complete %/% iterations run." % iters.@str.() ~ } ``` ## Calling Methods Without Capture We now want to call this method from the `@main` function, but we do not need to capture the `null` result. To call a function without capturing the return value we use the `cll` keyword followed by our function call. We want to pass the variable `iters` into our function call. ``` cll printResults.(iters) ~ ``` Inside our `@main` function it should look like this: ```swift func null printResults: int iters { println "FizzBuzz Program Complete %/% iterations run." % iters.@str.() ~ } func null @main: str[] args { println "Hello World" ~ let FizzBuzz fizzy = $(20) FizzBuzz ~ let int iters = fizzy.run.("Fizz", "Buzz") ~ cll printResults.(iters) ~ } ``` > Notice that `@main` is the last thing in our file. This is not required but is suggested. ## Conclusion If you have followed along correctly your program should now look like this: ```swift " My FizzBuzz Program Created Fri Sep 6, 2024 FizzbBuzz test program created for practice. - No command line arguments - No dependencies " struct FizzBuzz { let int iters ~ func null @new: int iters { updt @this.iters = iters ~ } func int run: str _3Word, str _5Word { loop idx: idx < @this.iters { let str result = "" ~ let int idx = idx + 1 ~ if idx % 3 == 0 { updt result += _3Word ~ } if idx % 5 == 0 { updt result += _5Word ~ } if result == "" { updt result += idx.@str.() ~ } println result ~ } return @this.iters ~ } } func null printResults: int iters { println "FizzBuzz Program Complete %/% iterations run." % iters.@str.() ~ } func null @main: str[] args { println "Hello World" ~ let FizzBuzz fizzy = $(20) FizzBuzz ~ let int iters = fizzy.run.("Fizz", "Buzz") ~ cll printResults.(iters) ~ } ``` > It is suggested to have a single blank line at the end of the file. This will be added automatically by the autoformatter if not present. If we now run our program we should get the following result: ``` Hello World 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz FizzBuzz Program Complete 20/20 iterations run. ``` Next: [2.1 Reference](./2.1%20Reference.md)