From 7f9bb68dc52438a2911ba6dff0a80de3048d12f0 Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Sun, 7 Feb 2021 16:32:56 +0100 Subject: [PATCH] docs: add if statement documentation --- TODO | 1 + docs/SUMMARY.md | 1 + docs/concepts/control-flow.md | 76 +++++++++++++++++++ docs/introduction/SUMMARY.md | 2 + ...pe.sb => function_return_type_explicit.sb} | 0 tests/if_statement_basic.sb | 9 +++ tests/if_statement_multiple_arms.sb | 13 ++++ tests/if_statement_non_boolean_condition.sb | 7 ++ 8 files changed, 109 insertions(+) create mode 100644 docs/concepts/control-flow.md rename tests/{function_with_return_type.sb => function_return_type_explicit.sb} (100%) create mode 100644 tests/if_statement_basic.sb create mode 100644 tests/if_statement_multiple_arms.sb create mode 100644 tests/if_statement_non_boolean_condition.sb diff --git a/TODO b/TODO index 9084d76..91711ed 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ # Bugs +- Nested expressions can have invalid parens. Example: 6 % 3 == 0 should be true; is false # Cleanups - Improve error reporting (See ./util/string_util::highlight_position_in_file) diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index d5fbbac..361de59 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -8,6 +8,7 @@ - [Data Types](./concepts/datatypes.md) - [Functions](./concepts/functions.md) - [Comments](./concepts/comments.md) + - [Control Flow](./concepts/control-flow.md) - [Developer Resources](./developers/SUMMARY.md) - [Contributing to Sabre](./developers/contributing.md) - [Compiler Backends](./developers/backends.md) diff --git a/docs/concepts/control-flow.md b/docs/concepts/control-flow.md new file mode 100644 index 0000000..6148273 --- /dev/null +++ b/docs/concepts/control-flow.md @@ -0,0 +1,76 @@ +# Control Flow + +Deciding whether or not to run some code depending on if a condition is true and deciding to run some code repeatedly while a condition is true are basic building blocks in most programming languages. The most common constructs that let you control the flow of execution of Sabre code are `if` expressions and loops. + +## `if` Expressions + +An `if` expression allows you to branch your code depending on conditions. You provide a condition and then state, "If this condition is met, run this block of code. If the condition is not met, do not run this block of code." + +Here is a basic example of an `if` expression: + +``` +fn main() { + let number = 3 + + if number < 5 { + println("condition was true") + } else { + println("condition was false") + } +} +``` + +All `if` Statements start with the keyword `if`, followed by a condition. In this case, the condition checks if the number has a value less than 5. The block of code we want to execute if the condition is true is placed immediately after the condition inside curly braces. + +Optionally, we can also include an `else` expression, which we chose to do here, to give the program an alternative block of code to execute should the condition evaluate to false. If you don’t provide an `else` expression and the condition is false, the program will just skip the `if` block and move on to the next bit of code. + +Try running this code; You should see the following output: + +``` +$ sabre run main.sb +condition was true +``` + +Let’s try changing the value of `number` to a value that makes the condition false to see what happens: + +``` +let number = 7 +``` + +Run the program again, and look at the output: + +``` +$ sabre run main.sb +condition was false +``` + +> **Note**: It's worth noting that the condition in this code must be a bool. At the current state of the project, this is not the case, but it is subject to change at any time. **TODO**: Discuss this behavior. + +### Handling multiple conditions with `else if` + +You can have multiple conditions by combining `if` and `else` in an `else if` expression. For example: + +``` +fn main() { + let number = 6 + + if number % 4 == 0 { + println("number is divisible by 4") + } else if number % 3 == 0 { + println("number is divisible by 3") + } else if number % 2 == 0 { + println("number is divisible by 2") + } else { + println("number is not divisible by 4, 3, or 2") + } +} +``` + +This program has four possible paths it can take. After running it, you should see the following output: + +``` +$ sabre run main.sb +number is divisible by 3 +``` + +When this program executes, it checks each `if` expression in turn and executes the first body for which the condition holds true. Note that even though 6 is divisible by 2, we don’t see the output `number is divisible by 2`, nor do we see the `number is not divisible by 4, 3, or 2` text from the else block. That’s because Sabre only executes the block for the first true condition, and once it finds one, it doesn’t even check the rest. diff --git a/docs/introduction/SUMMARY.md b/docs/introduction/SUMMARY.md index 4a6e99b..e9893f3 100644 --- a/docs/introduction/SUMMARY.md +++ b/docs/introduction/SUMMARY.md @@ -6,3 +6,5 @@ It is meant to "just work", without adding unnecessary and bloated language feat To get started with Sabre, continue with the [installation](./installation.md) > **Note**: Some parts of this documentation have been copied from the [Rust book](https://doc.rust-lang.org/book/). + +> **Note**: This documentation is incomplete. If you feel like that a feature or behavior should be documented, feel free to contact the maintainers. You can search for the word _TODO_, if you want to help improving this documentation but don't know where to start. Any help is always welcome! diff --git a/tests/function_with_return_type.sb b/tests/function_return_type_explicit.sb similarity index 100% rename from tests/function_with_return_type.sb rename to tests/function_return_type_explicit.sb diff --git a/tests/if_statement_basic.sb b/tests/if_statement_basic.sb new file mode 100644 index 0000000..6569033 --- /dev/null +++ b/tests/if_statement_basic.sb @@ -0,0 +1,9 @@ +fn main() { + let number = 3 + + if number < 5 { + println("condition was true") + } else { + println("condition was false") + } +} \ No newline at end of file diff --git a/tests/if_statement_multiple_arms.sb b/tests/if_statement_multiple_arms.sb new file mode 100644 index 0000000..8f70398 --- /dev/null +++ b/tests/if_statement_multiple_arms.sb @@ -0,0 +1,13 @@ +fn main() { + let number = 6 + + if number % 4 == 0 { + println("number is divisible by 4") + } else if number % 3 == 0 { + println("number is divisible by 3") + } else if number % 2 == 0 { + println("number is divisible by 2") + } else { + println("number is not divisible by 4, 3, or 2") + } +} \ No newline at end of file diff --git a/tests/if_statement_non_boolean_condition.sb b/tests/if_statement_non_boolean_condition.sb new file mode 100644 index 0000000..8fbd737 --- /dev/null +++ b/tests/if_statement_non_boolean_condition.sb @@ -0,0 +1,7 @@ +fn main() { + let number = 3 + + if number { + println("number was three") + } +} \ No newline at end of file