Compare commits

...

5 Commits

Author SHA1 Message Date
2eb6e13d32 Add Outfit as display font 2024-07-13 17:27:07 -05:00
bfeb065c68 Add page for Array.concat 2024-07-12 19:15:07 -05:00
3584c6d798 Fixes is std 2024-07-11 21:59:38 -05:00
07ff7ede1e restore old lexer 2024-07-05 19:51:50 -05:00
a542071af9 Use the native lexer instead of a TS reimplementation 2024-07-05 19:12:30 -05:00
19 changed files with 457 additions and 140 deletions

1
.env.example Normal file
View File

@ -0,0 +1 @@
THP_BINARY=/path/to/rust/thp/binary

View File

@ -4,9 +4,9 @@
line-height: 2.5rem;
margin-bottom: 1rem;
margin-top: 2rem;
font-family: Inter, sans-serif;
font-family: Outfit, Inter, sans-serif;
opacity: 0.9;
font-weight: 900;
font-weight: 700;
color: var(--c-text-2);
}
@ -16,23 +16,41 @@
line-height: 2rem;
margin-bottom: 1rem;
margin-top: 2.5rem;
font-family: Inter, sans-serif;
font-family: Outfit, Inter, sans-serif;
opacity: 0.9;
font-weight: 700;
font-weight: 600;
color: var(--c-text-2);
}
.markdown h2::before {
content: "#";
display: block;
height: 0;
position: relative;
right: 1.5rem;
opacity: 0.2;
}
.markdown h3 {
font-size: 1.35rem;
line-height: 1.75rem;
margin-bottom: 1rem;
margin-top: 1.75rem;
font-family: Inter, sans-serif;
font-family: Outfit, Inter, sans-serif;
opacity: 0.9;
font-weight: 600;
font-weight: 400;
color: var(--c-text-2);
}
.markdown h3::before {
content: "##";
display: block;
height: 0;
position: relative;
right: 2.25rem;
opacity: 0.1;
}
.markdown ul {
list-style-type: disc;
list-style-position: inside;
@ -49,7 +67,11 @@
background: var(--code-theme-bg-color);
}
.markdown a {
.markdown > p > a {
color: var(--c-link);
text-decoration: underline;
}
.markdown blockquote {
color: red
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -2,31 +2,52 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="76.347305mm"
width="76.347313mm"
height="76.400658mm"
viewBox="0 0 76.347306 76.400657"
viewBox="0 0 76.347314 76.400657"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="thp_2_logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showguides="true"
inkscape:zoom="2"
inkscape:cx="157"
inkscape:cy="166"
inkscape:window-width="1906"
inkscape:window-height="1040"
inkscape:window-x="3"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2">
<path
d="m 26.237336,46.619443 v 4.907545 h -3.808557 v 9.796139 q 0,1.648482 1.686376,1.648482 0.341065,0 0.947402,-0.07579 0.625286,-0.09474 0.890559,-0.151585 l 0.852663,4.812802 q -1.117936,0.322117 -2.160079,0.435806 -1.042142,0.113689 -1.970596,0.113689 -3.372753,0 -5.115973,-1.572689 -1.74322,-1.591635 -1.74322,-4.623321 V 51.526988 H 13.0116 v -4.907545 h 2.804311 v -5.04018 h 6.612868 v 5.04018 z m 10.156152,9.095063 v 12.088855 h -6.612866 v -28.23259 h 6.48023 v 11.25514 q 0.852662,-2.046391 2.425351,-3.259064 1.591635,-1.212675 4.054882,-1.212675 3.315907,0 5.324401,2.179026 2.008492,2.179024 2.008492,5.779154 V 67.803361 H 43.461112 V 55.600817 q 0,-1.781114 -0.909508,-2.785361 -0.909505,-1.023194 -2.539037,-1.023194 -1.610585,0 -2.614832,1.04214 -1.004247,1.023197 -1.004247,2.880104 z m 18.03854,20.009138 V 46.619443 h 6.537076 v 3.638026 h 0.227378 q 0.397909,-0.947401 1.155832,-1.837962 0.75792,-0.909506 1.951649,-1.477947 1.193726,-0.587388 2.880103,-0.587388 2.235867,0 4.149622,1.174779 1.932699,1.174779 3.107478,3.58118 1.193726,2.406402 1.193726,6.12022 0,3.600128 -1.155829,6.025478 -1.136883,2.406402 -3.069585,3.638024 -1.913752,1.212675 -4.263308,1.212675 -2.425351,0 -3.884351,-1.136883 -1.44005,-1.155829 -2.065337,-2.59588 H 61.044897 V 75.723644 Z M 64.891351,62.952659 q 1.913753,0 2.918,-1.572686 1.023194,-1.572689 1.023194,-4.149622 0,-2.576936 -1.023194,-4.130675 -1.004247,-1.572688 -2.918,-1.572688 -1.894805,0 -2.955896,1.534792 -1.042143,1.534792 -1.042143,4.168571 0,2.59588 1.042143,4.168569 1.061091,1.553739 2.955896,1.553739 z"
id="path2"
style="font-weight:800;font-size:38.8056px;font-family:Inter;-inkscape-font-specification:'Inter Ultra-Bold';display:none;fill:#ffffff;stroke:#f472b6;stroke-width:0"
aria-label="thp" />
<path
id="lpe_path-effect2"
style="font-weight:800;font-size:38.8056px;font-family:Inter;-inkscape-font-specification:'Inter Ultra-Bold';fill:#ffffff;stroke:#f472b6;stroke-width:0"
class="powerclip"
d="M -4.9871546,-4.9877447 H 81.335912 V 81.335322 H -4.9871546 Z M 26.237336,46.619443 h -3.808557 v -5.04018 h -6.612868 v 5.04018 H 13.0116 v 4.907545 h 2.804311 v 10.383533 q 0,3.031686 1.74322,4.623321 1.74322,1.572689 5.115973,1.572689 0.928454,0 1.970596,-0.113689 1.042143,-0.113689 2.160079,-0.435806 l -0.852663,-4.812802 q -0.265273,0.05685 -0.890559,0.151585 -0.606337,0.07579 -0.947402,0.07579 -1.686376,0 -1.686376,-1.648482 v -9.796139 h 3.808557 z m 10.156152,9.095063 q 0,-1.856907 1.004247,-2.880104 1.004247,-1.04214 2.614832,-1.04214 1.629532,0 2.539037,1.023194 0.909508,1.004247 0.909508,2.785361 v 12.202544 h 6.612866 V 54.312352 q 0,-3.60013 -2.008492,-5.779154 -2.008494,-2.179026 -5.324401,-2.179026 -2.463247,0 -4.054882,1.212675 -1.572689,1.212673 -2.425351,3.259064 v -11.25514 h -6.48023 v 28.23259 h 6.612866 z m 18.03854,20.009138 h 6.612869 V 64.373765 h 0.151585 q 0.625287,1.440051 2.065337,2.59588 1.459,1.136883 3.884351,1.136883 2.349556,0 4.263308,-1.212675 1.932702,-1.231622 3.069585,-3.638024 1.155829,-2.42535 1.155829,-6.025478 0,-3.713818 -1.193726,-6.12022 -1.174779,-2.406401 -3.107478,-3.58118 -1.913755,-1.174779 -4.149622,-1.174779 -1.686377,0 -2.880103,0.587388 -1.193729,0.568441 -1.951649,1.477947 -0.757923,0.890561 -1.155832,1.837962 H 60.969104 V 46.619443 H 54.432028 Z M 64.891351,62.952659 q 1.913753,0 2.918,-1.572686 1.023194,-1.572689 1.023194,-4.149622 0,-2.576936 -1.023194,-4.130675 -1.004247,-1.572688 -2.918,-1.572688 -1.894805,0 -2.955896,1.534792 -1.042143,1.534792 -1.042143,4.168571 0,2.59588 1.042143,4.168569 1.061091,1.553739 2.955896,1.553739 z" />
</clipPath>
<inkscape:path-effect
effect="powerclip"
id="path-effect2"
is_visible="true"
lpeversion="1"
inverse="true"
flatten="false"
hide_clip="false"
message="Use fill-rule evenodd on &lt;b&gt;fill and stroke&lt;/b&gt; dialog if no flatten result after convert clip to paths." />
</defs>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="display:none;fill:#1a1a1a;fill-opacity:1;stroke:#f472b6;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
@ -36,15 +57,9 @@
x="0.001250195"
y="0.0017838299" />
<path
style="fill:#f472b6;fill-opacity:1;stroke:#f472b6;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
id="rect1"
width="76.323067"
height="76.323067"
x="0.01284539"
y="0.012255264"
rx="5.2916665"
ry="5.2916665"
clip-path="url(#clipPath2)"
d="M 5.3045119,0.01225526 H 71.044246 c 2.931583,0 5.291666,2.36008324 5.291666,5.29166654 V 71.043655 c 0,2.931584 -2.360083,5.291667 -5.291666,5.291667 H 5.3045119 c -2.9315832,0 -5.29166651,-2.360083 -5.29166651,-5.291667 V 5.3039218 c 0,-2.9315833 2.36008331,-5.29166654 5.29166651,-5.29166654 z" />
clip-path="none"
style="fill:#f472b6;fill-opacity:1;stroke:#f472b6;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
d="M 5.3045858 0.012402344 C 2.3730055 0.012402344 0.012919108 2.3724887 0.012919108 5.304069 L 0.012919108 71.043726 C 0.012919108 73.975306 2.3730055 76.335392 5.3045858 76.335392 L 71.044242 76.335392 C 73.975823 76.335392 76.335909 73.975306 76.335909 71.043726 L 76.335909 5.304069 C 76.335909 2.3724887 73.975823 0.012402344 71.044242 0.012402344 L 5.3045858 0.012402344 z M 33.009355 39.365039 L 38.94646 39.365039 L 38.94646 50.102368 C 39.321997 49.768449 39.728897 49.467499 40.188245 49.221802 C 41.300671 48.600912 42.581646 48.290592 44.030387 48.290592 C 45.504999 48.290592 46.798344 48.600912 47.910771 49.221802 C 49.023196 49.81682 49.876836 50.657573 50.471855 51.744128 C 51.092743 52.804813 51.403064 54.046612 51.403064 55.469482 L 51.403064 67.537996 L 45.465959 67.537996 L 45.465959 56.788782 C 45.465959 55.805707 45.155639 55.01702 44.534749 54.422001 C 43.939731 53.801112 43.1763 53.490275 42.244967 53.490275 C 41.598207 53.490275 41.029114 53.632549 40.537577 53.917122 C 40.04604 54.175826 39.657881 54.563985 39.373307 55.081392 C 39.088733 55.57293 38.94646 56.142022 38.94646 56.788782 L 38.94646 67.537996 L 33.009355 67.537996 L 33.009355 39.365039 z M 20.203418 40.878642 L 26.14104 40.878642 L 26.14104 48.678682 L 30.409513 48.678682 L 30.409513 53.723336 L 26.14104 53.723336 L 26.14104 67.537996 L 20.203418 67.537996 L 20.203418 53.723336 L 15.934945 53.723336 L 15.934945 48.678682 L 20.203418 48.678682 L 20.203418 40.878642 z M 66.071936 48.290592 C 67.856992 48.290592 69.434885 48.717412 70.806014 49.571134 C 72.203015 50.424857 73.289652 51.588817 74.065763 53.063428 C 74.867745 54.538039 75.268791 56.219544 75.268791 58.108081 C 75.268791 59.996618 74.867745 61.67864 74.065763 63.153251 C 73.289652 64.627862 72.203015 65.791822 70.806014 66.645544 C 69.434885 67.499267 67.856992 67.926086 66.071936 67.926086 C 64.804288 67.926086 63.639812 67.680201 62.579126 67.188664 C 62.019518 66.929333 61.517632 66.616566 61.06604 66.256421 L 61.06604 75.493066 L 55.206449 75.493066 L 55.206449 48.678682 L 61.143555 48.678682 L 61.143555 49.980929 C 61.574458 49.628464 62.0526 49.323615 62.579126 49.066772 C 63.639812 48.549365 64.804288 48.290592 66.071936 48.290592 z M 65.023938 53.645821 C 64.196086 53.645821 63.458946 53.839642 62.812187 54.227698 C 62.191298 54.589883 61.699527 55.107428 61.337341 55.780058 C 60.975156 56.452688 60.794222 57.228489 60.794222 58.108081 C 60.794222 58.961804 60.962269 59.725234 61.298584 60.397864 C 61.660769 61.070494 62.165427 61.600926 62.812187 61.988981 C 63.458946 62.377037 64.183199 62.570858 64.985181 62.570858 C 65.838902 62.570858 66.576043 62.377037 67.196932 61.988981 C 67.843691 61.600926 68.34835 61.070494 68.710535 60.397864 C 69.07272 59.725234 69.253654 58.961804 69.253654 58.108081 C 69.253654 57.228489 69.07272 56.452688 68.710535 55.780058 C 68.34835 55.107428 67.843691 54.589883 67.196932 54.227698 C 66.576043 53.839642 65.85179 53.645821 65.023938 53.645821 z " />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,10 +1,10 @@
---
import { leftTrimDedent } from "./utils";
import { thp_highlighter } from "../lexer/highlighter";
import { native_highlighter } from "../lexer/highlighter";
const { thpcode } = Astro.props;
const html_code = thp_highlighter(leftTrimDedent(thpcode).join("\n"));
const native_html = await native_highlighter(thpcode);
---
<pre
class="language-thp"><code class="language-thp" set:html={html_code} /><span class="absolute top-2 right-2 inline-block text-sm select-none opacity-75">thp</span></pre>
class="language-thp"><code class="language-thp" set:html={native_html} /><span class="absolute top-2 right-2 inline-block text-sm select-none opacity-75">thp</span></pre>

View File

@ -18,7 +18,7 @@ if (!title) {
<div>
<div class="bg-c-thp text-c-bg">
<h1 class="container mx-auto font-medium py-8 text-3xl">
<h1 class="container mx-auto font-medium py-8 text-3xl font-display">
{subtitle} <span class="font-black">{title}</span>
</h1>
</div>

View File

@ -16,9 +16,12 @@ function buildHierarchy(headings: any) {
const heading = { ...h, subheadings: [] };
parentHeadings.set(heading.depth, heading);
// Change 2 to 1 if your markdown includes your <h1>
if (heading.depth === 1) {
if (heading.depth === 2) {
toc.push(heading);
} else {
} else if (heading.depth === 1) {
/** empty */
}
else {
parentHeadings.get(heading.depth - 1).subheadings.push(heading);
}
});

View File

@ -0,0 +1,9 @@
---
import { native_highlighter } from "../../lexer/highlighter";
const { thpcode, href } = Astro.props;
const native_html = await native_highlighter(thpcode);
---
<a href={href} class="inline-block w-full py-2 font-mono whitespace-pre" set:html={native_html} />

View File

@ -0,0 +1,4 @@
<div class="my-6 px-4 py-2 rounded bg-red-200 dark:bg-red-950">
<div class="font-bold pt-2">Warning</div>
<slot />
</div>

View File

@ -24,6 +24,7 @@ const { headings } = Astro.props;
class="py-[3.5rem] lg:pl-12 lg:pr-4 markdown min-w-0 small-container mx-auto"
>
<slot />
<div class="h-32"></div>
</main>
<div
@ -38,6 +39,4 @@ const { headings } = Astro.props;
</nav>
</div>
</div>
<div class="h-32"></div>
</BaseLayout>

View File

@ -24,11 +24,7 @@ const { title } = Astro.props;
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500;600;700;800;900&family=Fira+Code&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Outfit:wght@100..900&display=swap"
rel="stylesheet"
/>
</head>
@ -37,5 +33,9 @@ const { title } = Astro.props;
<slot />
<script src="/js/alpine-3.14.0.min.js" defer></script>
<script>
import { highlightOnDom } from "./thpHighlighter";
document.addEventListener("DOMContentLoaded", highlightOnDom);
</script>
</body>
</html>

View File

@ -7,7 +7,7 @@ export function highlightOnDom() {
// Create a visual indicador
const indicator = document.createElement("span");
indicator.className = "absolute top-2 right-2 inline-block text-sm select-none opacity-75";
indicator.className = `absolute top-1 right-0 inline-block text-sm select-none opacity-75 ${language === "php" ? "bg-[#4f5b93]" : ""} px-2 rounded-full`;
indicator.innerText = language;
pre_el.appendChild(indicator);
}

View File

@ -1,13 +1,148 @@
import { lex } from "./lexer";
import { spawn } from "node:child_process";
import { leftTrimDedent } from "../components/utils";
export function thp_highlighter(code: string) {
let tokens = lex(code);
export interface LexResult {
Ok?: Token[]
Err?: Err
}
let highlighted_code = "";
export interface Token {
token_type: TokenType
value: string
position: number
}
for (let token of tokens) {
highlighted_code += `<span class="token ${token.token_type}">${token.v}</span>`;
type TokenType =
"Identifier" |
"Datatype" |
"Int" |
"Float" |
"String" |
"Operator" |
"LeftParen" |
"RightParen" |
"LeftBracket" |
"RightBracket" |
"LeftBrace" |
"RightBrace" |
"NewLine" |
"Comment" |
"Comma" |
"INDENT" |
"DEDENT" |
"VAL" |
"VAR" |
"EOF" |
"FUN";
export interface Err {
Lex: LexError
}
export interface LexError {
position: number
reason: string
}
export async function native_highlighter(code: string): Promise<string> {
let formatted_code = leftTrimDedent(code).join("\n");
const result = await native_lex(formatted_code);
if (result.Err) {
throw new Error(JSON.stringify(result.Err.Lex) + "\n" + code);
}
return highlighted_code;
const tokens = result.Ok!;
const input_chars = formatted_code.split("");
let output = "";
let current_pos = 0;
for (let i = 0; i < tokens.length; i += 1) {
const t = tokens[i]!;
const token_start = t.position;
const token_end = t.position + t.value.length;
// There are some tokens that are empty, ignore them
if (t.value == "") {
continue;
}
// Append all characters before the token
output += input_chars.slice(current_pos, token_start).join("");
// Append the token
const token_value = t.value.replaceAll(/</g, "&lt;").replaceAll(/>/g, "&gt;");
const token_type = translate_token_type(t.token_type, token_value);
output += `<span class="token ${token_type}">${token_value}</span>`;
current_pos = token_end;
}
return output;
}
function translate_token_type(tt: TokenType, value: string): string {
const keywords = ["throws", "extends", "constructor", "case", "static", "const", "enum", "union", "loop", "use", "break", "catch", "continue", "as", "do", "else", "finally", "for", "fun", "if", "in", "fn", "nil", "return", "throw", "try", "while", "type", "match", "with", "of", "abstract", "class", "interface", "private", "pub", "override", "open", "init", "val", "var", "mut", "clone"];
switch (tt) {
case "Datatype":
return "class-name";
case "Identifier": {
if (keywords.includes(value)) {
return "keyword";
}
return "identifier";
}
case "Int":
return "number";
case "Float":
return "number";
case "String":
return "string";
case "Comment":
return "comment";
// keywords:
case "VAL":
case "VAR":
case "FUN":
return "keyword";
default:
return tt;
}
}
const native_lex = (code: string) => new Promise<LexResult>((resolve, reject) => {
// Get binary path from .env
const binary = import.meta.env.THP_BINARY;
if (!binary) {
throw new Error("THP_BINARY not set in .env");
}
const subprocess = spawn(binary, ["tokenize"]);
let response = "";
let error = "";
subprocess.stdin.write(code);
subprocess.stdin.end();
subprocess.stdout.on("data", (data) => {
response += data.toString();
});
subprocess.stderr.on("data", (data) => {
error += data.toString();
});
subprocess.on("close", (code) => {
if (code === 0) {
resolve(JSON.parse(response));
} else {
reject(error);
}
});
})

View File

@ -2,6 +2,9 @@
layout: ../../../layouts/ApiLayout.astro
---
import TwoColumn from "../../../components/TwoColumn.astro"
import Code from "../../../components/Code.astro"
import CodeMin from "../../../components/docs/CodeMin.astro"
import Warning from "../../../components/docs/Warning.astro"
# Array
@ -16,39 +19,38 @@ THP arrays are 0-indexed.
## Signature
```thp
<Code thpcode={`
type Array[T] = Map[Int, T]
```
`} />
Where `T` is the datatype that the Array stores. For example:
```thp
<Code thpcode={`
Array[Int] // An array of integers
Array[Float] // An array of floats
Array[Array[String]] // A 2-dimensional array of strings
```
`} />
## PHP array internals
<Warning>
TL;DR: **Never** assign to an array using an invalid index. If you do
the program will not crash, but it will not behaved as expected
the program will not crash, instead it will not behaved as expected
[(this is a common problem in PHP)](https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/).
THP tries its best to solve such behavior.
---
</Warning>
Since THP compiles down to PHP, it's important to understand how PHP
represents arrays internally.
PHP doesn't have arrays. Instead, PHP has ordered maps and syntax sugar
to make them look like arrays.
When declaring an array like:
```thp
<Code thpcode={`
var arr = ["a", "b", "c"]
```
`} />
in reality what goes into memory is a map with numbers as keys:
@ -75,7 +77,7 @@ Invalid indexes are:
PHP maps preserve insertion order. This means that when iterating over
a PHP map, values are processed in FIFO.
```thp
<Code thpcode={`
var numbers = ["a", "b", "c"]
numbers[-10] = "?" // Assign to a negative index
@ -127,7 +129,7 @@ numbers.push("/") // This will be at position 8
// -4: "???",
// 8: "/",
// }
```
`} />
This is one of many fundamental flaws with PHP. The only way to solve it
would be to check every insertion at runtime, and this would have a
@ -146,59 +148,59 @@ abstraction, as if all indexes were valid.
To create an empty array use square brackets.
If you create an empty array, you need to specify the datatype.
```thp
<Code thpcode={`
Array[Int] empty = []
```
`} />
### Creation
To create an array use square brackets notation:
```thp
<Code thpcode={`
val numbers = [0, 1, 2, 3, 4, 5]
```
`} />
When the array is not empty, you don't need to specify a datatype.
When the Array is declared over many lines, the last
item should have a trailing comma:
```thp
<Code thpcode={`
val colors = [
"red",
"blue",
"green", // trailing comma
]
```
`} />
If it doesn't, the code formatter will automatically
insert one for you.
### Assignment
### Assignment to elements
Use square brackets notation to insert into an array or modify it:
To modify an array it must be mutable, that is, assigned to a `var`
instead of a `val`.
```thp
// This array cannot be modified, as it's declared with `val`
<Code thpcode={`
// This array cannot be modified, as it's declared with \`val\`
val immutable = [1, 2, 3]
// This is a compile time error
immutable[0] = 322
// This array can be modified, as it's declared with `var`
// This array can be modified, as it's declared with \`var\`
var mutable = [1, 2, 3]
// Ok
mutable[0] = 322
```
`} />
To append an element to an array, use the method `push()`:
```thp
<Code thpcode={`
mutable.push(4)
```
`} />
Do not insert into an invalid index. See [PHP array internals](#php-array-internals) to learn why.
@ -207,28 +209,58 @@ Do not insert into an invalid index. See [PHP array internals](#php-array-intern
Use a `for` loop to iterate over the elements of an array:
```thp
<Code thpcode={`
val colors = ["red", "green", "blue"]
for #(_index, c) in colors
for c in colors
{
print("{c} ")
}
```
`} />
```sh
red green blue
```
A for loop automatically declares new immutable variables. It is a compile
error to attempt to modify those, as in the following snippet:
<Code thpcode={`
val colors = ["red", "green", "blue"]
for c in colors
{
c = "orange" // Compile error: Can't assign to an immutable variable
print("{c} ")
}
`} />
You can also declare an index along with the value:
<Code thpcode={`
val colors = ["red", "green", "blue"]
for index, color in colors
{
println("item {index}: {c}")
}
`} />
```sh
item 0: red
item 1: green
item 2: blue
```
### Access
To access a value of the array use square brackets notation:
```thp
<Code thpcode={`
print(colors[0])
```
`} />
Since the index might not exist, this will return a
[nullable type](/learn/error-handling/null/) that you have to handle.
@ -240,6 +272,17 @@ THP arrays don't have destructuring, since the values can all be `null`.
If you know that the number of elements is fixed and valid, use Tuples instead.
### Operators
While PHP allows using certain operators with arrays, THP disallows that.
Methods that perform comparisons should be used instead.
### Assignment
// TODO: Detail that assignment of arrays is copy on write
## Methods
In the parameters, <code class="token keyword">self</code> is the array to operate on.
@ -253,25 +296,26 @@ In the parameters, <code class="token keyword">self</code> is the array to opera
<tbody>
<tr class="dark:odd:bg-zinc-900 odd:bg-stone-200">
<td class="px-2">
<p class="font-mono whitespace-pre">
<span class="token keyword">fun </span>
<span class="token function">filter</span>
<span>[</span>
<span class="token class">T</span>
<span>]</span>
<span>(</span>
<br/>
<span class="token keyword"> self</span>
<span>,</span>
<br />
<span> (T) -> Bool callback,</span>
<br />
<span>)-> </span>
<span class="token class">Array</span>
<span>[</span>
<span class="token class">T</span>
<span>]</span>
</p>
<CodeMin href="./concat" thpcode={`
fun concat[T](
self,
Array[T]... arrays,
) -> Array[T]
`} />
</td>
<td>
Concatenate with other arrays, and return the result
as a new array.
</td>
</tr>
<tr class="dark:odd:bg-zinc-900 odd:bg-stone-200">
<td class="px-2">
<CodeMin thpcode={`
fun filter[T](
self,
(T) -> (Bool) callback,
) -> Array[T]
`} />
</td>
<td>
Filters elements using a callback function, and returns
@ -280,17 +324,7 @@ In the parameters, <code class="token keyword">self</code> is the array to opera
</tr>
<tr class="dark:odd:bg-zinc-900 odd:bg-stone-200">
<td class="px-2">
<p class="font-mono">
<span class="token keyword">fun </span>
<span class="token function">push</span>
<span>[</span>
<span class="token class">T</span>
<span>]</span>
<span>(</span>
<span class="token keyword">self</span>
<span>, T ...elements) -> </span>
<span class="token class">Int</span>
</p>
<CodeMin thpcode="fun push[T](self, T... elements) -> Int" />
</td>
<td>
Appends one or more elements to the end of the array.
@ -299,17 +333,7 @@ In the parameters, <code class="token keyword">self</code> is the array to opera
</tr>
<tr class="dark:odd:bg-zinc-900 odd:bg-stone-200">
<td class="px-2">
<p class="font-mono">
<span class="token keyword">fun </span>
<span class="token function">pop</span>
<span>[</span>
<span class="token class">T</span>
<span>]</span>
<span>(</span>
<span class="token keyword">self</span>
<span>) -> </span>
<span class="token class">T</span>
</p>
<CodeMin thpcode="fun pop[T](self) -> T" />
</td>
<td>
Removes the last value of the array, and returns it.
@ -319,4 +343,3 @@ In the parameters, <code class="token keyword">self</code> is the array to opera
</table>

