refactor: latest docs

This commit is contained in:
Fernando Araoz 2025-01-20 22:06:16 -05:00
parent c26251567c
commit a1641046cb
12 changed files with 68 additions and 89 deletions

View File

@ -18,8 +18,7 @@ THP enums are a 1 to 1 map of PHP enums, with a slightly different syntax.
Enums don't have a scalar value by default. Enums don't have a scalar value by default.
<Code thpcode={` <Code thpcode={`
enum Suit enum Suit {
{
Hearts, Hearts,
Diamonds, Diamonds,
Clubs, Clubs,
@ -36,8 +35,7 @@ Backed enums can have a scalar for each case. The scalar values can only be
<Code <Code
thpcode={` thpcode={`
enum Suit(String) enum Suit(String) {
{
Hearts = "H", Hearts = "H",
Diamonds = "D", Diamonds = "D",
Clubs = "C", Clubs = "C",

View File

@ -26,17 +26,17 @@ map Person {
// Here we declare an instance of a Person. // Here we declare an instance of a Person.
val john_doe = Person { val john_doe = Person {
name: "John", name: "John",
surname: "Doe", surname: "Doe",
age: 33, age: 33,
} }
// If the compiler can infer the type of a Map, // If the compiler can infer the type of a Map,
// we can omit its type // we can omit its type
var Person mary_jane = .{ var Person mary_jane = .{
name: "Mary", name: "Mary",
surname: "Jane", surname: "Jane",
age: 27, age: 27,
} }
`} /> `} />

View File

@ -10,8 +10,7 @@ import Code from "@/components/Code.astro";
Tagged unions can hold a value from a fixed selection of types. Tagged unions can hold a value from a fixed selection of types.
<Code thpcode={` <Code thpcode={`
union Shape union Shape {
{
Dot, Dot,
Square(Int), Square(Int),
Rectangle(Int, Int), Rectangle(Int, Int),
@ -27,12 +26,10 @@ val rectangle1 = Shape::Rectangle(5, 15)
<Code <Code
thpcode={` thpcode={`
match shape_1 match shape_1
case ::Square(side) case ::Square(side) {
{
print("Area of the square: {side * side}") print("Area of the square: {side * side}")
} }
case ::Rectangle(length, height) case ::Rectangle(length, height) {
{
print("Area of the rectangle: {length * height}") print("Area of the rectangle: {length * height}")
} }
`} `}
@ -47,8 +44,7 @@ are contained as part of an array.
```php ```php
// The first snippet is compiled to: // The first snippet is compiled to:
enum Shape enum Shape {
{
case Dot; case Dot;
case Square; case Square;
case Rectangle; case Rectangle;

View File

@ -18,7 +18,6 @@ val result = {
val temp = 161 val temp = 161
temp * 2 // This will be assigned to \`result\` temp * 2 // This will be assigned to \`result\`
} }
print(result) // 322 print(result) // 322

View File

@ -47,10 +47,10 @@ TBD
val user_id = POST::get("user_id") val user_id = POST::get("user_id")
if Some(user_id) = user_id { if Some(user_id) = user_id {
print("user_id exists: {user_id}") print("user_id exists: {user_id}")
} }
if Some(user_id) = user_id && user_id > 0 { if Some(user_id) = user_id && user_id > 0 {
print("user_id is greater than 0: {user_id}") print("user_id is greater than 0: {user_id}")
} }
`} /> `} />

View File

@ -19,7 +19,7 @@ Braces are required.
val numbers = [0, 1, 2, 3] val numbers = [0, 1, 2, 3]
for number in numbers { for number in numbers {
print(number) print(number)
} }
`} /> `} />
@ -31,7 +31,7 @@ val dict = .{
} }
for value in dict { for value in dict {
print("{value}") print("{value}")
} }
`} /> `} />
@ -41,7 +41,7 @@ print("{value}")
val numbers = [0, 1, 2, 3] val numbers = [0, 1, 2, 3]
for index, number in numbers { for index, number in numbers {
print("{index} : {number}") print("{index} : {number}")
} }
`} /> `} />
@ -53,7 +53,7 @@ val dict = .{
} }
for key, value in dict { for key, value in dict {
print("{key} => {value}") print("{key} => {value}")
} }
`} /> `} />
@ -64,8 +64,8 @@ val colors = ["red", "green", "blue"]
var index = 0 var index = 0
while index < colors.size() { while index < colors.size() {
print("{colors[index]}") print("{colors[index]}")
index += 1 index += 1
} }
`} /> `} />

View File

@ -20,36 +20,36 @@ case None { print("user_id doesn't exist") }
match user_id match user_id
case Some(id) { case Some(id) {
print("user_id exists: {id}") print("user_id exists: {id}")
} }
case None { case None {
print("user_id doesn't exist") print("user_id doesn't exist")
} }
match user_id match user_id
case Some(id) if id > 0 { case Some(id) if id > 0 {
print("user_id exists: {id}") print("user_id exists: {id}")
} }
else { else {
print("user_id has other values ") print("user_id has other values ")
} }
match customer_id match customer_id
case 1, 2, 3 { case 1, 2, 3 {
print("special discount for our first 3 customers!") print("special discount for our first 3 customers!")
} }
else { else {
print("hello dear") print("hello dear")
} }
match customer*id match customer*id
| 1 | 2 | 3 { | 1 | 2 | 3 {
print("ehhhh") print("ehhhh")
} }
| 4 | 5 { | 4 | 5 {
print("ohhh") print("ohhh")
} }
| * { | * {
print("???") print("???")
} }
`} /> `} />

View File

@ -17,8 +17,7 @@ The following code shows a function without parameters
and without return type: and without return type:
<Code thpcode={` <Code thpcode={`
fun say_hello() fun say_hello() {
{
print("Hello") print("Hello")
} }
@ -34,8 +33,7 @@ type is **mandatory**, and it's done by placing an
arrow `->` followed by the return datatype: arrow `->` followed by the return datatype:
<Code thpcode={` <Code thpcode={`
fun get_random_number() -> Int fun get_random_number() -> Int {
{
return Random::get(0, 35_222) return Random::get(0, 35_222)
} }
@ -47,8 +45,7 @@ a return type:
<Code <Code
thpcode={` thpcode={`
fun get_random_number() fun get_random_number() {
{
// Error: the function does not define a return type // Error: the function does not define a return type
return Random::get(0, 35_222) return Random::get(0, 35_222)
} }
@ -60,8 +57,7 @@ expression on the function:
<Code <Code
thpcode={` thpcode={`
fun get_random_number() -> Int fun get_random_number() -> Int {
{
// The last expression of a function is // The last expression of a function is
// automatically returned // automatically returned
Random::get(0, 35_222) Random::get(0, 35_222)
@ -75,8 +71,7 @@ Parameters are declared like C-style languages:
`Type name`, separated by commas. `Type name`, separated by commas.
<Code thpcode={` <Code thpcode={`
fun add(Int a, Int b) -> Int fun add(Int a, Int b) -> Int {
{
return a + b return a + b
} }
@ -96,8 +91,7 @@ The following example declares a generic `T` and uses it
in the parameters and return type: in the parameters and return type:
<Code thpcode={` <Code thpcode={`
fun get_first_item[T](Array[T] array) -> T fun get_first_item[T](Array[T] array) -> T {
{
array[0] array[0]
} }
@ -134,8 +128,7 @@ fun html_special_chars(
Int? flags, Int? flags,
String? encoding, String? encoding,
Bool? double_encoding, Bool? double_encoding,
) -> String ) -> String {
{
// ... // ...
} }
@ -150,8 +143,7 @@ TBD: If & how named arguments affect the order of the parameters
fun greet( fun greet(
String name, String name,
String from: city, String from: city,
) ) {
{
print("Hello {name} from {city}!") print("Hello {name} from {city}!")
} }

View File

@ -10,8 +10,7 @@ import Code from "@/components/Code.astro";
## Function as parameters ## Function as parameters
<Code thpcode={` <Code thpcode={`
fun map[A, B](Array[A] input, (A) -> (B) function) -> Array[B] fun map[A, B](Array[A] input, (A) -> (B) function) -> Array[B] {
{
// implementation // implementation
} }
@ -20,8 +19,7 @@ fun map[A, B](Array[A] input, (A) -> (B) function) -> Array[B]
## Function as return ## Function as return
<Code thpcode={` <Code thpcode={`
fun generate_generator() -> () -> Int fun generate_generator() -> () -> Int {
{
// code... // code...
return fun() { return fun() {
322 322

View File

@ -64,7 +64,7 @@ By default closures **always** capture variables as **references**.
var x = 20 var x = 20
val f = fun() { val f = fun() {
print(x) print(x)
} }
f() // 20 f() // 20
@ -87,7 +87,7 @@ fun(parameters) clone(variables) {
var x = 20 var x = 20
val f = fun() clone(x) { val f = fun() clone(x) {
print(x) print(x)
} }
f() // 20 f() // 20
@ -112,6 +112,6 @@ numbers.map() #{
// the above lambda is equivalent to: // the above lambda is equivalent to:
numbers.map(fun(param1) { numbers.map(fun(param1) {
$1 \* 2 $1 \* 2
}) })
`} /> `} />

View File

@ -12,11 +12,11 @@ To represent `null` we must use nullable types, represented
by the question mark `?` character. by the question mark `?` character.
For instance, a POST request may have a `username` parameter, For instance, a POST request may have a `username` parameter,
or it may not. This can be represented with an `?String`. or it may not. This can be represented with an `String?`.
<Code <Code
thpcode={` thpcode={`
?String new_username = POST::get("username") String? new_username = POST::get("username")
`} `}
/> />
@ -26,15 +26,13 @@ check if the value is null, and then use it.
The syntax `?` returns `true` if the value is not null. The syntax `?` returns `true` if the value is not null.
<Code thpcode={` <Code thpcode={`
if new_username? if new_username? {
{
// Here \`new_username\` is automatically casted to String // Here \`new_username\` is automatically casted to String
} }
// you can also manually check for null // you can also manually check for null
if new_username == null if new_username == null {
{ // This is the same as above
// This is the same as above
} }
`} /> `} />
@ -49,24 +47,24 @@ To create a nullable type we must explicitly annotate the type.
<Code thpcode={` <Code thpcode={`
val favorite_color = null // Error, we must define the type val favorite_color = null // Error, we must define the type
?String favorite_color = null // Ok String? favorite_color = null // Ok
`} /> `} />
Other examples: Other examples:
<Code thpcode={` <Code thpcode={`
fun get_first(Array[?String] values) -> ?String {} fun get_first(Array[String?] values) -> String? {}
val result = get_first([]) val result = get_first([])
`} /> `} />
## Optional chaining ## Optional chaining
If you have a `?Type` and you wish to access a field of `Type` if it exists, If you have a `Type?` and you wish to access a field of `Type` if it exists,
you can use the optional chaining operator `?.`. you can use the optional chaining operator `?.`.
<Code thpcode={` <Code thpcode={`
?Person person = ... Person? person = ...
val name = person?.name val name = person?.name
`} /> `} />
@ -76,14 +74,14 @@ val name = person?.name
## Null unboxing ## Null unboxing
The `!!` operator transforms a `?Type` into `Type`. The `!!` operator transforms a `Type?` into `Type`.
If you are sure that a value cannot be `null`, you can force the If you are sure that a value cannot be `null`, you can force the
compiler to treat it as a regular value with the `!!` operator. compiler to treat it as a regular value with the `!!` operator.
Note the two exclamation marks. Note the two exclamation marks.
<Code thpcode={` <Code thpcode={`
?String lastname = find_lastname() String? lastname = find_lastname()
// Tell the compiler trust me, // Tell the compiler trust me,
// I know this is not null // I know this is not null
@ -109,7 +107,7 @@ The Elvis operator `??` is used to give a default value in case a `null` is foun
<Code thpcode={` <Code thpcode={`
// This is a function that may return a Int // This is a function that may return a Int
fun get_score() -> ?Int {...} fun get_score() -> Int? {...}
val test_score = get_score() ?? 0 val test_score = get_score() ?? 0
`} /> `} />

View File

@ -13,42 +13,41 @@ and handled.
## Declare that a function returns an exception ## Declare that a function returns an exception
Possible errors have their own syntax: `Error!Type`. Possible errors have their own syntax: `Type!Error`.
This means: This may be an `Error`, or a `Type`. This means: This may be a `Type`, or an `Error`.
For example, a function that returned a `DivisionByZero` For example, a function that returned a `DivisionByZero`
may be written like this: may be written like this:
<Code thpcode={` <Code thpcode={`
fun invert(Int number) -> DivisionByZero!Int fun invert(Int number) -> Int!DivisionByZero {
{
if number == 0 if number == 0
{ {
return DivisionByZero() throw DivisionByZero()
} }
return 1 / number return 1 / number
} }
`} /> `} />
In the previous segment, `DivisionByZero!Int` denotates In the previous segment, `Int!DivisionByZero` denotates
that the function may return either a `DivisionByZero` error that the function may return either a `DivisionByZero` error
or an `Int`. or an `Int`.
There is no `throw` keyword, errors are just returned. The `throw` keyword is used to denotate that an error is being
returned.
### Multiple error returns ### Multiple error returns
TODO: properly define syntax, how this interacts with type unions. TODO: properly define syntax, how this interacts with type unions.
Multiple errors are chained with `!`. The last one is always Multiple errors are chained with `!`.
the success value.
<Code <Code
thpcode={` thpcode={`
fun sample() -> Error1!Error2!Error3!Int fun sample() -> Int!Error1!Error2!Error3 {
{ /* ... */} /* ... */
}
`} `}
/> />
@ -66,14 +65,13 @@ Use a naked `try` when you want to rethrow an error, if there is any.
<InteractiveCode <InteractiveCode
code={` code={`
fun dangerous() -> Exception!Int fun dangerous() -> Int!Exception { // May throw randomly
{ // May throw randomly
return if Math.random() < 0.5 { 50 } return if Math.random() < 0.5 { 50 }
else { Exception("Unlucky") } else { Exception("Unlucky") }
} }
fun run() -> Exception! fun run() -> Void!Exception {
{ // If \`dangerous()\` throws, the function exits with the same error. // If \`dangerous()\` throws, the function exits with the same error.
// Otherwise, continues // Otherwise, continues
val result = try dangerous() val result = try dangerous()
print("The result is {result}") print("The result is {result}")