Compare commits
3 Commits
5208496124
...
49faed4fcb
Author | SHA1 | Date | |
---|---|---|---|
49faed4fcb | |||
ebf62bcd5c | |||
631acc8122 |
10
src/components/Code.astro
Normal file
10
src/components/Code.astro
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
import { leftTrimDedent } from "./utils";
|
||||||
|
import { thp_highlighter } from "../lexer/highlighter";
|
||||||
|
|
||||||
|
const { thpcode } = Astro.props;
|
||||||
|
const html_code = thp_highlighter(leftTrimDedent(thpcode).join("\n"));
|
||||||
|
---
|
||||||
|
|
||||||
|
<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>
|
@ -1,13 +1,11 @@
|
|||||||
---
|
---
|
||||||
import { trimAndDedent } from "./utils";
|
import Code from "./Code.astro"
|
||||||
|
|
||||||
const { thpcode } = Astro.props;
|
const { thpcode } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="flex h-full py-8 items-center">
|
<div class="flex h-full py-8 items-center">
|
||||||
<div class="p-4 w-full">
|
<div class="p-4 w-full">
|
||||||
<pre
|
<Code thpcode={thpcode} />
|
||||||
class="language-thp"
|
|
||||||
data-language="thp"><code class="language-thp">{trimAndDedent(thpcode).join("\n")}</code></pre>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { lex } from "../lexer/lexer";
|
import { lex } from "../lexer/lexer";
|
||||||
import type { Instruction } from "../thp_machine/machine_parser";
|
import type { Instruction } from "../thp_machine/machine_parser";
|
||||||
import { parse_str } from "../thp_machine/machine_parser";
|
import { parse_str } from "../thp_machine/machine_parser";
|
||||||
import { trimAndDedent } from "./utils";
|
import { leftTrimDedent } from "./utils";
|
||||||
const { code, steps } = Astro.props;
|
const { code, steps } = Astro.props;
|
||||||
|
|
||||||
function highlightCode(lines: Array<string>): string {
|
function highlightCode(lines: Array<string>): string {
|
||||||
@ -31,7 +31,7 @@ function highlightCode(lines: Array<string>): string {
|
|||||||
return outLines.join("\n");
|
return outLines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeHtml = highlightCode(trimAndDedent(code));
|
const codeHtml = highlightCode(leftTrimDedent(code));
|
||||||
let instructionSet: Array<Array<Instruction>>;
|
let instructionSet: Array<Array<Instruction>>;
|
||||||
try {
|
try {
|
||||||
instructionSet = parse_str(steps);
|
instructionSet = parse_str(steps);
|
||||||
|
133
src/components/utils.test.ts
Normal file
133
src/components/utils.test.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { expect, test } from 'vitest'
|
||||||
|
import { leftTrimDedent } from "./utils"
|
||||||
|
|
||||||
|
test("should trim empty string", () => {
|
||||||
|
const input = ``;
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([""]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should work on a single line", () => {
|
||||||
|
const input = `hello`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello"
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should trim a single line", () => {
|
||||||
|
const input = ` hello`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello"
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should trim multiple lines", () => {
|
||||||
|
const input = ` hello\n world`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"world"
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should trim multiple lines without indentation", () => {
|
||||||
|
const input = `hello\nworld`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"world"
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should consume only whitespace", () => {
|
||||||
|
const input = ` hello\nworld`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = leftTrimDedent(input);
|
||||||
|
expect(res).not.toEqual([
|
||||||
|
"hello",
|
||||||
|
"rld",
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e).toBeInstanceOf(Error);
|
||||||
|
expect(e).toHaveProperty("message", "Invalid indentation while trimming: Expected 2 spaces, got 0");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should preserve deeper indentation", () => {
|
||||||
|
const input = ` hello\n world`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
" world",
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should ignore empty lines", () => {
|
||||||
|
const input = ` hello\n\n world`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"",
|
||||||
|
"world",
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should ignore lines with only whitespace", () => {
|
||||||
|
const input = ` hello\n \n \n world`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"",
|
||||||
|
" ",
|
||||||
|
"world",
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should trim multiple without indentation", () => {
|
||||||
|
const input = `hello\nworld\n!`
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
"!",
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should ignore empty first line", () => {
|
||||||
|
const input = `
|
||||||
|
hello
|
||||||
|
world`;
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should ignore empty first line 2", () => {
|
||||||
|
const input = `
|
||||||
|
hello
|
||||||
|
|
||||||
|
world`;
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"",
|
||||||
|
"world",
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
test("should ignore empty last line", () => {
|
||||||
|
const input = `
|
||||||
|
hello
|
||||||
|
world
|
||||||
|
`;
|
||||||
|
|
||||||
|
expect(leftTrimDedent(input)).toEqual([
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
]);
|
||||||
|
});
|
@ -5,15 +5,16 @@
|
|||||||
* - Picks the indentation level from the first non-white line
|
* - Picks the indentation level from the first non-white line
|
||||||
* - Dedents the following lines
|
* - Dedents the following lines
|
||||||
*/
|
*/
|
||||||
export function trimAndDedent(input: string): Array<string> {
|
export function leftTrimDedent(input: string): Array<string> {
|
||||||
let lines = input.split("\n");
|
let lines = input.split("\n");
|
||||||
|
let output: Array<string> = [];
|
||||||
|
|
||||||
// Remove empty lines at the start
|
// Ignore first line
|
||||||
while (lines[0] === "") {
|
if (lines[0] === "" && lines.length > 1) {
|
||||||
lines = lines.slice(1);
|
lines = lines.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get indentation level
|
// Get indentation level of the first line
|
||||||
let indentationLevel = 0;
|
let indentationLevel = 0;
|
||||||
for (const char of lines[0]!) {
|
for (const char of lines[0]!) {
|
||||||
if (char === " ") {
|
if (char === " ") {
|
||||||
@ -23,48 +24,37 @@ export function trimAndDedent(input: string): Array<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce indentation, or trim
|
for (const line of lines) {
|
||||||
for (let i = 0; i < lines.length; i += 1) {
|
// Ignore empty lines
|
||||||
// If the line is empty, continue
|
if (line === "") {
|
||||||
const characters = lines[i]!.split("");
|
output.push("");
|
||||||
if (characters.length === 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
output.push(trimWhitespace(line, indentationLevel));
|
||||||
// If all characters are whitespace, append just a newline
|
|
||||||
const nonWhitespace = characters.find((x) => x !== " ");
|
|
||||||
if (nonWhitespace === undefined) {
|
|
||||||
lines[i] = "";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce indentation
|
|
||||||
if (characters.length < indentationLevel) {
|
|
||||||
throw new Error("Invalid indentation while parsing THP code: " + lines[i]);
|
|
||||||
}
|
|
||||||
let currentIndentation = 0;
|
|
||||||
for (const c of characters) {
|
|
||||||
if (c === " ") { currentIndentation += 1 }
|
|
||||||
else {break;}
|
|
||||||
}
|
|
||||||
if (currentIndentation < indentationLevel) {
|
|
||||||
throw new Error("Invalid indentation while parsing THP code: " + lines[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines[i] = characters.slice(4).join("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (output.length > 1 && output[output.length - 1] === "") {
|
||||||
|
output = output.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove empty lines at the end
|
return output;
|
||||||
let endPosition = lines.length - 1;
|
}
|
||||||
while (true) {
|
|
||||||
if (lines[endPosition] === "") {
|
function trimWhitespace(input: string, count: number): string {
|
||||||
lines = lines.slice(0, -1);
|
let indentCount = 0;
|
||||||
endPosition -= 1;
|
|
||||||
|
for (const char of input) {
|
||||||
|
if (char === " ") {
|
||||||
|
indentCount += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines;
|
if (indentCount >= count || indentCount == input.length) {
|
||||||
}
|
return input.slice(count);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Invalid indentation while trimming: Expected ${count} spaces, got ${indentCount}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import Navbar from "../components/Navbar.astro";
|
|||||||
import BaseLayout from "./BaseLayout.astro";
|
import BaseLayout from "./BaseLayout.astro";
|
||||||
import TOC from "../components/TOC.astro";
|
import TOC from "../components/TOC.astro";
|
||||||
|
|
||||||
const {headings} = Astro.props;
|
const { headings } = Astro.props;
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
@ -41,9 +40,4 @@ const {headings} = Astro.props;
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="h-32"></div>
|
<div class="h-32"></div>
|
||||||
|
|
||||||
<script>
|
|
||||||
import {highlightOnDom} from "./thpHighlighter";
|
|
||||||
document.addEventListener("DOMContentLoaded", highlightOnDom);
|
|
||||||
</script>
|
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
@ -4,7 +4,13 @@ import BaseLayout from "./BaseLayout.astro";
|
|||||||
import TOC from "../components/TOC.astro";
|
import TOC from "../components/TOC.astro";
|
||||||
import Sidebar from "../components/Sidebar.astro";
|
import Sidebar from "../components/Sidebar.astro";
|
||||||
|
|
||||||
const { frontmatter, headings, posts: _posts, indexSubpath, basePath } = Astro.props;
|
const {
|
||||||
|
frontmatter,
|
||||||
|
headings,
|
||||||
|
posts: _posts,
|
||||||
|
indexSubpath,
|
||||||
|
basePath,
|
||||||
|
} = Astro.props;
|
||||||
const posts: Record<string, any>[] = _posts;
|
const posts: Record<string, any>[] = _posts;
|
||||||
|
|
||||||
const indexPage = posts.find((post) => post.file.endsWith(indexSubpath));
|
const indexPage = posts.find((post) => post.file.endsWith(indexSubpath));
|
||||||
@ -30,8 +36,10 @@ if (pagesIndex === undefined) {
|
|||||||
function validateEntry(entry: PageEntry, basePath: string) {
|
function validateEntry(entry: PageEntry, basePath: string) {
|
||||||
if (!entry.children) {
|
if (!entry.children) {
|
||||||
// Attempt to get the page title from frontmatter
|
// Attempt to get the page title from frontmatter
|
||||||
const pageData = posts.find((post) =>
|
const pageData = posts.find(
|
||||||
post.file.endsWith(entry.path + ".md") || post.file.endsWith(entry.path + ".mdx"),
|
(post) =>
|
||||||
|
post.file.endsWith(entry.path + ".md") ||
|
||||||
|
post.file.endsWith(entry.path + ".mdx"),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pageData === undefined) {
|
if (pageData === undefined) {
|
||||||
@ -112,7 +120,8 @@ for (const entry of pagesIndex) {
|
|||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
let current_uri = window.location.pathname;
|
let current_uri = window.location.pathname;
|
||||||
|
|
||||||
const sidebar = document.getElementById("sidebar")!.children[0]! as HTMLElement;
|
const sidebar = document.getElementById("sidebar")!
|
||||||
|
.children[0]! as HTMLElement;
|
||||||
const links = sidebar.querySelectorAll("a");
|
const links = sidebar.querySelectorAll("a");
|
||||||
for (const link of [...links]) {
|
for (const link of [...links]) {
|
||||||
if (link.getAttribute("href") === current_uri) {
|
if (link.getAttribute("href") === current_uri) {
|
||||||
|
@ -1,38 +1,5 @@
|
|||||||
import { thp_highlighter, CodeJar } from "../lexer/highlighter";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Highlights all THP code snippets mounted in the DOM with class .language-thp
|
|
||||||
*
|
|
||||||
* It assumes that the code is inside: <pre class="language-thp"><code>...
|
|
||||||
*/
|
|
||||||
export function highlightOnDom() {
|
export function highlightOnDom() {
|
||||||
const code_elements = document.querySelectorAll("code.language-thp");
|
|
||||||
|
|
||||||
for (const e of [...code_elements]) {
|
|
||||||
const el = e as HTMLElement;
|
|
||||||
// Some elements with .language-thp don't want to be processed
|
|
||||||
if (e.getAttribute("data-disabled") !== null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pre_parent = el.parentElement!;
|
|
||||||
const new_div = document.createElement("div");
|
|
||||||
let code = el.innerHTML;
|
|
||||||
|
|
||||||
// Replace all < with < and all > with >
|
|
||||||
code = code.replace(/</g, "<").replace(/>/g, ">");
|
|
||||||
|
|
||||||
el.parentElement!.className = "language-thp";
|
|
||||||
pre_parent.removeChild(el);
|
|
||||||
pre_parent.appendChild(new_div);
|
|
||||||
|
|
||||||
// Create and append a language name indicator
|
|
||||||
|
|
||||||
CodeJar(new_div, thp_highlighter, {
|
|
||||||
tab: " ",
|
|
||||||
}).updateCode(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
const pre_elements = document.querySelectorAll("pre");
|
const pre_elements = document.querySelectorAll("pre");
|
||||||
for (const pre_el of pre_elements) {
|
for (const pre_el of pre_elements) {
|
||||||
const language = pre_el.getAttribute("data-language");
|
const language = pre_el.getAttribute("data-language");
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { lex } from "./lexer";
|
import { lex } from "./lexer";
|
||||||
import {CodeJar as Codejar} from "codejar";
|
|
||||||
|
|
||||||
export function thp_highlighter(editor: any) {
|
|
||||||
let code: string = editor.textContent;
|
|
||||||
|
|
||||||
|
export function thp_highlighter(code: string) {
|
||||||
let tokens = lex(code);
|
let tokens = lex(code);
|
||||||
|
|
||||||
let highlighted_code = "";
|
let highlighted_code = "";
|
||||||
@ -12,7 +9,5 @@ export function thp_highlighter(editor: any) {
|
|||||||
highlighted_code += `<span class="token ${token.token_type}">${token.v}</span>`;
|
highlighted_code += `<span class="token ${token.token_type}">${token.v}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.innerHTML = highlighted_code;
|
return highlighted_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodeJar = Codejar;
|
|
||||||
|
@ -2,6 +2,28 @@
|
|||||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||||
import Navbar from "../components/Navbar.astro";
|
import Navbar from "../components/Navbar.astro";
|
||||||
import HeroSection from "../components/HeroSection.astro";
|
import HeroSection from "../components/HeroSection.astro";
|
||||||
|
import { thp_highlighter } from "../lexer/highlighter";
|
||||||
|
import { leftTrimDedent } from "../components/utils";
|
||||||
|
|
||||||
|
const thpcode = `union Animal {
|
||||||
|
Dog(String),
|
||||||
|
Cat(String, Int),
|
||||||
|
}
|
||||||
|
|
||||||
|
val cat_name = Post::get("cat_name") ?? "Michifu"
|
||||||
|
val my_cat = Animal::Cat(cat_name, 9)
|
||||||
|
|
||||||
|
try change_fur_color(cat) else die("Not a cat")
|
||||||
|
|
||||||
|
match random_animal()
|
||||||
|
case Dog(name)
|
||||||
|
{
|
||||||
|
print("{name} has 1 live ")
|
||||||
|
}
|
||||||
|
case Cat(name, lives)
|
||||||
|
{
|
||||||
|
print("{name} has {lives}")
|
||||||
|
}`;
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout>
|
<BaseLayout>
|
||||||
@ -95,7 +117,9 @@ import HeroSection from "../components/HeroSection.astro";
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<div class="h-1"></div>
|
<div class="h-1"></div>
|
||||||
<div id="editor" class="font-mono language-thp"></div>
|
<div id="editor" class="font-mono language-thp">
|
||||||
|
<pre set:html={thp_highlighter(leftTrimDedent(thpcode).join("\n"))}></pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -194,38 +218,4 @@ import HeroSection from "../components/HeroSection.astro";
|
|||||||
<br>
|
<br>
|
||||||
Nullable types must be explicitly checked before using them.
|
Nullable types must be explicitly checked before using them.
|
||||||
</HeroSection>
|
</HeroSection>
|
||||||
|
|
||||||
<script>
|
|
||||||
import { thp_highlighter, CodeJar } from "../lexer/highlighter";
|
|
||||||
|
|
||||||
let jar = CodeJar(document.getElementById("editor")!, thp_highlighter, {
|
|
||||||
tab: " ",
|
|
||||||
});
|
|
||||||
|
|
||||||
jar.updateCode(
|
|
||||||
`union Animal {
|
|
||||||
Dog(String),
|
|
||||||
Cat(String, Int),
|
|
||||||
}
|
|
||||||
|
|
||||||
val cat_name = Post::get("cat_name") ?? "Michifu"
|
|
||||||
val my_cat = Animal::Cat(cat_name, 9)
|
|
||||||
|
|
||||||
try change_fur_color(cat) else die("Not a cat")
|
|
||||||
|
|
||||||
match random_animal()
|
|
||||||
case Dog(name)
|
|
||||||
{
|
|
||||||
print("{name} has 1 live ")
|
|
||||||
}
|
|
||||||
case Cat(name, lives)
|
|
||||||
{
|
|
||||||
print("{name} has {lives}")
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
import { highlightOnDom } from "../layouts/thpHighlighter";
|
|
||||||
document.addEventListener("DOMContentLoaded", highlightOnDom);
|
|
||||||
</script>
|
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Comments
|
title: Comments
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Comments
|
# Comments
|
||||||
|
|
||||||
@ -12,12 +13,12 @@ THP supports single and multi line comments:
|
|||||||
|
|
||||||
Begin with double slash `//` and continue until the end of the line.
|
Begin with double slash `//` and continue until the end of the line.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// This is a single line comment
|
// This is a single line comment
|
||||||
print("hello!")
|
print("hello!")
|
||||||
|
|
||||||
print("the result is {5 + 5}") // This will print 10
|
print("the result is {5 + 5}") // This will print 10
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Multi line
|
## Multi line
|
||||||
@ -26,19 +27,19 @@ These begin with `/*` and end with `*/`. Everything in between is ignored.
|
|||||||
|
|
||||||
Multi line comments can be nested in THP.
|
Multi line comments can be nested in THP.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
/*
|
/*
|
||||||
This is a
|
This is a
|
||||||
multiline comment
|
multiline comment
|
||||||
*/
|
*/
|
||||||
```
|
`} />
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
/*
|
/*
|
||||||
Multiline comments
|
Multiline comments
|
||||||
can be /* nested */
|
can be /* nested */
|
||||||
*/
|
*/
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Documentation comments
|
## Documentation comments
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Datatypes
|
title: Datatypes
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Datatypes
|
# Datatypes
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ The following are basic datatypes.
|
|||||||
|
|
||||||
Same as php int
|
Same as php int
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
Int age = 32
|
Int age = 32
|
||||||
// Hexadecimal numbers start with 0x
|
// Hexadecimal numbers start with 0x
|
||||||
Int red = 0xff0000
|
Int red = 0xff0000
|
||||||
@ -24,10 +25,10 @@ Int permissions = 0o775
|
|||||||
Int char_code = 0b01000110
|
Int char_code = 0b01000110
|
||||||
|
|
||||||
// IMPORTANT!
|
// IMPORTANT!
|
||||||
// Since Octal starts with `0o`, using just a leading 0
|
// Since Octal starts with \`0o\`, using just a leading 0
|
||||||
// will result in a decimal!
|
// will result in a decimal!
|
||||||
Int not_octal = 032 // This is 32, not 26
|
Int not_octal = 032 // This is 32, not 26
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Float
|
## Float
|
||||||
@ -35,10 +36,10 @@ Int not_octal = 032 // This is 32, not 26
|
|||||||
Same as php float
|
Same as php float
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
Float pi = 3.141592
|
Float pi = 3.141592
|
||||||
Float light = 2.99e+8
|
Float light = 2.99e+8
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## String
|
## String
|
||||||
@ -46,15 +47,15 @@ Float light = 2.99e+8
|
|||||||
THP strings use **only** double quotes. Single quotes are
|
THP strings use **only** double quotes. Single quotes are
|
||||||
used elsewhere.
|
used elsewhere.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
String name = "Rose"
|
String name = "Rose"
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Strings have interpolation with `{}`.
|
Strings have interpolation with `{}`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
print("Hello, {name}") // Hello, Rose
|
print("Hello, {name}") // Hello, Rose
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Bool
|
## Bool
|
||||||
@ -62,10 +63,11 @@ print("Hello, {name}") // Hello, Rose
|
|||||||
THP booleans are `true` and `false`. They are case sensitive,
|
THP booleans are `true` and `false`. They are case sensitive,
|
||||||
**only lowercase.**
|
**only lowercase.**
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
Bool is_true = true
|
Bool is_true = true
|
||||||
Bool is_false = false
|
Bool is_false = false
|
||||||
|
|
||||||
// This is a compile error
|
// This is a compile error
|
||||||
val invalid = TRUE
|
val invalid = TRUE
|
||||||
```
|
`} />
|
||||||
|
|
@ -3,6 +3,7 @@ layout: ../../../layouts/DocsLayout.astro
|
|||||||
title: Hello world
|
title: Hello world
|
||||||
---
|
---
|
||||||
import InteractiveCode from "../../../components/InteractiveCode.astro";
|
import InteractiveCode from "../../../components/InteractiveCode.astro";
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Hello, world!
|
# Hello, world!
|
||||||
|
|
||||||
@ -16,9 +17,9 @@ detailed later on.
|
|||||||
|
|
||||||
To write a hello world program write the following code in a file:
|
To write a hello world program write the following code in a file:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
print("Hello, world!")
|
print("Hello, world!")
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Then run `thp hello.thp` from your terminal.
|
Then run `thp hello.thp` from your terminal.
|
||||||
|
|
||||||
@ -34,11 +35,11 @@ echo("B");
|
|||||||
echo("C");
|
echo("C");
|
||||||
```
|
```
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
print("A")
|
print("A")
|
||||||
print("B")
|
print("B")
|
||||||
print("C")
|
print("C")
|
||||||
```
|
`} />
|
||||||
|
|
||||||
As a consequence of this, there can only be 1 statement per line.
|
As a consequence of this, there can only be 1 statement per line.
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Operators
|
title: Operators
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Operators
|
# Operators
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ Most of the PHP operators are present in THP.
|
|||||||
|
|
||||||
## Numbers
|
## Numbers
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
var number = 322
|
var number = 322
|
||||||
|
|
||||||
number + 1
|
number + 1
|
||||||
@ -24,48 +25,48 @@ number -= 1
|
|||||||
number *= 1
|
number *= 1
|
||||||
number /= 1
|
number /= 1
|
||||||
number %= 2
|
number %= 2
|
||||||
```
|
`} />
|
||||||
|
|
||||||
**There are no prefix/postfix increment**, use `+=` or `-=`.
|
**There are no prefix/postfix increment**, use `+=` or `-=`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// Use
|
// Use
|
||||||
number += 1
|
number += 1
|
||||||
|
|
||||||
// instead of
|
// instead of
|
||||||
number++ // This is a compile error
|
number++ // This is a compile error
|
||||||
```
|
`} />
|
||||||
|
|
||||||
### Comparison
|
### Comparison
|
||||||
|
|
||||||
These operators will not do implicit type conversion. They can
|
These operators will not do implicit type conversion. They can
|
||||||
only be used with same datatypes.
|
only be used with same datatypes.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
v1 < v2
|
v1 < v2
|
||||||
v1 <= v2
|
v1 <= v2
|
||||||
v1 > v2
|
v1 > v2
|
||||||
v1 >= v2
|
v1 >= v2
|
||||||
```
|
`} />
|
||||||
|
|
||||||
There is only `==` and `!=`. They are equivalent to `===` and `!==`.
|
There is only `==` and `!=`. They are equivalent to `===` and `!==`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
v1 == v2
|
v1 == v2
|
||||||
v1 != v2
|
v1 != v2
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
### Bitwise
|
### Bitwise
|
||||||
|
|
||||||
TBD
|
TBD
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
number and 1
|
number and 1
|
||||||
number or 2
|
number or 2
|
||||||
number xor 1
|
number xor 1
|
||||||
number xand 1
|
number xand 1
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Strings
|
## Strings
|
||||||
|
|
||||||
@ -73,15 +74,15 @@ TBD.
|
|||||||
|
|
||||||
Strings **do not use `.`** for concatenation. They use `+`.
|
Strings **do not use `.`** for concatenation. They use `+`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
"Hello " + "world."
|
"Hello " + "world."
|
||||||
```
|
`} />
|
||||||
|
|
||||||
However, the plus operator `+` does not implicitly convert types.
|
However, the plus operator `+` does not implicitly convert types.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
"Hello " + 322 // This is an error
|
"Hello " + 322 // This is an error
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Boolean
|
## Boolean
|
||||||
@ -89,10 +90,10 @@ However, the plus operator `+` does not implicitly convert types.
|
|||||||
These operators work **only with booleans**, they do not perform
|
These operators work **only with booleans**, they do not perform
|
||||||
type coercion.
|
type coercion.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
c1 && c2
|
c1 && c2
|
||||||
c1 || c2
|
c1 || c2
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Ternary
|
## Ternary
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ There is no ternary operator. See [Conditionals](/learn/flow-control/conditional
|
|||||||
|
|
||||||
These are detailed in their section: [Nullable types](/learn/error-handling/null)
|
These are detailed in their section: [Nullable types](/learn/error-handling/null)
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val person = some_fun()
|
val person = some_fun()
|
||||||
|
|
||||||
person?.name
|
person?.name
|
||||||
@ -114,7 +115,7 @@ if person?
|
|||||||
{
|
{
|
||||||
person.name
|
person.name
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,6 +3,7 @@ layout: ../../../layouts/DocsLayout.astro
|
|||||||
title: Variables
|
title: Variables
|
||||||
|
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
|
|
||||||
@ -23,27 +24,27 @@ As a regex: `[a-z_][a-zA-Z0-9_]*`
|
|||||||
|
|
||||||
Defined with `val`, followed by a variable name and a value.
|
Defined with `val`, followed by a variable name and a value.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val surname = "Doe"
|
val surname = "Doe"
|
||||||
val year_of_birth = 1984
|
val year_of_birth = 1984
|
||||||
```
|
`} />
|
||||||
|
|
||||||
### Datatype annotation
|
### Datatype annotation
|
||||||
|
|
||||||
Written after the `val` keyword but before the variable name.
|
Written after the `val` keyword but before the variable name.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val String surname = "Doe"
|
val String surname = "Doe"
|
||||||
val Int year_of_birth = 1984
|
val Int year_of_birth = 1984
|
||||||
```
|
`} />
|
||||||
|
|
||||||
When annotating an immutable variable the `val` keyword is optional
|
When annotating an immutable variable the `val` keyword is optional
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// Equivalent to the previous code
|
// Equivalent to the previous code
|
||||||
String surname = "Doe"
|
String surname = "Doe"
|
||||||
Int year_of_birth = 1984
|
Int year_of_birth = 1984
|
||||||
```
|
`} />
|
||||||
|
|
||||||
This means that if a variable only has a datatype, it is immutable.
|
This means that if a variable only has a datatype, it is immutable.
|
||||||
|
|
||||||
@ -53,28 +54,27 @@ This means that if a variable only has a datatype, it is immutable.
|
|||||||
|
|
||||||
Defined with `var`, followed by a variable name and a value.
|
Defined with `var`, followed by a variable name and a value.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
var name = "John"
|
var name = "John"
|
||||||
var age = 32
|
var age = 32
|
||||||
```
|
`} />
|
||||||
|
|
||||||
### Datatype annotation
|
### Datatype annotation
|
||||||
|
|
||||||
Written after the `var` keywords but before the variable name.
|
Written after the `var` keywords but before the variable name.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
var String name = "John"
|
var String name = "John"
|
||||||
var Int age = 32
|
var Int age = 32
|
||||||
```
|
`} />
|
||||||
|
|
||||||
When annotating a mutable variable the keyword `var` is still **required**.
|
When annotating a mutable variable the keyword `var` is still **required**.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// Equivalent to the previous code
|
// Equivalent to the previous code
|
||||||
var String name = "John"
|
var String name = "John"
|
||||||
var Int age = 32
|
var Int age = 32
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,10 +2,12 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Anonymous classes
|
title: Anonymous classes
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Anonymous classes
|
# Anonymous classes
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Logger
|
class Logger
|
||||||
{
|
{
|
||||||
pub fun log(String msg)
|
pub fun log(String msg)
|
||||||
@ -25,9 +27,9 @@ setLogger(class
|
|||||||
print(msg)
|
print(msg)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
`} />
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
setLogger(class(Int param1) -> SomeClass(param1), SomeInterface
|
setLogger(class(Int param1) -> SomeClass(param1), SomeInterface
|
||||||
{
|
{
|
||||||
pub fun method()
|
pub fun method()
|
||||||
@ -35,4 +37,4 @@ setLogger(class(Int param1) -> SomeClass(param1), SomeInterface
|
|||||||
// code
|
// code
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
`} />
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Classes
|
title: Classes
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Classes
|
# Classes
|
||||||
|
|
||||||
@ -13,26 +14,26 @@ Syntax and semantics heavily inspired by Kotlin.
|
|||||||
To create an instance of a class call it as if it were a function,
|
To create an instance of a class call it as if it were a function,
|
||||||
without `new`.
|
without `new`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val animal = Animal()
|
val animal = Animal()
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Simple class
|
## Simple class
|
||||||
|
|
||||||
Classes are declared with the `class` keyword.
|
Classes are declared with the `class` keyword.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal
|
class Animal
|
||||||
|
|
||||||
val instance = Animal()
|
val instance = Animal()
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
Properties are declared with `var`/`val`.
|
Properties are declared with `var`/`val`.
|
||||||
They **must** declare their datatype.
|
They **must** declare their datatype.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Person
|
class Person
|
||||||
{
|
{
|
||||||
// This is an error. Properties must declare their datatype,
|
// This is an error. Properties must declare their datatype,
|
||||||
@ -42,21 +43,21 @@ class Person
|
|||||||
// This is correct
|
// This is correct
|
||||||
val String name = "Jane Doe"
|
val String name = "Jane Doe"
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Properties are private by default,
|
Properties are private by default,
|
||||||
but can be made public with `pub`.
|
but can be made public with `pub`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Person
|
class Person
|
||||||
{
|
{
|
||||||
// Properties are private by default
|
// Properties are private by default
|
||||||
val String name = "John Doe"
|
val String name = "John Doe"
|
||||||
|
|
||||||
// To make a property public use `pub`
|
// To make a property public use \`pub\`
|
||||||
pub var Int age = 30
|
pub var Int age = 30
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
More information about how properties interact with the constructor
|
More information about how properties interact with the constructor
|
||||||
is found in the contructor section.
|
is found in the contructor section.
|
||||||
@ -66,7 +67,7 @@ is found in the contructor section.
|
|||||||
|
|
||||||
Methods are declared with `fun`, as regular functions.
|
Methods are declared with `fun`, as regular functions.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Person
|
class Person
|
||||||
{
|
{
|
||||||
fun greet()
|
fun greet()
|
||||||
@ -74,11 +75,11 @@ class Person
|
|||||||
print("Hello")
|
print("Hello")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Methods are private by default, and are made public with `pub`.
|
Methods are private by default, and are made public with `pub`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Person
|
class Person
|
||||||
{
|
{
|
||||||
// This method is private
|
// This method is private
|
||||||
@ -87,7 +88,7 @@ class Person
|
|||||||
print("Hello from private method")
|
print("Hello from private method")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use `pub` to make a method public
|
// Use \`pub\` to make a method public
|
||||||
pub fun greet()
|
pub fun greet()
|
||||||
{
|
{
|
||||||
print("Hello from greet")
|
print("Hello from greet")
|
||||||
@ -97,14 +98,14 @@ class Person
|
|||||||
val p = Person()
|
val p = Person()
|
||||||
p.greet() //: Hello from greet
|
p.greet() //: Hello from greet
|
||||||
p.private_greet() // Compile time error. Private method.
|
p.private_greet() // Compile time error. Private method.
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## This
|
## This
|
||||||
|
|
||||||
THP uses the dollar sign `$` as this. It is **required** when
|
THP uses the dollar sign `$` as this. It is **required** when
|
||||||
using a class property/method.
|
using a class property/method.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Person
|
class Person
|
||||||
{
|
{
|
||||||
val String name = "Jane Doe"
|
val String name = "Jane Doe"
|
||||||
@ -120,7 +121,7 @@ class Person
|
|||||||
print("Hello, I'm {person_name}")
|
print("Hello, I'm {person_name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Static members
|
## Static members
|
||||||
|
|
||||||
@ -134,17 +135,17 @@ Static members are detailed in their own page.
|
|||||||
PHP only allows a single constructor, and so does THP.
|
PHP only allows a single constructor, and so does THP.
|
||||||
The basic constructor has the syntax of function parameters.
|
The basic constructor has the syntax of function parameters.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// |this is the constructor |
|
// |this is the constructor |
|
||||||
class Animal(String fullname, Int age)
|
class Animal(String fullname, Int age)
|
||||||
|
|
||||||
val a1 = Animal("Nal", 4)
|
val a1 = Animal("Nal", 4)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
The class properties can be declared in the constructor,
|
The class properties can be declared in the constructor,
|
||||||
using the keywords `pub`, `var`, `val`:
|
using the keywords `pub`, `var`, `val`:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal(
|
class Animal(
|
||||||
// Since we are using val/var, these are promoted to class properties
|
// Since we are using val/var, these are promoted to class properties
|
||||||
val String fullname,
|
val String fullname,
|
||||||
@ -160,7 +161,7 @@ class Animal(
|
|||||||
|
|
||||||
val a1 = Animal("Nal", 4)
|
val a1 = Animal("Nal", 4)
|
||||||
a1.say() //: My name is Nal and i'm 4 years old
|
a1.say() //: My name is Nal and i'm 4 years old
|
||||||
```
|
`} />
|
||||||
|
|
||||||
By using this syntax you are declaring properties and assigning them
|
By using this syntax you are declaring properties and assigning them
|
||||||
at the same time.
|
at the same time.
|
||||||
@ -173,14 +174,14 @@ The contructor parameters can also have default values.
|
|||||||
The constructor is public by default. It can be made private/protected
|
The constructor is public by default. It can be made private/protected
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal
|
class Animal
|
||||||
private constructor(
|
private constructor(
|
||||||
val String fullname,
|
val String fullname,
|
||||||
var Int age,
|
var Int age,
|
||||||
)
|
)
|
||||||
{...}
|
{...}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
### Derived properties
|
### Derived properties
|
||||||
@ -188,19 +189,19 @@ private constructor(
|
|||||||
You can declare properties whose values depend on values
|
You can declare properties whose values depend on values
|
||||||
on the constructor.
|
on the constructor.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal(
|
class Animal(
|
||||||
val String fullname,
|
val String fullname,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// A property whose value depends on `fullname`
|
// A property whose value depends on \`fullname\`
|
||||||
// This is executed after the contructor
|
// This is executed after the contructor
|
||||||
pub val Int name_length = $fullname.length
|
pub val Int name_length = $fullname.length
|
||||||
}
|
}
|
||||||
|
|
||||||
val a2 = Animal("Doa")
|
val a2 = Animal("Doa")
|
||||||
print(a2.name_length) //: 3
|
print(a2.name_length) //: 3
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
### Init block
|
### Init block
|
||||||
@ -208,7 +209,7 @@ print(a2.name_length) //: 3
|
|||||||
If you need to additional logic in the constructor you can
|
If you need to additional logic in the constructor you can
|
||||||
use a `init` block.
|
use a `init` block.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal(
|
class Animal(
|
||||||
val String fullname,
|
val String fullname,
|
||||||
)
|
)
|
||||||
@ -220,13 +221,13 @@ class Animal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val a3 = Animal("Lola") //: Lola in construction
|
val a3 = Animal("Lola") //: Lola in construction
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Inheritance
|
## Inheritance
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// Base class
|
// Base class
|
||||||
class Animal(var String name)
|
class Animal(var String name)
|
||||||
{
|
{
|
||||||
@ -241,13 +242,13 @@ class Cat(String name, Int lives)
|
|||||||
extends Animal(name)
|
extends Animal(name)
|
||||||
|
|
||||||
Cat("Michi", 9).say_name()
|
Cat("Michi", 9).say_name()
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Mutable methods
|
## Mutable methods
|
||||||
|
|
||||||
By default methods cannot mutate the state of the object.
|
By default methods cannot mutate the state of the object.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal(var String name)
|
class Animal(var String name)
|
||||||
{
|
{
|
||||||
pub fun set_name(String new_name)
|
pub fun set_name(String new_name)
|
||||||
@ -255,12 +256,12 @@ class Animal(var String name)
|
|||||||
$name = new_name // Error: Cannot mutate $
|
$name = new_name // Error: Cannot mutate $
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
To do so the method must be annotated. The caller must also
|
To do so the method must be annotated. The caller must also
|
||||||
declare a mutable variable.
|
declare a mutable variable.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Animal(var String name)
|
class Animal(var String name)
|
||||||
{
|
{
|
||||||
pub mut fun set_name(String new_name)
|
pub mut fun set_name(String new_name)
|
||||||
@ -271,13 +272,13 @@ class Animal(var String name)
|
|||||||
|
|
||||||
var michi = Animal("Michifu")
|
var michi = Animal("Michifu")
|
||||||
michi.set_name("Garfield")
|
michi.set_name("Garfield")
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Class constructor that may return an error
|
## Class constructor that may return an error
|
||||||
|
|
||||||
Working theory:
|
Working theory:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Fish(
|
class Fish(
|
||||||
val String name,
|
val String name,
|
||||||
var Int lives = 9,
|
var Int lives = 9,
|
||||||
@ -285,9 +286,9 @@ class Fish(
|
|||||||
extends Animal(name)
|
extends Animal(name)
|
||||||
throws Error
|
throws Error
|
||||||
|
|
||||||
val fish_result = Fish("bubble") // fish_result will be a `Result[Fish,Error]`
|
val fish_result = Fish("bubble") // fish_result will be a \`Result[Fish,Error]\`
|
||||||
val fish = try fish_result
|
val fish = try fish_result
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,12 +2,13 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Interfaces
|
title: Interfaces
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Interfaces
|
# Interfaces
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
interface Serializable
|
interface Serializable
|
||||||
{
|
{
|
||||||
// Methods are always public in interfaces
|
// Methods are always public in interfaces
|
||||||
@ -24,7 +25,7 @@ class Cat -> Serializable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
`} />
|
||||||
|
|
||||||
No interface inheritance.
|
No interface inheritance.
|
||||||
|
|
@ -2,12 +2,13 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Magic methods
|
title: Magic methods
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Magic methods
|
# Magic methods
|
||||||
|
|
||||||
Don't get special treatment.
|
Don't get special treatment.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
|
|
||||||
class Cat
|
class Cat
|
||||||
{
|
{
|
||||||
@ -17,13 +18,13 @@ class Cat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val option = Some("GAAA")
|
val option = Some("GAAA")
|
||||||
val Some(value) = option
|
val Some(value) = option
|
||||||
|
|
||||||
val colors = Array("red", "green", "blue")
|
val colors = Array("red", "green", "blue")
|
||||||
val Array()
|
val Array()
|
||||||
```
|
`} />
|
@ -2,13 +2,14 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Static
|
title: Static
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Static in classes
|
# Static in classes
|
||||||
|
|
||||||
|
|
||||||
## Class constants
|
## Class constants
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
class Cat
|
class Cat
|
||||||
{
|
{
|
||||||
// Stateful code
|
// Stateful code
|
||||||
@ -20,7 +21,7 @@ static Cat
|
|||||||
}
|
}
|
||||||
|
|
||||||
print(Cat::CONSTANT)
|
print(Cat::CONSTANT)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Static methods
|
## Static methods
|
||||||
@ -28,7 +29,7 @@ print(Cat::CONSTANT)
|
|||||||
aka. plain, old functions
|
aka. plain, old functions
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
static Cat
|
static Cat
|
||||||
{
|
{
|
||||||
fun static_method() -> Int
|
fun static_method() -> Int
|
||||||
@ -38,7 +39,7 @@ static Cat
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cat::static_method()
|
Cat::static_method()
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Static properties
|
## Static properties
|
||||||
@ -46,7 +47,7 @@ Cat::static_method()
|
|||||||
aka. global variables
|
aka. global variables
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
static Cat
|
static Cat
|
||||||
{
|
{
|
||||||
pub var access_count = 0
|
pub var access_count = 0
|
||||||
@ -55,7 +56,7 @@ static Cat
|
|||||||
print(Cat::access_count) // 0
|
print(Cat::access_count) // 0
|
||||||
Cat::access_count += 1
|
Cat::access_count += 1
|
||||||
print(Cat::access_count) // 1
|
print(Cat::access_count) // 1
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Arrays
|
title: Arrays
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Arrays
|
# Arrays
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ Use square brackets as usual.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val fruits = ["apple", "banana", "cherry"]
|
val fruits = ["apple", "banana", "cherry"]
|
||||||
val apple = fruits[0]
|
val apple = fruits[0]
|
||||||
|
|
||||||
@ -21,16 +22,16 @@ var numbers = [0, 1, 2, 3]
|
|||||||
numbers[3] = 5
|
numbers[3] = 5
|
||||||
|
|
||||||
print(numbers[3]) // 5
|
print(numbers[3]) // 5
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Type signature
|
## Type signature
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
Array[String]
|
Array[String]
|
||||||
Array[Int]
|
Array[Int]
|
||||||
```
|
`} />
|
||||||
|
|
||||||
The Array signature __requires__ the word `Array`.
|
The Array signature __requires__ the word `Array`.
|
||||||
There is no `Int[]` or `[Int]` signature, since that would cause
|
There is no `Int[]` or `[Int]` signature, since that would cause
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Enums
|
title: Enums
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Enums
|
# Enums
|
||||||
|
|
||||||
@ -15,7 +16,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.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
enum Suit
|
enum Suit
|
||||||
{
|
{
|
||||||
Hearts,
|
Hearts,
|
||||||
@ -25,14 +26,14 @@ enum Suit
|
|||||||
}
|
}
|
||||||
|
|
||||||
val suit = Suit::Hearts
|
val suit = Suit::Hearts
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Backed enums
|
## Backed enums
|
||||||
|
|
||||||
Backed enums can have a scalar for each case. The scalar values can only be
|
Backed enums can have a scalar for each case. The scalar values can only be
|
||||||
`String` or `Int`.
|
`String` or `Int`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
enum Suit(String)
|
enum Suit(String)
|
||||||
{
|
{
|
||||||
Hearts = "H",
|
Hearts = "H",
|
||||||
@ -40,7 +41,7 @@ enum Suit(String)
|
|||||||
Clubs = "C",
|
Clubs = "C",
|
||||||
Spades = "S",
|
Spades = "S",
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
All cases must explicitly define their value, there is no automatic generation.
|
All cases must explicitly define their value, there is no automatic generation.
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Maps
|
title: Maps
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Maps
|
# Maps
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ There can also be anonymous maps, which may contain any key.
|
|||||||
|
|
||||||
## Named Maps
|
## Named Maps
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// Here we define a map, called Person
|
// Here we define a map, called Person
|
||||||
map Person {
|
map Person {
|
||||||
String name,
|
String name,
|
||||||
@ -36,21 +37,21 @@ var Person mary_jane = .{
|
|||||||
surname: "Jane",
|
surname: "Jane",
|
||||||
age: 27,
|
age: 27,
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
To access the fields of a map we use square braces `[]`.
|
To access the fields of a map we use square braces `[]`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
mary_jane["age"] += 1
|
mary_jane["age"] += 1
|
||||||
print(mary_jane["name"]) // Mary
|
print(mary_jane["name"]) // Mary
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Or dot access `.` if the field's name is a valid identifier.
|
Or dot access `.` if the field's name is a valid identifier.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
mary_jane.age += 1
|
mary_jane.age += 1
|
||||||
print(mary_jane.name)
|
print(mary_jane.name)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Anonymous maps
|
## Anonymous maps
|
||||||
@ -58,23 +59,23 @@ print(mary_jane.name)
|
|||||||
An anonymous map allows us to store and retrieve any key of any datatype.
|
An anonymous map allows us to store and retrieve any key of any datatype.
|
||||||
They are declared as `Map`.
|
They are declared as `Map`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val car = Map {
|
val car = Map {
|
||||||
brand: "Toyota",
|
brand: "Toyota",
|
||||||
model: "Corolla",
|
model: "Corolla",
|
||||||
year: 2012,
|
year: 2012,
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Anonymous maps can also can have their type omitted.
|
Anonymous maps can also can have their type omitted.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
var car = .{
|
var car = .{
|
||||||
brand: "Toyota",
|
brand: "Toyota",
|
||||||
model: "Corolla",
|
model: "Corolla",
|
||||||
year: 2012,
|
year: 2012,
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
If the compiler encounters a map without a type (that is, `.{}`)
|
If the compiler encounters a map without a type (that is, `.{}`)
|
||||||
and doesn't expect a specific type, it will assume it is an
|
and doesn't expect a specific type, it will assume it is an
|
||||||
@ -82,30 +83,30 @@ anonymous map.
|
|||||||
|
|
||||||
We can freely assign fields to an anonymous map:
|
We can freely assign fields to an anonymous map:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// Modify an existing field
|
// Modify an existing field
|
||||||
car["year"] = 2015
|
car["year"] = 2015
|
||||||
// Create a new field
|
// Create a new field
|
||||||
car["status"] = "used"
|
car["status"] = "used"
|
||||||
```
|
`} />
|
||||||
|
|
||||||
However, if we try to access a field of an anonymous map we'll get
|
However, if we try to access a field of an anonymous map we'll get
|
||||||
a nullable type, and we must annotate it.
|
a nullable type, and we must annotate it.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// This is ok, we are declaring what datatype we expect
|
// This is ok, we are declaring what datatype we expect
|
||||||
String? car_status = car["status"]
|
String? car_status = car["status"]
|
||||||
|
|
||||||
// This won't work, the compiler doesn't know what datatype to use
|
// This won't work, the compiler doesn't know what datatype to use
|
||||||
var car_status = car["status"]
|
var car_status = car["status"]
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Instead, we can use the `get` function of the map, which expects a
|
Instead, we can use the `get` function of the map, which expects a
|
||||||
datatype and returns that type as nullable
|
datatype and returns that type as nullable
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val car_status = car.get[String]("status")
|
val car_status = car.get[String]("status")
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Both ways to get a value will check that the key exists in the map,
|
Both ways to get a value will check that the key exists in the map,
|
||||||
and that it has the correct datatype. If either the key doesn't exist
|
and that it has the correct datatype. If either the key doesn't exist
|
||||||
@ -113,10 +114,10 @@ or it has a different datatype, it will return `null`.
|
|||||||
|
|
||||||
We can also use dynamic keys, following the same rules:
|
We can also use dynamic keys, following the same rules:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val generated_value = "key"
|
val generated_value = "key"
|
||||||
|
|
||||||
String? v = map[generated_value]
|
String? v = map[generated_value]
|
||||||
// or
|
// or
|
||||||
val v = map[String](generated_value)
|
val v = map[String](generated_value)
|
||||||
```
|
`} />
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Tuples
|
title: Tuples
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Tuples
|
# Tuples
|
||||||
|
|
||||||
@ -9,18 +10,19 @@ Uses `#()` just to avoid confusion with function calls and grouping (`()`).
|
|||||||
|
|
||||||
## Definition
|
## Definition
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val person = #("John", "Doe", 32)
|
val person = #("John", "Doe", 32)
|
||||||
|
|
||||||
val #(name, surname, age) = person
|
val #(name, surname, age) = person
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
#(String, String, Int)
|
#(String, String, Int)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,12 +2,13 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Tagged unions
|
title: Tagged unions
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Tagged unions
|
# Tagged unions
|
||||||
|
|
||||||
Tagged unions can hold a value from a fixed selection of types.
|
Tagged unions can hold a value from a fixed selection of types.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
union Shape
|
union Shape
|
||||||
{
|
{
|
||||||
Dot,
|
Dot,
|
||||||
@ -18,11 +19,11 @@ union Shape
|
|||||||
val dot = Shape::Dot
|
val dot = Shape::Dot
|
||||||
val square1 = Shape::Square(10)
|
val square1 = Shape::Square(10)
|
||||||
val rectangle1 = Shape::Rectangle(5, 15)
|
val rectangle1 = Shape::Rectangle(5, 15)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Pattern matching
|
## Pattern matching
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
match shape_1
|
match shape_1
|
||||||
case ::Square(side)
|
case ::Square(side)
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ case ::Rectangle(length, height)
|
|||||||
{
|
{
|
||||||
print("Area of the rectangle: {length * height}")
|
print("Area of the rectangle: {length * height}")
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Internal representation
|
## Internal representation
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Nullable types
|
title: Nullable types
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Nullable types
|
# Nullable types
|
||||||
|
|
||||||
@ -12,18 +13,18 @@ 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?`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
String? new_username = POST::get("username")
|
String? new_username = POST::get("username")
|
||||||
```
|
`} />
|
||||||
|
|
||||||
When we have a `Type?` we cannot use it directly. We must first
|
When we have a `Type?` we cannot use it directly. We must first
|
||||||
check if the value is null, and then use it.
|
check if the value is null, and then use it.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
if new_username != null {
|
if new_username != null {
|
||||||
// Here `new_username` is automatically casted to String
|
// Here \`new_username\` is automatically casted to String
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
We must check explicitly that the value is not null. Doing
|
We must check explicitly that the value is not null. Doing
|
||||||
`if new_username {}` alone is not allowed.
|
`if new_username {}` alone is not allowed.
|
||||||
@ -32,30 +33,30 @@ We must check explicitly that the value is not null. Doing
|
|||||||
|
|
||||||
To create a nullable type we must explicitly annotate the type.
|
To create a nullable type we must explicitly annotate the type.
|
||||||
|
|
||||||
```thp
|
<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:
|
||||||
|
|
||||||
```thp
|
<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.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
Person? person = ...
|
Person? person = ...
|
||||||
|
|
||||||
val name = person?.name
|
val name = person?.name
|
||||||
```
|
`} />
|
||||||
|
|
||||||
- If `person` is null, `person?.name` will return `null`
|
- If `person` is null, `person?.name` will return `null`
|
||||||
- If `person` is not null, `person?.name` will return `name`
|
- If `person` is not null, `person?.name` will return `name`
|
||||||
@ -65,12 +66,12 @@ val name = person?.name
|
|||||||
|
|
||||||
The Elvis operator `??` is used to give a default value in case a `null` is found.
|
The Elvis operator `??` is used to give a default value in case a `null` is found.
|
||||||
|
|
||||||
```thp
|
<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
|
||||||
```
|
`} />
|
||||||
|
|
||||||
For the above code:
|
For the above code:
|
||||||
|
|
||||||
@ -79,9 +80,9 @@ For the above code:
|
|||||||
|
|
||||||
You can use the Elvis operator to return early
|
You can use the Elvis operator to return early
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val username = get_username() ?? return
|
val username = get_username() ?? return
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,6 +3,7 @@ layout: ../../../layouts/DocsLayout.astro
|
|||||||
title: Try/Exceptions
|
title: Try/Exceptions
|
||||||
---
|
---
|
||||||
import InteractiveCode from "../../../components/InteractiveCode.astro";
|
import InteractiveCode from "../../../components/InteractiveCode.astro";
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Try/exceptions
|
# Try/exceptions
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ is used.
|
|||||||
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:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun invert(Int number) -> Int!DivisionByZero
|
fun invert(Int number) -> Int!DivisionByZero
|
||||||
{
|
{
|
||||||
if number == 0
|
if number == 0
|
||||||
@ -27,7 +28,7 @@ fun invert(Int number) -> Int!DivisionByZero
|
|||||||
|
|
||||||
return 1 / number
|
return 1 / number
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
In the previous segment, `Int!DivisionByZero` denotates
|
In the previous segment, `Int!DivisionByZero` denotates
|
||||||
that the function may return either an `Int` or an `DivisionByZero`.
|
that the function may return either an `Int` or an `DivisionByZero`.
|
||||||
@ -44,12 +45,12 @@ TODO: fix?
|
|||||||
If there are multiple error types that the function can return,
|
If there are multiple error types that the function can return,
|
||||||
you can use the `|` operator:
|
you can use the `|` operator:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
type Exceptions = Exception1 | Exception2 | Exception3
|
type Exceptions = Exception1 | Exception2 | Exception3
|
||||||
|
|
||||||
fun sample() -> Int!Exceptions
|
fun sample() -> Int!Exceptions
|
||||||
{ /* ... */}
|
{ /* ... */}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -132,14 +133,14 @@ otherwise will assign the success value and continue.
|
|||||||
Try/return will run a function and assign its value if `Ok` is found.
|
Try/return will run a function and assign its value if `Ok` is found.
|
||||||
Otherwise, it will return a new value specified by the programmer.
|
Otherwise, it will return a new value specified by the programmer.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun run() -> Int
|
fun run() -> Int
|
||||||
{
|
{
|
||||||
val result = try dangerous() return 0
|
val result = try dangerous() return 0
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
In the previous example:
|
In the previous example:
|
||||||
|
|
||||||
@ -226,27 +227,27 @@ Either way, the function will continue executing.
|
|||||||
Try/catch allows the error to be manually used & handled.
|
Try/catch allows the error to be manually used & handled.
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun run()
|
fun run()
|
||||||
{
|
{
|
||||||
val result = try dangerous()
|
val result = try dangerous()
|
||||||
catch Exception e
|
catch Exception e
|
||||||
{
|
{
|
||||||
// This is run if `dangerous()` throws.
|
// This is run if \`dangerous()\` throws.
|
||||||
// `e` is the thrown error
|
// \`e\` is the thrown error
|
||||||
|
|
||||||
// Handle the error
|
// Handle the error
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
// Return a new value to be assigned to `result`
|
// Return a new value to be assigned to \`result\`
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
A try/catch may have many `catch` clauses:
|
A try/catch may have many `catch` clauses:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
try dangerous()
|
try dangerous()
|
||||||
catch Exception1 e
|
catch Exception1 e
|
||||||
{...}
|
{...}
|
||||||
@ -254,6 +255,6 @@ catch Exception2 e
|
|||||||
{...}
|
{...}
|
||||||
catch Exception3 e
|
catch Exception3 e
|
||||||
{...}
|
{...}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Blocks
|
title: Blocks
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Blocks
|
# Blocks
|
||||||
|
|
||||||
@ -11,13 +12,13 @@ Blocks can be assigned to variables, in which case
|
|||||||
they are executed and their last expression is
|
they are executed and their last expression is
|
||||||
returned.
|
returned.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val result = {
|
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
|
||||||
```
|
`} />
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Conditionals
|
title: Conditionals
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Conditionals
|
# Conditionals
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ title: Conditionals
|
|||||||
- There's no ternary operator
|
- There's no ternary operator
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
if condition
|
if condition
|
||||||
{
|
{
|
||||||
// code
|
// code
|
||||||
@ -28,25 +29,25 @@ else
|
|||||||
|
|
||||||
|
|
||||||
val result = if condition { value1 } else { value2 }
|
val result = if condition { value1 } else { value2 }
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Check for datatypes
|
## Check for datatypes
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
if variable is Datatype
|
if variable is Datatype
|
||||||
{
|
{
|
||||||
// code using variable
|
// code using variable
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## If variable is of enum
|
## If variable is of enum
|
||||||
|
|
||||||
TBD
|
TBD
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
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
|
||||||
@ -58,7 +59,7 @@ 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}")
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Loops
|
title: Loops
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Loops
|
# Loops
|
||||||
|
|
||||||
@ -11,16 +12,16 @@ This is simmilar to PHP's `foreach`. There is no equivalent to PHP's `for`.
|
|||||||
|
|
||||||
Braces are required.
|
Braces are required.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val numbers = [0, 1, 2, 3]
|
val numbers = [0, 1, 2, 3]
|
||||||
|
|
||||||
for #(index, number) in numbers
|
for #(index, number) in numbers
|
||||||
{
|
{
|
||||||
print(number)
|
print(number)
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val dict = .{
|
val dict = .{
|
||||||
apple: 10,
|
apple: 10,
|
||||||
banana: 7,
|
banana: 7,
|
||||||
@ -31,13 +32,13 @@ for #(key, value) in dict
|
|||||||
{
|
{
|
||||||
print("{key} => {value}")
|
print("{key} => {value}")
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## While loop
|
## While loop
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val colors = ["red", "green", "blue"]
|
val colors = ["red", "green", "blue"]
|
||||||
var index = 0
|
var index = 0
|
||||||
|
|
||||||
@ -46,14 +47,14 @@ while index < colors.size()
|
|||||||
print("{colors[index]}")
|
print("{colors[index]}")
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Infinite loop
|
## Infinite loop
|
||||||
|
|
||||||
Instead of doing `while true {}` use `loop`.
|
Instead of doing `while true {}` use `loop`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
loop
|
loop
|
||||||
{
|
{
|
||||||
print("looping")
|
print("looping")
|
||||||
@ -63,14 +64,14 @@ loop
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Labelled loops
|
## Labelled loops
|
||||||
|
|
||||||
You can give labels to loops, allowing you to `break` and `continue` in nested loops.
|
You can give labels to loops, allowing you to `break` and `continue` in nested loops.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
:top for i in values_1
|
:top for i in values_1
|
||||||
{
|
{
|
||||||
for j in values_2
|
for j in values_2
|
||||||
@ -79,12 +80,6 @@ You can give labels to loops, allowing you to `break` and `continue` in nested l
|
|||||||
break :top
|
break :top
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Match
|
title: Match
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Match
|
# Match
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ title: Match
|
|||||||
|
|
||||||
Braces are **required**.
|
Braces are **required**.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val user_id = POST::get("user_id")
|
val user_id = POST::get("user_id")
|
||||||
|
|
||||||
|
|
||||||
@ -47,5 +48,5 @@ else
|
|||||||
{
|
{
|
||||||
print("hello dear")
|
print("hello dear")
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Declaration
|
title: Declaration
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Declaration
|
# Declaration
|
||||||
|
|
||||||
@ -10,42 +11,42 @@ Function names **must** begin with a lowercase letter.
|
|||||||
|
|
||||||
## No parameters, no return
|
## No parameters, no return
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun say_hello()
|
fun say_hello()
|
||||||
{
|
{
|
||||||
print("Hello")
|
print("Hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
say_hello()
|
say_hello()
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## With return type
|
## With return type
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun get_random_number() -> Int
|
fun get_random_number() -> Int
|
||||||
{
|
{
|
||||||
Random::get(0, 35_222)
|
Random::get(0, 35_222)
|
||||||
}
|
}
|
||||||
|
|
||||||
val number = get_random_number()
|
val number = get_random_number()
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## With parameters and return type
|
## With parameters and return type
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun get_secure_random_number(Int min, Int max) -> Int
|
fun get_secure_random_number(Int min, Int max) -> Int
|
||||||
{
|
{
|
||||||
Random::get_secure(min, max)
|
Random::get_secure(min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
val number = get_secure_random_number(0, 65535)
|
val number = get_secure_random_number(0, 65535)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Generic types
|
## Generic types
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun get_first_item[T](Array[T] array) -> T
|
fun get_first_item[T](Array[T] array) -> T
|
||||||
{
|
{
|
||||||
array[0]
|
array[0]
|
||||||
@ -55,23 +56,23 @@ val first = get_first_item[Int](numbers)
|
|||||||
// The type annotation is optional if the compiler can infer the type
|
// The type annotation is optional if the compiler can infer the type
|
||||||
|
|
||||||
val first = get_first_item(numbers)
|
val first = get_first_item(numbers)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Signature
|
## Signature
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
() -> ()
|
() -> ()
|
||||||
() -> Int
|
() -> Int
|
||||||
(Int, Int) -> Int
|
(Int, Int) -> Int
|
||||||
[T](Array[T]) -> T
|
[T](Array[T]) -> T
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Named arguments
|
## Named arguments
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun html_special_chars(
|
fun html_special_chars(
|
||||||
String input,
|
String input,
|
||||||
Int? flags,
|
Int? flags,
|
||||||
@ -83,13 +84,13 @@ fun html_special_chars(
|
|||||||
}
|
}
|
||||||
|
|
||||||
html_special_chars(input, double_encoding: false)
|
html_special_chars(input, double_encoding: false)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
TBD: If & how named arguments affect the order of the parameters
|
TBD: If & how named arguments affect the order of the parameters
|
||||||
|
|
||||||
## Named arguments with different names
|
## Named arguments with different names
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun greet(
|
fun greet(
|
||||||
String name,
|
String name,
|
||||||
String from: city,
|
String from: city,
|
||||||
@ -99,7 +100,7 @@ fun greet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
greet("John", from: "LA")
|
greet("John", from: "LA")
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,23 +2,24 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Higher Order Functions
|
title: Higher Order Functions
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Higher Order functions
|
# Higher Order functions
|
||||||
|
|
||||||
|
|
||||||
## Function as parameter
|
## Function as parameter
|
||||||
|
|
||||||
```thp
|
<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
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
`} />
|
||||||
|
|
||||||
## Function as return
|
## Function as return
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun generate_generator() -> () -> Int
|
fun generate_generator() -> () -> Int
|
||||||
{
|
{
|
||||||
// code...
|
// code...
|
||||||
@ -30,7 +31,7 @@ fun generate_generator() -> () -> Int
|
|||||||
|
|
||||||
val generator = generate_generator() // A function
|
val generator = generate_generator() // A function
|
||||||
val value = generate_generator()() // An Int
|
val value = generate_generator()() // An Int
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Lambdas
|
title: Lambdas
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Lambdas / Anonymous functions
|
# Lambdas / Anonymous functions
|
||||||
|
|
||||||
|
|
||||||
## Anonymous function
|
## Anonymous function
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun(Int x, Int y) -> Int {
|
fun(Int x, Int y) -> Int {
|
||||||
x + y
|
x + y
|
||||||
}
|
}
|
||||||
@ -17,7 +18,7 @@ fun(Int x, Int y) -> Int {
|
|||||||
numbers.map(fun(x) {
|
numbers.map(fun(x) {
|
||||||
x * 2
|
x * 2
|
||||||
})
|
})
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ numbers.map(fun(x) {
|
|||||||
By default closures **always** capture variables as **references**.
|
By default closures **always** capture variables as **references**.
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
var x = 20
|
var x = 20
|
||||||
|
|
||||||
val f = fun() {
|
val f = fun() {
|
||||||
@ -37,18 +38,18 @@ f() // 20
|
|||||||
|
|
||||||
x = 30
|
x = 30
|
||||||
f() // 30
|
f() // 30
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
You can force a closure to capture variables by value.
|
You can force a closure to capture variables by value.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun(parameters) clone(variables) {
|
fun(parameters) clone(variables) {
|
||||||
// code
|
// code
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
var x = 20
|
var x = 20
|
||||||
|
|
||||||
val f = fun() clone(x) {
|
val f = fun() clone(x) {
|
||||||
@ -59,7 +60,7 @@ f() // 20
|
|||||||
|
|
||||||
x = 30
|
x = 30
|
||||||
f() // 20
|
f() // 20
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
## Lambdas
|
## Lambdas
|
||||||
@ -70,7 +71,7 @@ Inside the lambda you can access the parameters as `$1`, `$2`, etc.
|
|||||||
|
|
||||||
Finally, lambdas be written outside of the parenthesis of function calls.
|
Finally, lambdas be written outside of the parenthesis of function calls.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
numbers.map() #{
|
numbers.map() #{
|
||||||
$1 * 2
|
$1 * 2
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ numbers.map() #{
|
|||||||
numbers.map(fun(param1) {
|
numbers.map(fun(param1) {
|
||||||
$1 * 2
|
$1 * 2
|
||||||
})
|
})
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,39 +2,40 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Function parameters
|
title: Function parameters
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# Function parameters
|
# Function parameters
|
||||||
|
|
||||||
|
|
||||||
## Immutable reference
|
## Immutable reference
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun add_25(Array[Int] numbers) {
|
fun add_25(Array[Int] numbers) {
|
||||||
numbers.push(25) // Error: `numbers` is immutable
|
numbers.push(25) // Error: \`numbers\` is immutable
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
When using a regular type as a parameter, only it's immutable
|
When using a regular type as a parameter, only it's immutable
|
||||||
properties can be used
|
properties can be used
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun count(Array[Int] numbers) -> Int {
|
fun count(Array[Int] numbers) -> Int {
|
||||||
val items_count = numbers.size() // Ok, `size` is pure
|
val items_count = numbers.size() // Ok, \`size\` is pure
|
||||||
|
|
||||||
items_count
|
items_count
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
To use immutable properties you must use a mutable reference.
|
To use immutable properties you must use a mutable reference.
|
||||||
|
|
||||||
|
|
||||||
## Mutable reference
|
## Mutable reference
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun push_25(mut Array[Int] numbers) {
|
fun push_25(mut Array[Int] numbers) {
|
||||||
numbers.push(25) // Ok, will also mutate the original array
|
numbers.push(25) // Ok, will also mutate the original array
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Placing a `mut` 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
|
reference. Mutable methods can be used, and the original
|
||||||
@ -42,37 +43,34 @@ data **can** be mutated.
|
|||||||
|
|
||||||
The caller *must* also use `mut`.
|
The caller *must* also use `mut`.
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val numbers = Array(0, 1, 2, 3)
|
val numbers = Array(0, 1, 2, 3)
|
||||||
|
|
||||||
push_25(mut numbers) // Pass `numbers` as reference.
|
push_25(mut numbers) // Pass \`numbers\` as reference.
|
||||||
|
|
||||||
print(numbers(4)) // `Some(25)`
|
print(numbers(4)) // \`Some(25)\`
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Clone
|
## Clone
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun add_25(clone Array[Int] numbers) {
|
fun add_25(clone Array[Int] numbers) {
|
||||||
numbers.push(25) // Ok, the original array is unaffected
|
numbers.push(25) // Ok, the original array is unaffected
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
Using the `clone` keyword before the type creates a mutable copy
|
Using the `clone` keyword before the type creates a mutable copy
|
||||||
of the parameter (CoW). The original data will **not** be mutated.
|
of the parameter (CoW). The original data will **not** be mutated.
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
val numbers = Array(1, 2, 3, 4)
|
val numbers = Array(1, 2, 3, 4)
|
||||||
|
|
||||||
add_25(clone numbers) // Pass `numbers` as clone.
|
add_25(clone numbers) // Pass \`numbers\` as clone.
|
||||||
|
|
||||||
print(numbers(4)) // None
|
print(numbers(4)) // None
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -54,6 +54,7 @@ pagesLayout:
|
|||||||
- path: intro
|
- path: intro
|
||||||
---
|
---
|
||||||
import InteractiveCode from "../../components/InteractiveCode.astro";
|
import InteractiveCode from "../../components/InteractiveCode.astro";
|
||||||
|
import Code from "../../components/Code.astro"
|
||||||
|
|
||||||
|
|
||||||
# Welcome
|
# Welcome
|
||||||
@ -144,11 +145,11 @@ $has_key = str_contains($haystack, 'needle');
|
|||||||
print("has key? " . $has_key);
|
print("has key? " . $has_key);
|
||||||
```
|
```
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// THP
|
// THP
|
||||||
val has_key = haystack.contains("needle")
|
val has_key = haystack.contains("needle")
|
||||||
print("has key? " + has_key)
|
print("has key? " + has_key)
|
||||||
```
|
`} />
|
||||||
|
|
||||||
- Explicit variable declaration
|
- Explicit variable declaration
|
||||||
- No `$` for variable names (and thus no `$$variable`, use a map instead)
|
- No `$` for variable names (and thus no `$$variable`, use a map instead)
|
||||||
@ -170,14 +171,14 @@ $obj = [
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// THP
|
// THP
|
||||||
val obj = .{
|
val obj = .{
|
||||||
names: #("Toni", "Stark"), // Tuple
|
names: #("Toni", "Stark"), // Tuple
|
||||||
age: 33,
|
age: 33,
|
||||||
numbers: [32, 64, 128]
|
numbers: [32, 64, 128]
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
- Tuples, Arrays, Sets, Maps are clearly different
|
- Tuples, Arrays, Sets, Maps are clearly different
|
||||||
- JSON-like object syntax
|
- JSON-like object syntax
|
||||||
@ -192,11 +193,11 @@ $cat->meow();
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// THP
|
// THP
|
||||||
val cat = Cat("Michifu", 7)
|
val cat = Cat("Michifu", 7)
|
||||||
cat.meow();
|
cat.meow();
|
||||||
```
|
`} />
|
||||||
|
|
||||||
- Instantiate classes without `new`
|
- Instantiate classes without `new`
|
||||||
- Use dot `.` instead of arrow `->` syntax
|
- Use dot `.` instead of arrow `->` syntax
|
||||||
@ -211,10 +212,10 @@ use \Some\Deeply\Nested\Interface
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// THP
|
// THP
|
||||||
use Some::Deeply::Nested::{Class, Interface}
|
use Some::Deeply::Nested::{Class, Interface}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
- Different module syntax
|
- Different module syntax
|
||||||
- Explicit module declaration
|
- Explicit module declaration
|
||||||
@ -237,7 +238,7 @@ Where possible THP will compile to available PHP functions/classes/methods/etc.
|
|||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
// This expression
|
// This expression
|
||||||
val greeting =
|
val greeting =
|
||||||
match get_person()
|
match get_person()
|
||||||
@ -253,7 +254,7 @@ val greeting =
|
|||||||
{
|
{
|
||||||
"Nobody is here"
|
"Nobody is here"
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// Would compile to:
|
// Would compile to:
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
layout: ../../../layouts/DocsLayout.astro
|
layout: ../../../layouts/DocsLayout.astro
|
||||||
title: Introduction
|
title: Introduction
|
||||||
---
|
---
|
||||||
|
import Code from "../../../components/Code.astro"
|
||||||
|
|
||||||
# THP templating
|
# THP templating
|
||||||
|
|
||||||
@ -60,18 +61,19 @@ and compose them.
|
|||||||
|
|
||||||
The following would be the equivalent in THP:
|
The following would be the equivalent in THP:
|
||||||
|
|
||||||
```thp
|
<Code thpcode={`
|
||||||
fun Button(String name) -> Html {
|
fun Button(String name) -> Html {
|
||||||
<button class="some tailwind classes">
|
<button class="some tailwind classes">
|
||||||
Hello {name}!
|
Hello {name}!
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
It is very similar to React. The HTML is inside the THP code, not the other
|
It is very similar to React. The HTML is inside the THP code, not the other
|
||||||
way around, so you can have arbitrary logic in the component.
|
way around, so you can have arbitrary logic in the component.
|
||||||
|
|
||||||
```thp
|
|
||||||
|
<Code thpcode={`
|
||||||
fun User(String name) {
|
fun User(String name) {
|
||||||
// Get info from the database
|
// Get info from the database
|
||||||
val user = try Model::get_user(name)
|
val user = try Model::get_user(name)
|
||||||
@ -96,9 +98,6 @@ fun TransactionItem(Transaction t) {
|
|||||||
{t.date} - {t.name} ({t.price})
|
{t.date} - {t.name} ({t.price})
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user