View File

@ -0,0 +1,112 @@
---
layout: ../../../../layouts/ApiLayout.astro
---
import Code from "../../../../components/Code.astro"
# `Array.concat`
Concatenate with other arrays, and return the result as a new array.
## Signature
<Code thpcode={`
fun concat[T](
self,
Array[T]... arrays,
) -> Array[T]
`} />
## Parameters
- `self`: The callee.
- `Array[T]... arrays`: Multiple arrays to concatenate the current one to.
## Return value
`Array[T]`: A new array that contains the elements from all arrays.
## Description
Concatenates the elements of the callee and the elements of each array in the
variable `array`. These values are returned in a new array.
If called without any aditional array it returns a new array with the elements
of `self`.
The returned array is a new one. However, if the elements of the callee and the
parameters are references, the returned array will contain references that point
to the same memory. This is important if, for example, the arrays contain other
arrays or objects.
## Examples
Example concatenating 2 arrays:
<Code thpcode={`
val first = [1, 2, 3]
val second = [4, 5, 6]
val result = first.concat(second)
assert_eq(result, [1, 2, 3, 4, 5, 6])
`} />
Example concatenating 3 arrays:
<Code thpcode={`
val first = ["a", "b"]
val second = ["c", "d"]
val third = ["e", "f"]
val result = first.concat(second, third)
assert_eq(result, ["a", "b", "c", "d", "e", "f"])
`} />
Example concatenating without any other array. In this case
`first` and `result` are different arrays:
<Code thpcode={`
val first = [1, 2, 3]
val result = first.concat()
assert_eq(result, [1, 2, 3])
`} />
Example concatenating an empty array with a filled array:
<Code thpcode={`
val first = []
val second = [10, 20, 30]
val result = first.concat(second)
assert_eq(result, [10, 20, 30])
`} />
## PHP interop
This method is directly compiled to `array_merge`. Since THP guarantees that
arrays only have numbers as keys, this will never produce invalid values due
to merging with an array with string keys.
If the arrays contain invalid keys (negative values, out of bounds) the merge
is performed based on the insertion order, not the keys order, and the resulting
array will have correct keys.
```php
$array_1 = [2 => "a", 0 => "b"];
$array_2 = [1 => "c"];
var_dump(array_merge($array_1, $array_2));
```
```out
array(3) {
[0]=> string(1) "a"
[1]=> string(1) "b"
[2]=> string(1) "c"
}
```

