Use square brackets for arrays
This commit is contained in:
parent
e2119b135b
commit
2cab819c40
@ -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.
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
@ -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")
|
||||
```
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
```
|
||||
|
@ -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]()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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": /[{}[\];(),.]/,
|
||||
|
Loading…
Reference in New Issue
Block a user