refactor: move learn files to versioned folder

This commit is contained in:
Araozu 2024-11-21 21:21:09 -05:00
parent 67ff5203a6
commit 83c382d361
44 changed files with 100 additions and 1328 deletions

View File

@ -7,10 +7,6 @@ const basePath: string = Astro.props.basePath;
const entryPath = is_index_file(entry.path)? "": entry.path;
const entryUrl = basePath + entryPath + (entryPath.endsWith("/")? "" : "/");
console.table({
basePath,
entryPath,
})
function is_index_file(p) {
return p.endsWith("index")
@ -35,7 +31,7 @@ function is_index_file(p) {
entry.children && (
<>
<div class="mt-6 px-3 py-1 uppercase font-display text-c-text-2 font-medium">
{entry.title}
{entry.title.replaceAll("-", " ")}
</div>
<ul class="my-1">

View File

@ -21,6 +21,7 @@ export interface AstroFile {
export interface Frontmatter {
layout: string
title: string
order: number
}
type Props = {
@ -56,7 +57,8 @@ const second_level: Record<string, Array<AstroFile>> = {
for (const post of posts_2) {
const fragments = post.path.split("/");
if (fragments.length === 3) {
const folder_name = fragments[1];
const folder_name = fragments[1]!;
// create if not exists
if (second_level[folder_name] === undefined) {
second_level[folder_name] = [];
@ -65,21 +67,21 @@ for (const post of posts_2) {
}
else if (fragments.length === 2) {
// add to root folder
second_level["_"].push(post);
second_level["_"]!.push(post);
}
}
// transform to the layout that the sidebar expects
const entries = [];
const entries: Array<any> = [];
for (const levels_key in second_level) {
if (levels_key === "_") {
// top level
const posts = second_level[levels_key];
const posts = second_level[levels_key]!;
entries.push(...posts)
}
else {
const posts = second_level[levels_key];
const posts = second_level[levels_key]!;
const parentEntry = {
path: "",
title: levels_key,
@ -91,9 +93,6 @@ for (const levels_key in second_level) {
const index_page = entries.find(post => post.relative_file === "/index.md" || post.relative_file === "/index.mdx");
const basePath = index_page.url;
console.log(JSON.stringify(index_page, null, 4));
console.log(basePath);
---
<BaseLayout title={frontmatter.title}>

View File

@ -1,10 +1,11 @@
---
import path from "path";
import NewDocsLayout from "@/layouts/NewDocsLayout.astro";
import NewDocsLayout, { type AstroFile } from "@/layouts/NewDocsLayout.astro";
const { frontmatter, headings } = Astro.props;
// Get all the posts from this dir
const posts = await Astro.glob("./**/*.{md,mdx}");
const posts = await Astro.glob("./**/*.{md,mdx}") as unknown as Array<AstroFile>;
// Current dir
const current_dir = import.meta.dirname;
---

View File

@ -0,0 +1,9 @@
---
layout: "../_wrapper.astro"
title: Abstract
---
import Code from "@/components/Code.astro"
# Abstract

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Anonymous classes
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Anonymous classes

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Constructor/Destructor
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Constructor/Destructor

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Basics
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Classes

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Inheritance
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Inheritance

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Interfaces
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Interfaces

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Magic methods
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Magic methods

View File

@ -0,0 +1,15 @@
---
layout: "../_wrapper.astro"
title: Readonly
---
import Code from "@/components/Code.astro"
# Readonly
<Code thpcode={`
class Caño
{
}
`} />

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Static
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Static in classes

View File

@ -0,0 +1,7 @@
---
layout: "../_wrapper.astro"
title: Visibility
---
import Code from "@/components/Code.astro"
# Visibility

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Arrays
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Arrays

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Enums
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Enums

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Maps
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Maps

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Tuples
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Tuples

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Tagged unions
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Tagged unions

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Nullable types
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Nullable types

View File

@ -1,9 +1,9 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Try/Exceptions
---
import InteractiveCode from "../../../components/InteractiveCode.astro";
import Code from "../../../components/Code.astro"
import InteractiveCode from "@/components/InteractiveCode.astro";
import Code from "@/components/Code.astro"
# Try/exceptions

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Blocks
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Blocks

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Conditionals
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Conditionals

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Loops
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Loops

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Match
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Match

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Declaration
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Declaration

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Higher Order Functions
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Higher Order functions

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Lambdas
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Lambdas / Anonymous functions

View File

@ -1,8 +1,8 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Function parameters
---
import Code from "../../../components/Code.astro"
import Code from "@/components/Code.astro"
# Function parameters

View File

@ -1,9 +1,9 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Components
---
import Code from "../../../components/Code.astro"
import Info from "../../../components/docs/Info.astro"
import Code from "@/components/Code.astro"
import Info from "@/components/docs/Info.astro"
# Components

View File

@ -1,9 +1,9 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Control flow
---
import Code from "../../../components/Code.astro"
import Info from "../../../components/docs/Info.astro"
import Code from "@/components/Code.astro"
import Info from "@/components/docs/Info.astro"
# Control flow

View File

@ -1,9 +1,9 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Introduction
---
import Code from "../../../components/Code.astro"
import Info from "../../../components/docs/Info.astro"
import Code from "@/components/Code.astro"
import Info from "@/components/docs/Info.astro"
# THP templating

View File

@ -1,9 +1,9 @@
---
layout: ../../../layouts/DocsLayout.astro
layout: "../_wrapper.astro"
title: Props
---
import Code from "../../../components/Code.astro"
import Info from "../../../components/docs/Info.astro"
import Code from "@/components/Code.astro"
import Info from "@/components/docs/Info.astro"
# Props

View File

@ -1,61 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Comments
---
import Code from "../../../components/Code.astro"
# Comments
THP supports single and multi line comments:
## Single line
Begin with double slash `//` and continue until the end of the line.
<Code thpcode={`
// This is a single line comment
print("hello!")
print("the result is {5 + 5}") // This will print 10
`} />
## Multi line
These begin with `/*` and end with `*/`. Everything in between is ignored.
Multi line comments can be nested in THP.
<Code thpcode={`
/*
This is a
multiline comment
*/
`} />
<Code thpcode={`
/*
Multiline comments
can be /* nested */
*/
`} />
## Documentation comments
Documentation comments use triple slashes `///`.
These use [CommonMark Markdown](https://commonmark.org/) syntax.
<Code thpcode={`
/// Transforms the format from A to B...
///
/// ## Errors
///
/// This function will error if condition
/// X or Y is met...
fun transform() {
// ...
}
`} />

View File

@ -1,86 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Datatypes
---
import Code from "../../../components/Code.astro"
# Datatypes
THP requires that all datatypes start their name with an
uppercase letter.
The following are basic datatypes.
## Int
Same as php int
<Code thpcode={`
Int age = 32
// Hexadecimal numbers start with 0x
Int red = 0xff0000
// Octal numbers start with 0o
Int permissions = 0o775
// Binary numbers start with 0b
Int char_code = 0b01000110
// IMPORTANT!
// Since Octal starts with \`0o\`, using just a leading 0
// will result in a decimal!
Int not_octal = 032 // This is 32, not 26
`} />
// TODO: Make it a compile error to have leading zeroes,
and force users to use `0o` for octal
## Float
Same as php float
<Code thpcode={`
Float pi = 3.141592
Float light = 2.99e+8
`} />
## String
THP strings use **only** double quotes. Single quotes are
used elsewhere.
<Code thpcode={`
String name = "Rose"
`} />
Strings have interpolation with `{}`.
<Code thpcode={`
print("Hello, {name}") // Hello, Rose
`} />
Unlike PHP, THP strings are concatenated with `++`, not with `.`.
This new operator implicitly converts any operator into a string.
<Code thpcode={`
val name = "John" ++ " " ++ "Doe"
val greeting = "My name is " ++ name ++ " and I'm " ++ 32 ++ " years old"
`} />
The plus operator `+` is reserved for numbers.
## Bool
THP booleans are `true` and `false`. They are case sensitive,
**only lowercase.**
<Code thpcode={`
Bool is_true = true
Bool is_false = false
// This is a compile error
val invalid = TRUE
`} />

View File

@ -1,45 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Hello world
---
import InteractiveCode from "../../../components/InteractiveCode.astro";
import Code from "../../../components/Code.astro"
# Hello, world!
## THP source code
Unlike PHP, THP code is written directly. There is no need to use any `<?php` tags,
just write the code like any other programming language.
As a consequence of this, HTML templates are defined in other ways, which will be
detailed later on.
To write a hello world program write the following code in a file:
<Code thpcode={`
print("Hello, world!")
`} />
Then run `thp hello.thp` from your terminal.
## Instruction separation
THP uses whitespace to determine when a statement is over. In short,
where PHP uses a semicolon `;`, THP uses a newline.
```php
echo("A");
echo("B");
echo("C");
```
<Code thpcode={`
print("A")
print("B")
print("C")
`} />
As a consequence of this, there can only be 1 statement per line.

View File

@ -1,120 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Operators
---
import Code from "../../../components/Code.astro"
# Operators
Most of the PHP operators are present in THP.
## Numbers
<Code thpcode={`
var number = 322
number + 1
number - 1
number * 1
number / 1
number % 2
number += 1
number -= 1
number *= 1
number /= 1
number %= 2
`} />
**There are no prefix/postfix increment operators** (`++`, `--`),
use `+=` or `-=` instead.
<Code thpcode={`
// Use
number += 1
// instead of
number++ // This is a compile error
`} />
### Comparison
These operators will not do implicit type conversion. They can
only be used with same datatypes.
<Code thpcode={`
v1 < v2
v1 <= v2
v1 > v2
v1 >= v2
`} />
There is only `==` and `!=`. They are equivalent to `===` and `!==`.
<Code thpcode={`
v1 == v2
v1 != v2
`} />
### Bitwise
TBD
<Code thpcode={`
number and 1
number or 2
number xor 1
number xand 1
`} />
## Strings
Strings **do not use `.`** for concatenation. They use `++`.
<Code thpcode={`
"Hello " ++ "world."
`} />
This new operator **implicitly converts** types to string
<Code thpcode={`
"Hello " ++ 322 // 322 will be converted to "322"
`} />
## Boolean
These operators work **only with booleans**, they do not perform
type coercion.
<Code thpcode={`
c1 && c2
c1 || c2
`} />
## Ternary
There is no ternary operator. See [Conditionals](/learn/flow-control/conditionals) for alternatives.
## Null
These are detailed in their section: [Nullable types](/learn/error-handling/null)
<Code thpcode={`
val person = some_fun()
person?.name
person?.name ?? "Jane"
person?.greet?.()
if person?
{
person.name
}
`} />

View File

@ -1,98 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Variables
---
import Code from "../../../components/Code.astro"
# Variables
THP distinguishes between mutable and immutable variables.
Variables must be declared in THP to avoid issues with scoping and
to know if they are mutable/immutable.
It's a compile error to use undeclared variables.
Variable names **don't** start with a dollar sign `$`.
Variable names **must** begin with a lowercase letter or an underscore.
Then they may contain lowercase/uppercase letters, numbers and underscores.
As a regex: `[a-z_][a-zA-Z0-9_]*`
## Immutable variables
Defined with `val`, followed by a variable name and a value.
<Code level={2} thpcode={`
val surname = "Doe"
val year_of_birth = 1984
`} />
It's a compile error to attempt to modify it
<Code level={2} thpcode={`
val surname = "Doe"
surname = "Dane" // Error
`} />
### Datatype annotation
Written after the `val` keyword but before the variable name.
<Code level={2} thpcode={`
val String surname = "Doe"
val Int year_of_birth = 1984
`} />
When annotating an immutable variable the `val` keyword is optional
<Code level={2} thpcode={`
// Equivalent to the previous code
String surname = "Doe"
Int year_of_birth = 1984
`} />
This means that if a variable only has a datatype, it is immutable.
It is a compile error to declare a variable of a datatype,
but use another.
<Code level={2} thpcode={`
// Declare the variable as a String, but use a Float as its value
String capital = 123.456
`} />
## Mutable variables
Defined with `var`, followed by a variable name and a value.
<Code level={2} thpcode={`
var name = "John"
var age = 32
age = 33
`} />
### Datatype annotation
Written after the `var` keywords but before the variable name.
<Code level={2} thpcode={`
var String name = "John"
var Int age = 32
`} />
When annotating a mutable variable the keyword `var` is still **required**.
<Code level={2} thpcode={`
// Equivalent to the previous code
var String name = "John"
var Int age = 32
`} />

View File

@ -1,230 +0,0 @@
---
layout: ../../layouts/DocsLayout.astro
title: Cheatsheet
disable_container: true
---
import TwoColumn from "../../components/TwoColumn.astro"
import Code from "../../components/Code.astro"
# Language cheatsheet
Comparisons to PHP are noted.
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
<Code thpcode={`
// THP code is written directly, it's not enclosed in any ?php tag
// Single line comments are written with two slashes
/*
Multiline comments use slash-asterisk
and can be /* nested */
*/
// there is no echo, only print
// Unlike PHP, parenthesis are required
print("Hello world")
`} />
```php
<?php
// PHP requires a <?php opening tag
/*
PHP cannot nest multiline comments
/* this would be an error * /
*/
# PHP also has hash comments. THP doesn't
print "Hello world";
```
</TwoColumn>
## Variables
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
<Code no_warnings={true} thpcode={`
// THP has explicit variable declaration
// Variables don't start with a dollar sign ($)
// Variables are declared with \`var\`
var age = 32
// Immutable variables are declared with \`val\`,
// and can't be reassigned
val name = "John"
// Variables may have a datatype declaration
// This is an immutable variable with a type
String road = "Abbey road"
// This is a mutable variable with a type
var String name = "The Beatles"
`} />
```php
<?php
$age = 32;
// There is no PHP equivalent
$name = "John";
// You can't annotate the type of a variable in PHP
$road = "Abbey road";
$name = "The Beatles";
```
</TwoColumn>
## Datatypes
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
<Code no_warnings={true} thpcode={`
// Only double quotes, never single quotes
String name = "Jane"
// Interpolation
String full_name = "{name} Doe"
Int age = 25
Float interest = 3.22
// An integer with a leading zero is an error,
// you must use \`0o\` for octal
// Int invalid = 0755
Int valid = 0o755
// Case sensitive, only \`true\` or \`false\`
Bool has_a_cute_dress = true
`} />
```php
$name = 'Jane';
$full_name = "$name Doe";
$age = 25;
$interest = 3.22;
$invalid = 0755;
$valid = 0o755;
// PHP allows true/false in any case, for some reason
$has_a_cute_dress = TrUe;
```
</TwoColumn>
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
<Code no_warnings={true} thpcode={`
// String concatenation uses \`++\`
print("Hello " ++ "world")
// Basic operators
var res = 1 + 2 - 3 * 4 % 5
res += 2
res -= 2
res *= 2
res /= 2
res %= 2
// There are no prefix/postfix increment/decrement
//
//
`} />
```php
print("Hello " . "world");
$res = 1 + 2 - 3 * 4 % 5;
res += 2;
res -= 2;
res *= 2;
res /= 2;
res %= 2;
++res;
res--;
```
</TwoColumn>
## Flow control
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
<Code no_warnings={true} thpcode={`
// Parenthesis not required, braces required
if age < 18
{
print("Not allowed")
}
else if age == 18
{
print("Allowed, barely")
}
else
{
print("Allowed")
}
// Conditionals are expressions
val gift = if prefers_silver
{
"silver necklace"
}
else
{
"gold necklace"
}
`} />
```php
if (age < 18) {
print("Not allowed");
} else if (age === 18) {
print("Allowed, barely");
} else {
print("Allowed");
}
$gift = "";
if (prefers_silver) {
$gift = "silver necklace";
} else {
$gift = "gold necklace";
}
```
</TwoColumn>
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
<Code no_warnings={true} thpcode={`
`} />
```php
```
</TwoColumn>

View File

@ -1,9 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Abstract
---
import Code from "../../../components/Code.astro"
# Abstract

View File

@ -1,15 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Readonly
---
import Code from "../../../components/Code.astro"
# Readonly
<Code thpcode={`
class Caño
{
}
`} />

View File

@ -1,7 +0,0 @@
---
layout: ../../../layouts/DocsLayout.astro
title: Visibility
---
import Code from "../../../components/Code.astro"
# Visibility

View File

@ -1,251 +0,0 @@
# Idea 1
let mut x = 20
let y = 30
type Something = ...
Something s1 = ...
Something s2 = s1
// Passes `some` by reference, but it's immutable. Cannot call mutable methods
// or use it in mutable operations
fun do_something(Something some) -> Bool {}
do_something(s1)
// Passes `some` by reference, and it's mutable. Can call mutable methods
// or use it in mutable operations
fun do_something(&Something some) -> Bool {}
do_something(&s1)
let mut arr1 = Array(10, 20, 30)
let mut arr2 = &arr1
Owned/Reference Mutable
Type Owned n
&Type Reference n
mut Type Owned y
&mut Type Reference y
Copy/Reference Mutable Equivalent
Some Copy n 1 (technically) references the other data
&Some Reference n 1 References the other data
mut Some Copy y 2 Creates a __mutable__ copy
&mut Some Reference y 3 References the other data, __mutable__
## `Array[A]::map`
```thp
fun map[B](this, (A) -> B callback) -> Array[B]
```
Applies `callback` to all the elements of this array, and
returns those new values in a new array.
### Example
```thp
let numbers = Array(1, 2, 3, 4, 5)
let numbers_squared = numbers.map {it ** 2}
print(numbers_squared) // Array(1, 4, 9, 16, 25)
numbers.map(fun(v) {
v - 2
})
```
## `Array[A]::reduce`
```thp
fun reduce[B](
this,
B initial,
(A previous, B current) -> B callback,
) -> B
```
Iteratively reduce the array to a single value using `callback`.
### Example
```thp
let numbers = Array(1, 2, 3, 4, 5)
let sum = numbers.reduce(0, \+)
let sum = numbers.reduce(0) {$1 + $2}
let sum = numbers.reduce(0, fun(prev, curr) {prev + curr})
print(sum) // 15
```
```thp
let numbers = Array(1, 2, 3, 4, 5)
let sum = numbers.reduce("", fun(prev, curr) {prev + curr})
let sum = numbers.reduce("") {prev, curr -> prev + curr}
print(sum) // "12345"
```
```thp
// Functor
fun fmap(
(A) -> B,
f[A],
) -> f[B]
fun (<$)(
A,
f[B],
) -> f[A]
// Applicative
fun pure(A) -> f[A]
fun (<*>)(
f[A -> B],
f[A],
) -> f[B]
fun (*>)(
f[_],
f[B],
) -> f[B]
fun (<*)(
f[A],
f[_],
) -> f[A]
// Monad
fun (>>=)[m, A, B](
m[A],
(A) -> m[B],
) -> m[B]
(Array[Int], Int -> Array[String]) -> Array[String]
let result = Array(1, 2, 3, 4, 5) >>= {Array($.into[String]())}
print(result) // Array("1", "2", "3", "4", "5")
```
```thp
Option[Int] result = "322".try_into()
Option[Int] result_halved = result >>= {Some($ / 2)}
print(result_halved) // Some(161)
Option[Int] result = "abc".try_into()
Option[Int] result_halved = result >>= {Some($ / 2)}
print(result_halved) // None
```
```thp
fun (<$>)[m, A, B](
(A) -> B,
m[A],
) -> m[B]
fun half(Int x) -> Int {
x / 2
}
Option[Int] result = "322".try_into()
Option[Int] result_halved = result <$> half
print(result_halved) // Some(161)
Option[Int] result = "abc".try_into()
Option[Int] result_halved = result <$> half
print(result_halved) // None
```
```thp
fun (>>)[A, B, C](
(A) -> B,
(B) -> C,
) -> (A) -> C
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

@ -1,305 +0,0 @@
---
layout: ../../layouts/DocsLayout.astro
title: Welcome
pagesLayout:
- path: index
- path: install
- path: cheatsheet
- path: basics
title: Basics
children:
- path: hello-world
- path: comments
- path: variables
- path: datatypes
- path: operators
- path: flow-control
title: Flow control
children:
- path: conditionals
- path: loops
- path: match
- path: blocks
- path: data-structures
title: Data structures
children:
- path: tuples
- path: arrays
- path: maps
- path: enums
- path: unions
- path: functions
title: Functions
children:
- path: declaration
- path: parameters
- path: higher-order
- path: lambdas
- path: error-handling
title: Error handling
children:
- path: "null"
- path: try
- path: classes
title: Classes
children:
- path: definition
- path: constructor
- path: inheritance
- path: static
- path: visibility
- path: readonly
- path: abstract
- path: interfaces
- path: anonymous
- path: magic
- path: templating
title: Templating
children:
- path: intro
- path: components
- path: props
- path: control-flow
---
import InteractiveCode from "../../components/InteractiveCode.astro";
import Code from "../../components/Code.astro"
# Welcome
Welcome to the documentation of the THP programming languague.
THP is a new programming language that compiles to PHP.
![Accurate visual description of THP](/img/desc_thp.jpg)
This page details the main design desitions of the language,
if you want to install THP go to the [installation guide](install)
## Why?
PHP is an old language. It has been growing since 1995, adopting a
lot of features from many places like C, Perl, Java, etc. This was
done in a very inconsistent way, as detailed by Eevee in their article
[PHP: a fractal of bad design.](https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/)
Along the years PHP has been improving. PHP added classes, exceptions,
interfaces, traits, type hints and checks, functional features,
reflection, etc., etc. However, by building on top of the existing
language without a clear design philosophy, and by keeping backwards
compatibility, we ended up with a messy language. The article
above goes into detail about this.
In spite of this, PHP has remained widely used and loved, in a
weird way (I'd say in the same way that people love JavaScript),
and at the time of writing PHP 8.3 is available. However,
PHP is to my eyes fundamentally flawed, and cannot get up to
date without completely breaking what came before.
This is where THP comes in. I wanted a modern language
that could run in the same environment that PHP does.
And I quickly realized that building on top of PHP
in the same way that TypeScript did for JavaScript would be
detrimental. It would be better to create a completely new
language, treat PHP source code as a "low level" compilation
target, and focus entirely on the new language.
This new language would be mainly inspired by what **I** consider the best
designed languages out there: Rust as a baseline, Zig for
its null and error handling and Kotlin for its OOP features.
In a way, PHP will be adapted to, say, Rust's syntax and semantics,
instead of having Rust adapt to PHP.
In pursue of this THP **will** ditch many things about PHP,
in name of consistency. These are things that PHP devs are
used to doing, but that I consider bad practices, hacks or
workarounds. One example of this are variable variables on PHP:
`$$variable`.
Another critical point of THP is type safety. It is a goal
to approach the same level of type safety that have compiled
languages like Java/Go/Rust, and leave aside dynamic typing
as much as possible. Types cannot be turned off, you cannot
use `Any` to avoid typechecking, and so on.
Finally, there are some additions to the language that I consider
essential today: A good, unified LSP, type definitions,
accesible documentation, an opinionated code formatter
and plugins for major editors like VSCode and Neovim.
## Goals
- Bring static typing to PHP: Generics, type checks at compile and runtime, etc.
- Reduce implicit type conversion to a minimum.
- Remove the inconsistencies in the language.
- Organize the PHP stdlib.
- Have a clear distinctions between Arrays, Tuples, Maps and Sets.
- Implement Union types
- Create a **consistent** language.
- Have typings for popular libraries (like TS's `.d.ts`).
- Have a simple instalation and configuration (requiring just Composer or a binary).
- Ship a **_blazingly fast_**, native binary, ~~written in Rust~~ now rewritten in Zig!.
- Support in-place compilation.
- Implement a Language Server.
- Implement an opinionated code formatter.
![Friendship ended with Rust, now Zig is my best friend.](/img/mudasir.jpg)
## Not goals
These are **not** things that THP wants to solve or implement
- Be what TypeScript is for JavaScript (PHP with types).
- Strictly adhere to PHP syntax/conventions.
THP **_intentionally_** uses a different syntax from PHP to signal
that it is a different language, and has different semantics.
## Some differences with PHP
```php
// PHP
$has_key = str_contains($haystack, 'needle');
print("has key? " . $has_key);
```
<Code thpcode={`
// THP
val has_key = haystack.contains("needle")
print("has key? " + has_key)
`} />
- Explicit variable declaration
- No `$` for variable names (and thus no `$$variable`, use a map instead)
- No semicolons
- Use methods on common datatypes
- Strings use only double quotes
- String concatenation with `+`
<br/>
<br/>
```php
// PHP
$obj = [
'names' => ['Toni', 'Stark'],
'age' => 33,
'numbers' => [32, 64, 128]
]
```
<Code thpcode={`
// THP
val obj = .{
names: #("Toni", "Stark"), // Tuple
age: 33,
numbers: [32, 64, 128]
}
`} />
- Tuples, Arrays, Sets, Maps are clearly different
- JSON-like object syntax
<br/>
<br/>
```php
// PHP
$cat = new Cat("Michifu", 7);
$cat->meow();
```
<Code thpcode={`
// THP
val cat = Cat("Michifu", 7)
cat.meow()
`} />
- Instantiate classes without `new`
- Use dot `.` instead of arrow `->` syntax
<br/>
<br/>
```php
// PHP
use \Some\Deeply\Nested\Class
use \Some\Deeply\Nested\Interface
```
<Code thpcode={`
// THP
use Some::Deeply::Nested::{Class, Interface}
`} />
- Different module syntax
- Explicit module declaration
- PSR-4 required
- No `include`, `include_once`, `require` or `require_once`
<br/>
<br/>
Other things:
- Pattern matching
- ADTs
## Runtime changes
Where possible THP will compile to available PHP functions/classes/methods/etc.
For example:
<Code thpcode={`
// This expression
val greeting =
match get_person()
case Some(person) if person.age > 18
{
"Welcome, {person.name}"
}
case Some(person)
{
"I'm sorry {person.name}, you need to be 18 or older"
}
case None
{
"Nobody is here"
}
`} />
```php
// 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";
}
}
else {
$greeting = "Nobody is here";
}
```
However, more advanced datatypes & helper functions will require a sort of
runtime (new classes/functions/etc) or abuse the language's syntax/semantics.

View File

@ -1,28 +0,0 @@
---
layout: ../../layouts/DocsLayout.astro
title: Install
---
# Install
**THP is technically usable.**
## From source (*nix)
Requires Rust installed.
Clone [the repo](https://git.araozu.dev/fernando/thp) and run
`cargo build --release`. You'll have a `thp` binary on
`target/release/thp`, run it and see for yourself.
## Binary
Goal: Install THP with a single binary. Assumes that php and composer is
available.
## With composer
TBD: Install THP with `composer require thp`