View File

@ -1,6 +0,0 @@
---
layout: ../../../../layouts/ApiLayout.astro
---
# Array.filter

View File

@ -2,7 +2,7 @@
import BaseLayout from "../layouts/BaseLayout.astro";
import Navbar from "../components/Navbar.astro";
import HeroSection from "../components/HeroSection.astro";
import { thp_highlighter } from "../lexer/highlighter";
import { native_highlighter } from "../lexer/highlighter";
import { leftTrimDedent } from "../components/utils";
const thpcode = `union Animal {
@ -118,7 +118,7 @@ case Cat(name, lives)
</svg>
<div class="h-1"></div>
<div id="editor" class="font-mono language-thp">
<pre set:html={thp_highlighter(leftTrimDedent(thpcode).join("\n"))}></pre>
<pre set:html={native_highlighter(leftTrimDedent(thpcode).join("\n"))}></pre>
</div>
</div>
</div>

View File

@ -196,7 +196,7 @@ $cat->meow();
<Code thpcode={`
// THP
val cat = Cat("Michifu", 7)
cat.meow();
cat.meow()
`} />
- Instantiate classes without `new`

View File

@ -21,7 +21,7 @@ export default {
},
fontFamily: {
"mono": ["'Iosevka Fixed Web'", "Iosevka", "'Iosevka Nerd Font'", "monospace"],
"display": ["Inter", "'Josefin Sans'", "'Fugaz One'", "sans-serif"],
"display": ["Outfit", "Inter", "sans-serif"],
"body": ["Inter", "sans-serif"],
},
},