Use square brackets for arrays

master
Araozu 2024-01-01 09:11:41 -05:00
parent e2119b135b
commit 2cab819c40
8 changed files with 144 additions and 115 deletions

View File

@ -1,23 +1,21 @@
# Arrays
No destructuring (for now?). There's no `[]` syntax
for constructing arrays
Use square brackets as usual.
## Usage
```thp
let fruits = Array("apple", "banana", "cherry")
let apple = fruits.[0]
let fruits = ["apple", "banana", "cherry"]
let apple = fruits[0]
print(apple)
let mut numbers = Array(0, 1, 2, 3)
let mut numbers = [0, 1, 2, 3]
// Note the dot
numbers.[3] = 5
numbers[3] = 5
print(numbers.[3]) // 5
print(numbers[3]) // 5
```
@ -29,6 +27,9 @@ Array[String]
Array[Int]
```
The Array signature __requires__ the word `Array`.
There is no `Int[]` or `[Int]` signature, since that would cause
problems with the language's grammar.

View File

@ -5,7 +5,7 @@
Braces are required.
```thp
let numbers = Array(0, 1, 2, 3)
let numbers = [0, 1, 2, 3]
for number in numbers
{
@ -20,9 +20,9 @@ for #(index, number) in numbers.entries()
```thp
let dict = Obj {
"apple": 10,
"banana": 7,
"cherries": 3,
apple: 10,
banana: 7,
cherries: 3,
}
for #(key, value) in dict
@ -45,12 +45,12 @@ for value in collection
## While loop
```thp
let colors = Array("red", "green", "blue")
let colors = ["red", "green", "blue"]
let mut index = 0
while index < colors.size()
{
print("{colors.[index]}")
print("{colors[index]}")
index += 1
}
```

View File

@ -41,7 +41,7 @@ let number = get_secure_random_number(0, 65535)
```thp
fun get_first_item[T](Array[T] array) -> T
{
array.[0]
array[0]
}
let first = get_first_item[Int](numbers)
@ -75,22 +75,23 @@ fun html_special_chars(
// ...
}
html_special_chars(input, double_encode: false)
html_special_chars(input, double_encoding: false)
```
TBD: If & how named arguments affect the order of the parameters
## Named arguments with different names
```thp
fun replace(
String in: input,
String each: pattern,
String with: replacement,
) -> String
fun greet(
String name,
String from: city,
)
{
// Use input, pattern and replacement
print("Hello {name} from {city}!")
}
replace(each: " ", in: "my name", with: "-")
greet(name: "John", from: "LA")
```

View File

@ -24,7 +24,7 @@ By default closures **always** capture variables as **references**.
```thp
let mut x = 20
val f = fun() {
let f = fun() {
print(x)
}
@ -46,7 +46,7 @@ fun(parameters) clone(variables) {
```thp
let mut x = 20
val f = fun() clone(x) {
let f = fun() clone(x) {
print(x)
}
@ -62,7 +62,7 @@ f() // 20
```thp
numbers.map {
it * 2
$0 * 2
}
```

View File

@ -24,21 +24,21 @@ fun count(Array[Int] numbers) -> Int {
## Mutable reference
```thp
fun push_25(&Array[Int] numbers) {
fun push_25(mut Array[Int] numbers) {
numbers.push(25) // Ok, will also mutate the original array
}
```
Placing a `&` before the type makes the parameter a mutable
Placing a `mut` before the type makes the parameter a mutable
reference. Mutable methods can be used, and the original
data **can** be mutated.
The caller *must* also use `&`.
The caller *must* also use `mut`.
```thp
let numbers = Array(0, 1, 2, 3)
push_25(&numbers) // Pass `numbers` as reference.
push_25(mut numbers) // Pass `numbers` as reference.
print(numbers(4)) // `Some(25)`
```
@ -60,7 +60,7 @@ of the parameter (CoW). The original data will **not** be mutated.
```thp
let numbers = Array(1, 2, 3, 4)
add_25(numbers) // Pass `numbers` as clone.
add_25(clone numbers) // Pass `numbers` as clone.
print(numbers(4)) // None
```

View File

@ -199,3 +199,53 @@ let f1 = add1 >> times2
f1(5) // 12
```
```thp
function_call[Datatype](param1, param2) {
// lambda
}
function_call([arr1, arr2])
function_call[Datatype]([arr1, arr2])
fun test[A, B](A a, B b) -> B {}
Array[String] v = 20
val x = Obj {
Array[Int] x: [1, 2, 3]
}
value + [1, 2, 3]
value + [Int]
value[0]
let functions = [
{0},
{1},
{2},
]
let index = 0
functions[index]()
```
```thp
fun main()
{
// Using the turbofish operator
let result = "42".parse[Int]()
}
```

View File

@ -55,7 +55,7 @@ These are **not** aspects that THP looks to solve or implement.
$has_key = str_contains($haystack, 'needle');
// THP
val has_key = haystack.contains("needle")
let has_key = haystack.contains("needle")
```
- Explicit variable declaration
@ -93,7 +93,7 @@ $cat = new Cat("Michifu", 7);
$cat->meow();
// THP
val cat = Cat("Michifu", 7)
let cat = Cat("Michifu", 7)
cat.meow();
```
@ -113,8 +113,9 @@ use Some::Deeply::Nested::{Class, Interface}
```
- Different module syntax
- Explicit module declaration
- PSR-4 required
- No `include` or `require`
- No `include`, `include_once`, `require` or `require_once`
---
@ -124,93 +125,69 @@ Other things:
- ADTs
### Runtime changes
## Runtime changes
THP should add as little runtime as possible.
Where possible THP will compile to available PHP functions/classes/methods/etc.
For example:
```thp
// ===== current =======
val name = "John"
var name = "John"
String name = "John"
var String name = "John"
// This expression
let greeting =
match get_person()
| Some(person) if person.age > 18
{
"Welcome, {person.name}"
}
| Some(person)
{
"I'm sorry {person.name}, you need to be 18 or older"
}
| None
{
"Nobody is here"
}
// ===== new? =======
let name = "John"
let mut name = "John"
String name = "John"
mut String name = "John"
// For primitive datatypes (Int, Float, Bool, String?)
// Cloned
fun add(Int x)
// Still cloned, but the x **binding** can be mutated, not the original variable
fun add(mut Int x)
// Same as 1st
fun add(clone Int x)
// For other datatypes
// Pass an immutable reference
fun add(Obj o)
// Pass a mutable reference
fun add(mut Obj o)
// Clone the argument
fun add(clone Obj o)
// Only references are passed, not "variables" (as PHP calls them)
let john = Obj {name: "John"}
/*
john --------> {name: "John"}
*/
fun set_empty(mut Obj person) {
/*
john ------┬--> {name: "John"}
person ----┘
*/
// This creates a **new** Obj, and the variable `person` now points to it.
person = Obj {name: "Alex"}
/*
john ---------> {name: "John"}
person -------> {name: "Alex"}
*/
// Would compile to:
$greeting = null;
$_person = get_person();
if ($_person !== null) {
if ($_person["age"] > 18) {
$greeting = "Welcome, " . $_person["name"];
}
else {
$greeting = "I'm sorry " . $_person["name"] . ", you need to be 18 or older";
}
}
set_empty(mut obj)
print(obj) // Obj {name: "John"}
```
## Example
```thp
use PDO
use Globals::Env
val (Some(dbUri) Some(dbUser) Some(dbPassword)) = (
Env::get("DB_URI")
Env::get("DB_USERNAME")
Env::get("DB_PASSWORD")
)
else {
die("All 3 db environment variables must be set.")
$greeting = "Nobody is here";
}
match PDO(dbUri dbUser dbPassword)
| Ok(connection) { /* db operations */ }
| Err(pdoException) { /* handle exception */ }
```
However, more advanced datatypes & helper functions will require a sort of
runtime (new classes/functions/etc) or abuse the language's syntax/semantics.
```thp
// TBD: Enum compilation
enum IpAddress {
V4(String),
V6(String),
}
let ip_1 = IpAddress::V4("255.255.0.0")
// Would possibly compile to:
enum IpAddress {
V4,
V6,
}
$ip_1 = [IpAddress::V4, "255.255.0.0"]
```
Such changes will be documented

View File

@ -15,7 +15,7 @@ Prism.languages.thp = {
pattern: /(["])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
greedy: true,
},
"keyword": /\b(?:static|const|enum|loop|use|break|catch|continue|do|else|finally|for|fun|if|in|fn|nil|return|throw|try|while|type|match|with|of|abstract|class|interface|private|pub|obj|override|open|init|let|mut)\b/,
"keyword": /\b(?:static|const|enum|loop|use|break|catch|continue|do|else|finally|for|fun|if|in|fn|nil|return|throw|try|while|type|match|with|of|abstract|class|interface|private|pub|obj|override|open|init|let|mut|clone)\b/,
"number": /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
"operator": /[<>]=?|[!=]=?=?|--?|\$|\+\+?|&&?|\|\|?|[?*/~^%]/,
"punctuation": /[{}[\];(),.]/,