Update syntax in docs
This commit is contained in:
parent
4a3db447ce
commit
1a196aa8f7
@ -5,14 +5,14 @@ language that cross-compiles to C. Tomo is designed to anticipate and influence
|
||||
the language design decisions of the future.
|
||||
|
||||
```
|
||||
func greeting(name:Text, add_exclamation:Bool -> Text):
|
||||
func greeting(name:Text, add_exclamation:Bool -> Text)
|
||||
message := "hello $name"
|
||||
message = " ".join([w.title() for w in message.split_any(" ")])
|
||||
if add_exclamation:
|
||||
if add_exclamation
|
||||
message ++= "!!!"
|
||||
return message
|
||||
|
||||
func main(name:Text, shout=no):
|
||||
func main(name:Text, shout=no)
|
||||
to_say := greeting(name, add_exclamation=shout)
|
||||
say(to_say)
|
||||
```
|
||||
|
@ -5,10 +5,10 @@ Here's a simple example:
|
||||
|
||||
```tomo
|
||||
# greet.tm
|
||||
func main(name:Text, be_excited=no):
|
||||
func main(name:Text, be_excited=no)
|
||||
if be_excited
|
||||
say("Hello $name!!!")
|
||||
else:
|
||||
else
|
||||
say("Hi $name.")
|
||||
```
|
||||
|
||||
@ -85,7 +85,7 @@ Parsing is case-insensitive:
|
||||
```
|
||||
# foo.tm
|
||||
enum Foo(One, Two, Three)
|
||||
func main(foo:Foo):
|
||||
func main(foo:Foo)
|
||||
>> foo
|
||||
|
||||
# Signature:
|
||||
@ -104,7 +104,7 @@ List-of-text arguments can be passed like this:
|
||||
|
||||
```tomo
|
||||
# many-texts.tm
|
||||
func main(args:[Text]):
|
||||
func main(args:[Text])
|
||||
>> args
|
||||
```
|
||||
|
||||
|
@ -15,14 +15,14 @@ c := VariousThings.Nothing
|
||||
|
||||
## Pattern Matching
|
||||
|
||||
The values inside an enum can be accessed with pattern matching:
|
||||
The values inside an enum can be accessed with pattern matching
|
||||
|
||||
```tomo
|
||||
when x is AnInteger(i):
|
||||
when x is AnInteger(i)
|
||||
say("It was $i")
|
||||
is TwoWords(x, y):
|
||||
is TwoWords(x, y)
|
||||
say("It was $x and $y")
|
||||
is Nothing:
|
||||
is Nothing
|
||||
say("It was nothing")
|
||||
```
|
||||
|
||||
@ -54,10 +54,10 @@ from a function with an explicit return type:
|
||||
enum ArgumentType(AnInt(x:Int), SomeText(text:Text))
|
||||
enum ReturnType(Nothing, AnInt(x:Int))
|
||||
|
||||
func increment(arg:ArgumentType -> ReturnType):
|
||||
when arg is AnInt(x):
|
||||
func increment(arg:ArgumentType -> ReturnType)
|
||||
when arg is AnInt(x)
|
||||
return AnInt(x + 1)
|
||||
is SomeText:
|
||||
is SomeText
|
||||
return Nothing
|
||||
|
||||
...
|
||||
@ -78,9 +78,9 @@ known.
|
||||
Enums can also define their own methods and variables inside their namespace:
|
||||
|
||||
```tomo
|
||||
enum VariousThings(AnInteger(i:Int), TwoWords(word1, word2:Text), Nothing):
|
||||
enum VariousThings(AnInteger(i:Int), TwoWords(word1, word2:Text), Nothing)
|
||||
meaningful_thing := AnInteger(42)
|
||||
func doop(v:VariousThings):
|
||||
func doop(v:VariousThings)
|
||||
say("$v")
|
||||
```
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
In Tomo, you can define functions with the `func` keyword:
|
||||
|
||||
```tomo
|
||||
func add(x:Int, y:Int -> Int):
|
||||
func add(x:Int, y:Int -> Int)
|
||||
return x + y
|
||||
```
|
||||
|
||||
@ -19,7 +19,7 @@ Instead of giving a type, you can provide a default argument and the type
|
||||
checker will infer the type of the argument from that value:
|
||||
|
||||
```tomo
|
||||
func increment(x:Int, amount=1 -> Int):
|
||||
func increment(x:Int, amount=1 -> Int)
|
||||
return x + amount
|
||||
```
|
||||
|
||||
@ -47,7 +47,7 @@ and are bound to arguments first, followed by binding positional arguments to
|
||||
any unbound arguments, in order:
|
||||
|
||||
```tomo
|
||||
func foo(x:Int, y:Text, z:Num):
|
||||
func foo(x:Int, y:Text, z:Num)
|
||||
return "x=$x y=$y z=$z"
|
||||
|
||||
>> foo(x=1, y="hi", z=2.5)
|
||||
@ -68,7 +68,7 @@ Tomo supports automatic function caching using the `cached` or `cache_size=N`
|
||||
attributes on a function definition:
|
||||
|
||||
```tomo
|
||||
func add(x, y:Int -> Int; cached):
|
||||
func add(x, y:Int -> Int; cached)
|
||||
return x + y
|
||||
```
|
||||
|
||||
@ -78,15 +78,15 @@ return value for those arguments. The above example is functionally similar to
|
||||
the following code:
|
||||
|
||||
```tomo
|
||||
func _add(x, y:Int -> Int):
|
||||
func _add(x, y:Int -> Int)
|
||||
return x + y
|
||||
|
||||
struct add_args(x,y:Int)
|
||||
add_cache : @{add_args=Int} = @{}
|
||||
|
||||
func add(x, y:Int -> Int):
|
||||
func add(x, y:Int -> Int)
|
||||
args := add_args(x, y)
|
||||
if cached := add_cache[args]:
|
||||
if cached := add_cache[args]
|
||||
return cached
|
||||
ret := _add(x, y)
|
||||
add_cache[args] = ret
|
||||
@ -98,7 +98,7 @@ evicted if the cache has reached the maximum size and needs to insert a new
|
||||
entry:
|
||||
|
||||
```tomo
|
||||
func doop(x:Int, y:Text, z:[Int]; cache_size=100 -> Text):
|
||||
func doop(x:Int, y:Text, z:[Int]; cache_size=100 -> Text)
|
||||
return "x=$x y=$y z=$z"
|
||||
```
|
||||
|
||||
@ -108,7 +108,7 @@ Functions can also be given an `inline` attribute, which encourages the
|
||||
compiler to inline the function when possible:
|
||||
|
||||
```tomo
|
||||
func add(x, y:Int -> Int; inline):
|
||||
func add(x, y:Int -> Int; inline)
|
||||
return x + y
|
||||
```
|
||||
|
||||
@ -128,8 +128,8 @@ The normal form of a lambda is to give a return expression after the colon,
|
||||
but you can also use a block that includes statements:
|
||||
|
||||
```tomo
|
||||
fn := func(x,y:Int):
|
||||
if x == 0:
|
||||
fn := func(x,y:Int)
|
||||
if x == 0
|
||||
return y
|
||||
return x + y
|
||||
```
|
||||
@ -151,8 +151,8 @@ values. **Captured values are copied to a new location at the moment the lambda
|
||||
is created and will not reflect changes to local variables.**
|
||||
|
||||
```tomo
|
||||
func create_adder(n:Int -> func(i:Int -> Int)):
|
||||
adder := func(i:Int):
|
||||
func create_adder(n:Int -> func(i:Int -> Int))
|
||||
adder := func(i:Int)
|
||||
return n + i
|
||||
|
||||
n = -1 // This does not affect the adder
|
||||
|
@ -362,7 +362,7 @@ An iterator function that counts onward from the starting integer.
|
||||
**Example:**
|
||||
```tomo
|
||||
nums : &[Int] = &[]
|
||||
for i in (5).onward():
|
||||
for i in (5).onward()
|
||||
nums.insert(i)
|
||||
stop if i == 10
|
||||
>> nums[]
|
||||
|
@ -24,7 +24,7 @@ successively gets one line from a file at a time until the file is exhausted:
|
||||
>> iter()
|
||||
= none : Text?
|
||||
|
||||
for line in (./test.txt).each_line():
|
||||
for line in (./test.txt).each_line()
|
||||
pass
|
||||
```
|
||||
|
||||
@ -32,13 +32,13 @@ You can write your own iterator methods this way. For example, this iterator
|
||||
iterates over prime numbers up to a given limit:
|
||||
|
||||
```tomo
|
||||
func primes_up_to(limit:Int):
|
||||
func primes_up_to(limit:Int)
|
||||
n := 2
|
||||
return func():
|
||||
if n > limit:
|
||||
return func()
|
||||
if n > limit
|
||||
return !Int
|
||||
|
||||
while not n.is_prime():
|
||||
while not n.is_prime()
|
||||
n += 1
|
||||
|
||||
n += 1
|
||||
|
@ -9,8 +9,8 @@ values and give type checking errors if you attempt to use one type of string
|
||||
where a different type of string is needed.
|
||||
|
||||
```tomo
|
||||
lang HTML:
|
||||
convert(t:Text -> HTML):
|
||||
lang HTML
|
||||
convert(t:Text -> HTML)
|
||||
t = t.translate({
|
||||
"&" = "&",
|
||||
"<" = "<",
|
||||
@ -20,7 +20,7 @@ lang HTML:
|
||||
})
|
||||
return HTML.from_text(t)
|
||||
|
||||
func paragraph(content:HTML -> HTML):
|
||||
func paragraph(content:HTML -> HTML)
|
||||
return $HTML"<p>$content</p>"
|
||||
```
|
||||
|
||||
@ -73,11 +73,11 @@ instead of building a global function called `execute()` that takes a
|
||||
`ShellScript` argument, you could instead build something like this:
|
||||
|
||||
```tomo
|
||||
lang Sh:
|
||||
convert(text:Text -> Sh):
|
||||
lang Sh
|
||||
convert(text:Text -> Sh)
|
||||
return Sh.from_text("'" ++ text.replace("'", "''") ++ "'")
|
||||
|
||||
func execute(sh:Sh -> Text):
|
||||
func execute(sh:Sh -> Text)
|
||||
...
|
||||
|
||||
dir := ask("List which dir? ")
|
||||
@ -92,14 +92,14 @@ keyword. Conversions can be defined either inside of the language's block,
|
||||
another type's block or at the top level.
|
||||
|
||||
```tomo
|
||||
lang Sh:
|
||||
convert(text:Text -> Sh):
|
||||
lang Sh
|
||||
convert(text:Text -> Sh)
|
||||
return Sh.from_text("'" ++ text.replace("'", "''") ++ "'")
|
||||
|
||||
struct Foo(x,y:Int):
|
||||
convert(f:Foo -> Sh):
|
||||
struct Foo(x,y:Int)
|
||||
convert(f:Foo -> Sh)
|
||||
return Sh.from_text("$(f.x),$(f.y)")
|
||||
|
||||
convert(texts:[Text] -> Sh):
|
||||
convert(texts:[Text] -> Sh)
|
||||
return $Sh" ".join([Sh(t) for t in texts])
|
||||
```
|
||||
|
@ -50,10 +50,10 @@ Now, what happens if we want to _use_ the compiled object file?
|
||||
// File: baz.tm
|
||||
foo := use ./foo.tm
|
||||
|
||||
func say_stuff():
|
||||
func say_stuff()
|
||||
say("I got $(foo.my_variable) from foo")
|
||||
|
||||
func main():
|
||||
func main()
|
||||
say_stuff()
|
||||
```
|
||||
|
||||
|
@ -86,10 +86,10 @@ list access.
|
||||
You can iterate over the items in a list like this:
|
||||
|
||||
```tomo
|
||||
for item in list:
|
||||
for item in list
|
||||
...
|
||||
|
||||
for i, item in list:
|
||||
for i, item in list
|
||||
...
|
||||
```
|
||||
|
||||
|
@ -15,9 +15,9 @@ collide with a user-chosen name like `FooBaz`.
|
||||
// File: foo.tm
|
||||
my_var := 123
|
||||
|
||||
struct Baz(x:Int):
|
||||
struct Baz(x:Int)
|
||||
member := 5
|
||||
func frob(b:Baz -> Int):
|
||||
func frob(b:Baz -> Int)
|
||||
return b.x
|
||||
```
|
||||
|
||||
|
@ -71,7 +71,7 @@ y := 1.0
|
||||
# implicit `!`:
|
||||
x = x/y
|
||||
|
||||
func doop(x:Num -> Num):
|
||||
func doop(x:Num -> Num)
|
||||
# If a function's return type is non-optional and an optional value is
|
||||
# used in a return statement, an implicit none check will be inserted and
|
||||
# will error if the value is none:
|
||||
|
@ -98,8 +98,8 @@ This simplifies things if you want to do a reduction without writing a full
|
||||
comprehension:
|
||||
|
||||
```tomo
|
||||
struct Foo(x,y:Int):
|
||||
func is_even(f:Foo)->Bool:
|
||||
struct Foo(x,y:Int)
|
||||
func is_even(f:Foo -> Bool)
|
||||
return (f.x + f.y) mod 2 == 0
|
||||
|
||||
>> foos := [Foo(1, 2), Foo(-10, 20)]
|
||||
@ -217,7 +217,7 @@ will be raised.
|
||||
#### Addition
|
||||
|
||||
```
|
||||
func plus(T, T)->T
|
||||
func plus(T, T -> T)
|
||||
```
|
||||
|
||||
In an addition expression `a + b` between two objects of the same type, the
|
||||
@ -226,7 +226,7 @@ method `a.plus(b)` will be invoked, which returns a new value of the same type.
|
||||
#### Subtraction
|
||||
|
||||
```
|
||||
func minus(T, T)->T
|
||||
func minus(T, T -> T)
|
||||
```
|
||||
|
||||
In a subtraction expression `a - b` between two objects of the same type, the
|
||||
@ -235,8 +235,8 @@ method `a.minus(b)` will be invoked, which returns a new value of the same type.
|
||||
#### Multiplication
|
||||
|
||||
```
|
||||
func times(T, T)->T
|
||||
func scaled_by(T, N)->T
|
||||
func times(T, T -> T)
|
||||
func scaled_by(T, N -> T)
|
||||
```
|
||||
|
||||
The multiplication expression `a * b` invokes either the `a.times(b)` method,
|
||||
@ -247,7 +247,7 @@ non-numeric and `b` is numeric, or `b.scaled_by(a)` if `b` is non-numeric and
|
||||
#### Division
|
||||
|
||||
```
|
||||
func divided_by(T, N)->T
|
||||
func divided_by(T, N -> T)
|
||||
```
|
||||
|
||||
In a division expression `a / b` the method `a.divided_by(b)` will be invoked
|
||||
@ -256,7 +256,7 @@ if `a` has type `T` and `b` has a numeric type `N`.
|
||||
#### Exponentiation
|
||||
|
||||
```
|
||||
func power(T, N)->T
|
||||
func power(T, N -> T)
|
||||
```
|
||||
|
||||
In an exponentiation expression, `a ^ b`, if `a` has type `T` and `b` has a
|
||||
@ -265,8 +265,8 @@ numeric type `N`, then the method `a.power(b)` will be invoked.
|
||||
#### Modulus
|
||||
|
||||
```
|
||||
func mod(T, N)->T
|
||||
func mod1(T, N)->T
|
||||
func mod(T, N -> T)
|
||||
func mod1(T, N -> T)
|
||||
```
|
||||
|
||||
In a modulus expression, `a mod b` or `a mod1 b`, if `a` has type `T` and `b`
|
||||
@ -275,7 +275,7 @@ has a numeric type `N`, then the method `mod()` or `mod1()` will be invoked.
|
||||
#### Negative
|
||||
|
||||
```
|
||||
func negative(T)->T
|
||||
func negative(T -> T)
|
||||
```
|
||||
|
||||
In a unary negative expression `-x`, the method `negative()` will be invoked
|
||||
@ -284,13 +284,13 @@ and will return a value of the same type.
|
||||
#### Bit Operations
|
||||
|
||||
```
|
||||
func left_shifted(T, Int)->T
|
||||
func right_shifted(T, Int)->T
|
||||
func unsigned_left_shifted(T, Int)->T
|
||||
func unsigned_right_shifted(T, Int)->T
|
||||
func bit_and(T, T)->T
|
||||
func bit_or(T, T)->T
|
||||
func bit_xor(T, T)->T
|
||||
func left_shifted(T, Int -> T)
|
||||
func right_shifted(T, Int -> T)
|
||||
func unsigned_left_shifted(T, Int -> T)
|
||||
func unsigned_right_shifted(T, Int -> T)
|
||||
func bit_and(T, T -> T)
|
||||
func bit_or(T, T -> T)
|
||||
func bit_xor(T, T -> T)
|
||||
```
|
||||
|
||||
In a bit shifting expression, `a >> b` or `a << b`, if `a` has type `T` and `b`
|
||||
@ -305,7 +305,7 @@ method `bit_and()`, `bit_or()`, or `bit_xor()` will be invoked, assuming that
|
||||
#### Bitwise Negation
|
||||
|
||||
```
|
||||
func negated(T)->T
|
||||
func negated(T -> T)
|
||||
```
|
||||
|
||||
In a unary bitwise negation expression `not x`, the method `negated()` will be
|
||||
|
@ -6,10 +6,10 @@ represent this case using enums like so:
|
||||
```tomo
|
||||
enum MaybeInt(AnInt(x:Int), NoInt)
|
||||
|
||||
func maybe_takes_int(maybe_x:MaybeInt):
|
||||
when maybe_x is AnInt(x):
|
||||
func maybe_takes_int(maybe_x:MaybeInt)
|
||||
when maybe_x is AnInt(x)
|
||||
say("Got an int: $x")
|
||||
else:
|
||||
else
|
||||
say("Got nothing")
|
||||
```
|
||||
|
||||
@ -18,10 +18,10 @@ situation where you might want to not have a value. Instead, Tomo has
|
||||
built-in support for optional types:
|
||||
|
||||
```
|
||||
func maybe_takes_int(x:Int?):
|
||||
if x:
|
||||
func maybe_takes_int(x:Int?)
|
||||
if x
|
||||
say("Got an int: $x")
|
||||
else:
|
||||
else
|
||||
say("Got nothing")
|
||||
```
|
||||
|
||||
@ -76,7 +76,7 @@ Here are some examples:
|
||||
x := 5?
|
||||
x = none
|
||||
|
||||
func doop(arg:Int?)->Text?:
|
||||
func doop(arg:Int? -> Text?)
|
||||
return none
|
||||
|
||||
doop(none)
|
||||
@ -89,7 +89,7 @@ the need for an explicit `?` operator in the cases listed above:
|
||||
x : Int? = none
|
||||
x = 5
|
||||
|
||||
func doop(arg:Int?)->Text?:
|
||||
func doop(arg:Int? -> Text?)
|
||||
return "okay"
|
||||
|
||||
doop(123)
|
||||
@ -115,10 +115,10 @@ maybe_x = none
|
||||
>> maybe_x or fail("No value!")
|
||||
# Failure!
|
||||
|
||||
func do_stuff(matches:[Text]):
|
||||
func do_stuff(matches:[Text])
|
||||
pass
|
||||
|
||||
for line in lines:
|
||||
for line in lines
|
||||
matches := line.matches($/{..},{..}/) or skip
|
||||
# The `or skip` above means that if we're here, `matches` is non-none:
|
||||
do_stuff(matches)
|
||||
|
@ -181,14 +181,14 @@ value if the file couldn't be read.
|
||||
**Example:**
|
||||
```tomo
|
||||
# Safely handle file not being readable:
|
||||
if lines := (./file.txt).by_line():
|
||||
for line in lines:
|
||||
if lines := (./file.txt).by_line()
|
||||
for line in lines
|
||||
say(line.upper())
|
||||
else:
|
||||
else
|
||||
say("Couldn't read file!")
|
||||
|
||||
# Assume the file is readable and error if that's not the case:
|
||||
for line in (/dev/stdin).by_line()!:
|
||||
for line in (/dev/stdin).by_line()!
|
||||
say(line.upper())
|
||||
```
|
||||
|
||||
|
@ -12,7 +12,7 @@ a new, different value and assigning it to a pointer's memory location to
|
||||
replace the value that previously resided there.
|
||||
|
||||
```tomo
|
||||
func no_mutation_possible(nums:[Int]):
|
||||
func no_mutation_possible(nums:[Int])
|
||||
nums[1] = 10 // This performs a copy-on-write and creates a new list
|
||||
// The new list is only accessible as a local variable here
|
||||
...
|
||||
@ -21,7 +21,7 @@ no_mutation_possible(my_nums)
|
||||
>> my_nums
|
||||
= [0, 1, 2]
|
||||
|
||||
func do_mutation(nums:@[Int]):
|
||||
func do_mutation(nums:@[Int])
|
||||
nums[1] = 10 // The mutates the value at the given pointer's location
|
||||
...
|
||||
my_nums := @[0, 1, 2]
|
||||
@ -82,9 +82,9 @@ this, and everywhere inside the truthy block will allow you to use the pointer
|
||||
as a non-null pointer:
|
||||
|
||||
```
|
||||
if optional:
|
||||
if optional
|
||||
ok := optional[]
|
||||
else:
|
||||
else
|
||||
say("Oh, it was null")
|
||||
```
|
||||
|
||||
|
@ -62,10 +62,10 @@ Set length can be accessed by the `.length` field:
|
||||
You can iterate over the items in a table like this:
|
||||
|
||||
```tomo
|
||||
for item in set:
|
||||
for item in set
|
||||
...
|
||||
|
||||
for i, item in set:
|
||||
for i, item in set
|
||||
...
|
||||
```
|
||||
|
||||
|
@ -21,13 +21,13 @@ Structs can define their own methods that can be called with a `:` or different
|
||||
values that are stored on the type itself.
|
||||
|
||||
```tomo
|
||||
struct Foo(name:Text, age:Int):
|
||||
struct Foo(name:Text, age:Int)
|
||||
oldest := Foo("Methuselah", 969)
|
||||
|
||||
func greet(f:Foo):
|
||||
func greet(f:Foo)
|
||||
say("Hi my name is $f.name and I am $f.age years old!")
|
||||
|
||||
func get_older(f:@Foo):
|
||||
func get_older(f:@Foo)
|
||||
f.age += 1
|
||||
...
|
||||
my_foo := @Foo("Alice", 28)
|
||||
|
@ -139,10 +139,10 @@ t := {"A"=10, "B"=20}
|
||||
You can iterate over the key/value pairs in a table like this:
|
||||
|
||||
```tomo
|
||||
for key, value in table:
|
||||
for key, value in table
|
||||
...
|
||||
|
||||
for key in table:
|
||||
for key in table
|
||||
...
|
||||
```
|
||||
|
||||
|
@ -370,7 +370,7 @@ text := "
|
||||
line one
|
||||
line two
|
||||
"
|
||||
for line in text.by_line():
|
||||
for line in text.by_line()
|
||||
# Prints: "line one" then "line two":
|
||||
say(line)
|
||||
```
|
||||
@ -398,7 +398,7 @@ delimiter (the default) will iterate over single grapheme clusters in the text.
|
||||
**Example:**
|
||||
```tomo
|
||||
text := "one,two,three"
|
||||
for chunk in text.by_split(","):
|
||||
for chunk in text.by_split(",")
|
||||
# Prints: "one" then "two" then "three":
|
||||
say(chunk)
|
||||
```
|
||||
@ -425,7 +425,7 @@ given delimiter characters, until it runs out and returns `none`.
|
||||
**Example:**
|
||||
```tomo
|
||||
text := "one,two,;,three"
|
||||
for chunk in text.by_split_any(",;"):
|
||||
for chunk in text.by_split_any(",;")
|
||||
# Prints: "one" then "two" then "three":
|
||||
say(chunk)
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user