feat: Add docs
This commit is contained in:
parent
3f388b8e22
commit
e6df715955
@ -9,8 +9,7 @@ const [native_html, error_type, error_message] = await native_highlighter(thpcod
|
||||
---
|
||||
|
||||
<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>
|
||||
class="language-thp"><code class="language-thp" set:html={native_html} /><span class="absolute top-1 right-1 text-right inline-block text-sm select-none opacity-75">thp</span></pre>
|
||||
{
|
||||
no_warnings !== true && error_message !== null && (
|
||||
<CodeError error_type={error_type} error_message={error_message} />
|
||||
|
@ -30,18 +30,24 @@ const { showSidebarButton = true } = Astro.props;
|
||||
>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
href="/api/std/"
|
||||
class="hidden sm:inline-block px-4 font-display font-bold-text-xl hover:underline"
|
||||
>
|
||||
Standard Library
|
||||
</a>
|
||||
<a
|
||||
href="/api/help/"
|
||||
class="hidden sm:inline-block px-4 font-display font-bold-text-xl hover:underline"
|
||||
>
|
||||
Help
|
||||
</a>
|
||||
<a
|
||||
href="/spec/"
|
||||
class="hidden sm:inline-block px-4 font-display font-bold-text-xl hover:underline"
|
||||
>
|
||||
Language spec
|
||||
</a>
|
||||
<a
|
||||
href="/api/std/"
|
||||
class="hidden sm:inline-block px-4 font-display font-bold-text-xl hover:underline"
|
||||
>
|
||||
std reference
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
<div class="two-column grid grid-cols-[10rem_auto]">
|
||||
---
|
||||
const {cols} = Astro.props;
|
||||
const grid_cols = cols ?? "grid-cols-[10rem_auto]";
|
||||
---
|
||||
|
||||
<div class={`two-column grid ${grid_cols}`}>
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -13,6 +13,7 @@ const indexSubpath = `/learn/index.mdx`;
|
||||
posts={posts}
|
||||
indexSubpath={indexSubpath}
|
||||
basePath="/learn/"
|
||||
disable_container={!!frontmatter.disable_container}
|
||||
>
|
||||
<slot />
|
||||
</PagesLayout>
|
||||
|
@ -10,6 +10,7 @@ const {
|
||||
posts: _posts,
|
||||
indexSubpath,
|
||||
basePath,
|
||||
disable_container,
|
||||
} = Astro.props;
|
||||
const posts: Record<string, any>[] = _posts;
|
||||
|
||||
@ -78,7 +79,7 @@ for (const entry of pagesIndex) {
|
||||
<Navbar />
|
||||
|
||||
<div
|
||||
class="lg:grid lg:grid-cols-[14rem_auto_12rem] lg:container mx-auto font-display"
|
||||
class={`lg:grid lg:grid-cols-[14rem_auto_12rem] ${disable_container? "": "lg:container"} mx-auto font-display`}
|
||||
>
|
||||
<div
|
||||
id="sidebar"
|
||||
@ -95,7 +96,7 @@ for (const entry of pagesIndex) {
|
||||
</div>
|
||||
|
||||
<main
|
||||
class="py-[3.5rem] lg:pl-12 lg:pr-4 markdown min-w-0 small-container mx-auto"
|
||||
class="pt-[3.5rem] pb-[10rem] lg:pl-12 lg:pr-4 markdown min-w-0 small-container mx-auto"
|
||||
>
|
||||
<slot />
|
||||
</main>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { leftTrimDedent } from "../components/utils";
|
||||
import { HighlightLevel } from "./types";
|
||||
import type { LexError, SyntaxError, Token, TokenizeResult, TokenType } from "./types";
|
||||
import type { MistiErr, Token, TokenizeResult, TokenType } from "./types";
|
||||
|
||||
const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500";
|
||||
|
||||
@ -12,7 +12,7 @@ export async function native_highlighter(code: string, level = HighlightLevel.Sy
|
||||
let result = await native_lex(formatted_code);
|
||||
return highlight_syntax(formatted_code, result, level);
|
||||
} catch (error) {
|
||||
return compiler_error(formatted_code, error as Error);
|
||||
return compiler_error(formatted_code, error as MistiErr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ function highlight_syntax(code: string, result: TokenizeResult, level: Highlight
|
||||
const [tokens, semanticError] = result.SemanticError;
|
||||
|
||||
if (level === HighlightLevel.Semantic) {
|
||||
return semantic_error_highlighter(code, tokens, semanticError.Semantic!);
|
||||
return semantic_error_highlighter(code, tokens, semanticError);
|
||||
} else {
|
||||
tokens_final = tokens;
|
||||
}
|
||||
@ -31,13 +31,13 @@ function highlight_syntax(code: string, result: TokenizeResult, level: Highlight
|
||||
const [tokens, syntaxError] = result.SyntaxError;
|
||||
|
||||
if (level === HighlightLevel.Semantic || level === HighlightLevel.Syntactic) {
|
||||
return syntax_error_highlighter(code, tokens, syntaxError.Syntax!);
|
||||
return syntax_error_highlighter(code, tokens, syntaxError);
|
||||
} else {
|
||||
tokens_final = tokens;
|
||||
}
|
||||
} else if (result.LexError) {
|
||||
// There is no error level that bypasses a lex error
|
||||
return lex_error_highlighter(code, result.LexError!.Lex!);
|
||||
return lex_error_highlighter(code, result.LexError!);
|
||||
} else if (result.Ok) {
|
||||
tokens_final = result.Ok;
|
||||
} else {
|
||||
@ -56,7 +56,7 @@ function highlight_syntax(code: string, result: TokenizeResult, level: Highlight
|
||||
/**
|
||||
* Highlights code that has a lexic error
|
||||
*/
|
||||
function lex_error_highlighter(code: string, error: LexError): [string, string, string] {
|
||||
function lex_error_highlighter(code: string, error: MistiErr): [string, string, string] {
|
||||
// Create a single error token
|
||||
|
||||
const err_pos = error.position;
|
||||
@ -73,7 +73,7 @@ function lex_error_highlighter(code: string, error: LexError): [string, string,
|
||||
return [all, "Lexical", error.reason + ` at line ${error_line}:${error_column} `]
|
||||
}
|
||||
|
||||
function syntax_error_highlighter(code: string, tokens: Array<Token>, error: SyntaxError): [string, string, string] {
|
||||
function syntax_error_highlighter(code: string, tokens: Array<Token>, error: MistiErr): [string, string, string] {
|
||||
const highlighted = highlight_tokens(code, tokens, error.error_start, error.error_end);
|
||||
const [error_line, error_column] = absolute_to_line_column(code, error.error_start);
|
||||
|
||||
@ -81,7 +81,7 @@ function syntax_error_highlighter(code: string, tokens: Array<Token>, error: Syn
|
||||
return [highlighted, "Syntax", error_message];
|
||||
}
|
||||
|
||||
function semantic_error_highlighter(code: string, tokens: Array<Token>, error: SyntaxError): [string, string, string] {
|
||||
function semantic_error_highlighter(code: string, tokens: Array<Token>, error: MistiErr): [string, string, string] {
|
||||
const highlighted = highlight_tokens(code, tokens, error.error_start, error.error_end);
|
||||
const [error_line, error_column] = absolute_to_line_column(code, error.error_start);
|
||||
|
||||
@ -89,7 +89,7 @@ function semantic_error_highlighter(code: string, tokens: Array<Token>, error: S
|
||||
return [highlighted, "Semantic", error_message];
|
||||
}
|
||||
|
||||
function compiler_error(code: string, error: Error): [string, string, string] {
|
||||
function compiler_error(code: string, error: MistiErr): [string, string, string] {
|
||||
return [code, "Fatal Compiler", error.message];
|
||||
}
|
||||
|
||||
@ -225,7 +225,6 @@ function translate_token_type(tt: TokenType, value: string): string {
|
||||
case "FOR":
|
||||
case "IN":
|
||||
case "WHILE":
|
||||
case "LOOP":
|
||||
case "MATCH":
|
||||
case "CASE":
|
||||
return "keyword";
|
||||
|
@ -43,38 +43,29 @@ export type TokenType =
|
||||
| "CASE"
|
||||
;
|
||||
|
||||
export interface Err {
|
||||
Lex?: LexError
|
||||
Syntax?: SyntaxError
|
||||
Semantic?: SemanticError
|
||||
export interface MistiErr {
|
||||
error_code: number
|
||||
error_offset: number
|
||||
labels: Array<ErrorLabel>
|
||||
note: string | null,
|
||||
help: string | null,
|
||||
}
|
||||
|
||||
export interface LexError {
|
||||
position: number
|
||||
reason: string
|
||||
}
|
||||
|
||||
export interface SyntaxError {
|
||||
error_start: number
|
||||
error_end: number
|
||||
reason: string
|
||||
}
|
||||
|
||||
export interface SemanticError {
|
||||
error_start: number
|
||||
error_end: number
|
||||
reason: string
|
||||
export interface ErrorLabel {
|
||||
message: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
|
||||
export interface TokenizeResult {
|
||||
/** All checks passed */
|
||||
Ok?: Array<Token>,
|
||||
/** There were semantic errors */
|
||||
SemanticError?: [Array<Token>, Err],
|
||||
SemanticError?: [Array<Token>, MistiErr],
|
||||
/** There were syntax errors */
|
||||
SyntaxError?: [Array<Token>, Err],
|
||||
SyntaxError?: [Array<Token>, MistiErr],
|
||||
/** No checks passed */
|
||||
LexError?: Err,
|
||||
LexError?: MistiErr,
|
||||
}
|
||||
|
||||
export enum HighlightLevel {
|
||||
|
@ -1,62 +0,0 @@
|
||||
---
|
||||
layout: ../../layouts/DocsLayout.astro
|
||||
title: Cheatsheet
|
||||
---
|
||||
|
||||
# Language cheatsheet
|
||||
|
||||
Comparisons to PHP are noted.
|
||||
|
||||
```thp
|
||||
// THP code is written directly, it's not enclosed in any ?php tag
|
||||
|
||||
// Single line comments are written with two slashes
|
||||
|
||||
/*
|
||||
Multiline comments use slash-asterisk
|
||||
and can be /* nested */
|
||||
*/
|
||||
|
||||
// print writes input to stdout in terminal mode
|
||||
print("Hello world")
|
||||
```
|
||||
|
||||
## Types and variables
|
||||
|
||||
```thp
|
||||
// Variables are always declared
|
||||
// Variables don't start with a dollar sign ($)
|
||||
// Variables are declared with `var`
|
||||
var age = 32
|
||||
|
||||
// Immutable variables are declared with `val`,
|
||||
// and can't be reassigned
|
||||
val name = "John"
|
||||
|
||||
// A variable name starts with either a:
|
||||
// - lowercase letter
|
||||
// - underscore
|
||||
// and then may contain any letter, underscore or number
|
||||
val my_variable = "my value"
|
||||
|
||||
// Datatypes' names start with an uppercase letter, always
|
||||
// A declaration may optionally specifiy its datatype, after
|
||||
// the var/val keyword
|
||||
var String lastname = "Doe"
|
||||
|
||||
//
|
||||
// Bool
|
||||
//
|
||||
|
||||
// Booleans are only `true` and `false`, case sensitive
|
||||
val condition = true
|
||||
val accepted = false
|
||||
|
||||
//
|
||||
// Int
|
||||
//
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
230
src/pages/learn/cheatsheet.mdx
Normal file
230
src/pages/learn/cheatsheet.mdx
Normal file
@ -0,0 +1,230 @@
|
||||
---
|
||||
layout: ../../layouts/DocsLayout.astro
|
||||
title: Cheatsheet
|
||||
disable_container: true
|
||||
---
|
||||
import TwoColumn from "../../components/TwoColumn.astro"
|
||||
import Code from "../../components/Code.astro"
|
||||
|
||||
# Language cheatsheet
|
||||
|
||||
Comparisons to PHP are noted.
|
||||
|
||||
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
|
||||
|
||||
<Code thpcode={`
|
||||
// THP code is written directly, it's not enclosed in any ?php tag
|
||||
// Single line comments are written with two slashes
|
||||
|
||||
/*
|
||||
Multiline comments use slash-asterisk
|
||||
and can be /* nested */
|
||||
*/
|
||||
|
||||
// there is no echo, only print
|
||||
// Unlike PHP, parenthesis are required
|
||||
print("Hello world")
|
||||
`} />
|
||||
|
||||
```php
|
||||
<?php
|
||||
// PHP requires a <?php opening tag
|
||||
|
||||
/*
|
||||
PHP cannot nest multiline comments
|
||||
/* this would be an error * /
|
||||
*/
|
||||
|
||||
# PHP also has hash comments. THP doesn't
|
||||
|
||||
print "Hello world";
|
||||
```
|
||||
</TwoColumn>
|
||||
|
||||
|
||||
|
||||
|
||||
## Variables
|
||||
|
||||
|
||||
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
|
||||
|
||||
<Code no_warnings={true} thpcode={`
|
||||
// THP has explicit variable declaration
|
||||
// Variables don't start with a dollar sign ($)
|
||||
// Variables are declared with \`var\`
|
||||
var age = 32
|
||||
|
||||
// Immutable variables are declared with \`val\`,
|
||||
// and can't be reassigned
|
||||
val name = "John"
|
||||
|
||||
// Variables may have a datatype declaration
|
||||
// This is an immutable variable with a type
|
||||
String road = "Abbey road"
|
||||
// This is a mutable variable with a type
|
||||
var String name = "The Beatles"
|
||||
`} />
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
|
||||
$age = 32;
|
||||
|
||||
|
||||
// There is no PHP equivalent
|
||||
$name = "John";
|
||||
|
||||
// You can't annotate the type of a variable in PHP
|
||||
|
||||
$road = "Abbey road";
|
||||
|
||||
$name = "The Beatles";
|
||||
```
|
||||
|
||||
</TwoColumn>
|
||||
|
||||
## Datatypes
|
||||
|
||||
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
|
||||
<Code no_warnings={true} thpcode={`
|
||||
// Only double quotes, never single quotes
|
||||
String name = "Jane"
|
||||
// Interpolation
|
||||
String full_name = "{name} Doe"
|
||||
|
||||
Int age = 25
|
||||
Float interest = 3.22
|
||||
|
||||
// An integer with a leading zero is an error,
|
||||
// you must use \`0o\` for octal
|
||||
// Int invalid = 0755
|
||||
Int valid = 0o755
|
||||
|
||||
// Case sensitive, only \`true\` or \`false\`
|
||||
Bool has_a_cute_dress = true
|
||||
`} />
|
||||
```php
|
||||
|
||||
$name = 'Jane';
|
||||
|
||||
$full_name = "$name Doe";
|
||||
|
||||
$age = 25;
|
||||
$interest = 3.22;
|
||||
|
||||
|
||||
|
||||
$invalid = 0755;
|
||||
$valid = 0o755;
|
||||
|
||||
// PHP allows true/false in any case, for some reason
|
||||
$has_a_cute_dress = TrUe;
|
||||
```
|
||||
</TwoColumn>
|
||||
|
||||
|
||||
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
|
||||
<Code no_warnings={true} thpcode={`
|
||||
// String concatenation uses \`++\`
|
||||
print("Hello " ++ "world")
|
||||
|
||||
// Basic operators
|
||||
var res = 1 + 2 - 3 * 4 % 5
|
||||
|
||||
res += 2
|
||||
res -= 2
|
||||
res *= 2
|
||||
res /= 2
|
||||
res %= 2
|
||||
|
||||
// There are no prefix/postfix increment/decrement
|
||||
//
|
||||
//
|
||||
`} />
|
||||
```php
|
||||
|
||||
print("Hello " . "world");
|
||||
|
||||
|
||||
$res = 1 + 2 - 3 * 4 % 5;
|
||||
|
||||
res += 2;
|
||||
res -= 2;
|
||||
res *= 2;
|
||||
res /= 2;
|
||||
res %= 2;
|
||||
|
||||
|
||||
++res;
|
||||
res--;
|
||||
```
|
||||
</TwoColumn>
|
||||
|
||||
## Flow control
|
||||
|
||||
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
|
||||
<Code no_warnings={true} thpcode={`
|
||||
// Parenthesis not required, braces required
|
||||
if age < 18
|
||||
{
|
||||
print("Not allowed")
|
||||
}
|
||||
else if age == 18
|
||||
{
|
||||
print("Allowed, barely")
|
||||
}
|
||||
else
|
||||
{
|
||||
print("Allowed")
|
||||
}
|
||||
|
||||
// Conditionals are expressions
|
||||
val gift = if prefers_silver
|
||||
{
|
||||
"silver necklace"
|
||||
}
|
||||
else
|
||||
{
|
||||
"gold necklace"
|
||||
}
|
||||
`} />
|
||||
|
||||
```php
|
||||
|
||||
if (age < 18) {
|
||||
print("Not allowed");
|
||||
} else if (age === 18) {
|
||||
print("Allowed, barely");
|
||||
} else {
|
||||
print("Allowed");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$gift = "";
|
||||
if (prefers_silver) {
|
||||
$gift = "silver necklace";
|
||||
} else {
|
||||
$gift = "gold necklace";
|
||||
}
|
||||
```
|
||||
</TwoColumn>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<TwoColumn cols="grid-cols-[1fr_1fr] gap-2">
|
||||
<Code no_warnings={true} thpcode={`
|
||||
`} />
|
||||
```php
|
||||
```
|
||||
</TwoColumn>
|
@ -152,7 +152,7 @@ and plugins for major editors like VSCode and Neovim.
|
||||
|
||||
## Not goals
|
||||
|
||||
These are **not** aspects that THP looks to solve or implement.
|
||||
These are **not** things that THP wants to solve or implement
|
||||
|
||||
- Be what TypeScript is for JavaScript (PHP with types).
|
||||
- Strictly adhere to PHP syntax/conventions.
|
||||
|
@ -7,11 +7,13 @@ title: Install
|
||||
|
||||
**THP is not available for public use. These are goals.**
|
||||
|
||||
## From scratch
|
||||
## Binary
|
||||
|
||||
Goal: Install THP with a single binary. Assumes that php and composer is
|
||||
available.
|
||||
|
||||
Also install php (through XAMPP in windows/mac, php in linux) and Composer.
|
||||
|
||||
## With composer
|
||||
|
||||
TBD, the user should be able to just run `composer require thp` and
|
||||
the proper binary should be intalled.
|
||||
TBD: Install THP with `composer require thp`
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user