docs+doctest, while loop with break and labels for non-local breaks
This commit is contained in:
1 parent
0569be3b21
commit
22fbd5584b
12 files changed
+729
-105
No files matched your search
+140
-20
@@ -36,15 +36,31 @@ If you don't want block to return anything, use `void`:
|
||||
|
||||
Every construction is an expression that returns something (or `void`):
|
||||
|
||||
val x = 111 // or autotest will fail!
|
||||
val limited = if( x > 100 ) 100 else x
|
||||
limited
|
||||
>>> 100
|
||||
|
||||
You can use blocks in if statement, as expected:
|
||||
|
||||
val x = 200
|
||||
val limited = if( x > 100 ) {
|
||||
100 + x * 0.1
|
||||
}
|
||||
else
|
||||
x
|
||||
limited
|
||||
>>> 120.0
|
||||
|
||||
When putting multiple statments in the same line it is convenient and recommended to use `;`:
|
||||
|
||||
var from; var to;
|
||||
from = 0; to = 100
|
||||
>>> void
|
||||
|
||||
Notice: returned value is `void` as assignment operator does not return its value. We might decide to change it.
|
||||
|
||||
Most often you can omit `;`, but improves readability and prevent some hardly seen bugs.
|
||||
|
||||
So the principles are:
|
||||
|
||||
@@ -55,18 +71,54 @@ So the principles are:
|
||||
|
||||
It is rather simple, like everywhere else:
|
||||
|
||||
val x = 2.0
|
||||
//
|
||||
sin(x * π/4) / 2.0
|
||||
>>> 0.5
|
||||
|
||||
See [math](math.md) for more on it.
|
||||
See [math](math.md) for more on it. Notice using Greek as identifier, all languages are allowed.
|
||||
|
||||
# Variables
|
||||
|
||||
Much like in kotlin, there are _variables_:
|
||||
|
||||
var name = "Sergey"
|
||||
|
||||
Variables can be not initialized at declaration, in which case they must be assigned before use, or an exception
|
||||
will be thrown:
|
||||
|
||||
var foo
|
||||
// WRONG! Exception will be thrown at next line:
|
||||
foo + "bar"
|
||||
|
||||
Correct pattern is:
|
||||
|
||||
foo = "foo"
|
||||
// now is OK:
|
||||
foo + bar
|
||||
|
||||
This is though a rare case when you need uninitialized variables, most often you can use conditional operatorss
|
||||
and even loops to assign results (see below).
|
||||
|
||||
# Constants
|
||||
|
||||
Same as in kotlin:
|
||||
|
||||
val HalfPi = π / 2
|
||||
|
||||
Note using greek characters in identifiers! All letters allowed, but remember who might try to read your script, most likely will know some English, the rest is the pure uncertainty.
|
||||
|
||||
# Defining functions
|
||||
|
||||
fun check(amount) {
|
||||
if( amount > 100 )
|
||||
"anough"
|
||||
"enough"
|
||||
else
|
||||
"more"
|
||||
}
|
||||
>>> Callable@...
|
||||
|
||||
Notice how function definition return a value, instance of `Callable`.
|
||||
|
||||
You can use both `fn` and `fun`. Note that function declaration _is an expression returning callable_.
|
||||
|
||||
@@ -74,24 +126,25 @@ There are default parameters in Ling:
|
||||
|
||||
fn check(amount, prefix = "answer: ") {
|
||||
prefix + if( amount > 100 )
|
||||
"anough"
|
||||
"enough"
|
||||
else
|
||||
"more"
|
||||
}
|
||||
>>> Callable@...
|
||||
|
||||
## Closures
|
||||
|
||||
Each __block has an isolated context that can be accessed from closures__. For example:
|
||||
|
||||
var counter = 1
|
||||
|
||||
|
||||
// this is ok: coumter is incremented
|
||||
def increment(amount=1) {
|
||||
fun increment(amount=1) {
|
||||
// use counter from a closure:
|
||||
counter = counter + amount
|
||||
}
|
||||
|
||||
val taskAlias = def someTask() {
|
||||
val taskAlias = fun someTask() {
|
||||
// this obscures global outer var with a local one
|
||||
var counter = 0
|
||||
// ...
|
||||
@@ -99,6 +152,7 @@ Each __block has an isolated context that can be accessed from closures__. For e
|
||||
// ...
|
||||
counter
|
||||
}
|
||||
>>> void
|
||||
|
||||
As was told, `def` statement return callable for the function, it could be used as a parameter, or elsewhere
|
||||
to call it:
|
||||
@@ -132,28 +186,94 @@ Concatenation is a `+`: `"hello " + name` works as expected. No confusion.
|
||||
|
||||
String literal could be multiline:
|
||||
|
||||
"
|
||||
Hello,
|
||||
World!
|
||||
"
|
||||
>>> "Hello
|
||||
"Hello
|
||||
World"
|
||||
|
||||
In that case compiler removes left margin and first/last empty lines. Note that it won't remove margin:
|
||||
though multiline literals is yet work in progress.
|
||||
|
||||
"Hello,
|
||||
World
|
||||
"
|
||||
>>> "Hello,
|
||||
World
|
||||
"
|
||||
# Flow control operators
|
||||
|
||||
because the first line has no margin in the literal.
|
||||
## if-then-else
|
||||
|
||||
As everywhere else, and as expression:
|
||||
|
||||
val count = 11
|
||||
if( count > 10 )
|
||||
println("too much")
|
||||
else {
|
||||
// do something else
|
||||
println("just "+count)
|
||||
}
|
||||
>>> too much
|
||||
>>> void
|
||||
|
||||
Notice returned value `void`: it is because of `println` have no return value, e.g., `void`.
|
||||
|
||||
|
||||
Or, more neat:
|
||||
|
||||
var count = 3
|
||||
println( if( count > 10 ) "too much" else "just " + count )
|
||||
>>> just 3
|
||||
>>> void
|
||||
|
||||
## while
|
||||
|
||||
Regular pre-condition while loop, as expression, loop returns it's last line result:
|
||||
|
||||
var count = 0
|
||||
while( count < 5 ) {
|
||||
count = count + 1
|
||||
count * 10
|
||||
}
|
||||
>>> 50
|
||||
|
||||
We can break as usual:
|
||||
|
||||
var count = 0
|
||||
while( count < 5 ) {
|
||||
if( count < 5 ) break
|
||||
count = count + 1
|
||||
count * 10
|
||||
}
|
||||
>>> void
|
||||
|
||||
Why `void`? Because `break` drops out without the chute, not providing anything to return. Indeed, we should provide exit value in the case:
|
||||
|
||||
var count = 0
|
||||
while( count < 5 ) {
|
||||
if( count > 3 ) break "too much"
|
||||
count = count + 1
|
||||
count * 10
|
||||
}
|
||||
>>> too much
|
||||
|
||||
## Breaking nested loops
|
||||
|
||||
If you have several loops and want to exit not the inner one, use labels:
|
||||
|
||||
var count = 0
|
||||
// notice the label:
|
||||
outerLoop@ while( count < 5 ) {
|
||||
var innerCount = 0
|
||||
while( innerCount < 100 ) {
|
||||
innerCount = innerCount + 1
|
||||
|
||||
if( innerCount == 5 && count == 2 )
|
||||
// and here we break the labelled loop:
|
||||
break@outerLoop "5/2 situation"
|
||||
}
|
||||
count = count + 1
|
||||
count * 10
|
||||
}
|
||||
>>> 5/2 situation
|
||||
|
||||
The label can be any valid identifier, even a keyword, labels exist in their own, isolated world, so no risk of occasional clash. Labels are also scoped to their context and do not exist outside it.
|
||||
|
||||
# Comments
|
||||
|
||||
// single line comment
|
||||
var result = null // here we will store the result
|
||||
|
||||
>>> void
|
||||
|
||||
|
||||
Reference in new issue
Block a user