Add documentation from previous web page

This commit is contained in:
Araozu 2023-03-28 19:18:06 -05:00
parent 3197d4ed05
commit a9ee398440
19 changed files with 1153 additions and 8 deletions

View File

@ -1,15 +1,29 @@
# Doc-generator # Doc-generator
Here is the generator for the webpage of the language. Here is the documentation of the language in markdown, and a program to
generate static HTML files from them.
## `src` folder ## `src` folder
Contains the code to generate HTML files from MD files. Rust code to generate HTML files from MD files.
The binary is called like:
```sh
generator --input /path/to/markdown/folder/ --output /path/to/static/folder
```
## `markdown` folder
Contains the Markdown. All files inside are expected to be UTF-8 encoded
markdown, and have the `.md` file extension.
## `static` folder ## `static` folder
Contains the HTML esqueleton, and the MD files. Contains CSS, JS, and HTML templates. Here the MD files are written to
after being converted.
## `dist` folder ## `dist` folder
Contains the generated HTML files. Coming soon, this folder will contain all HTML, CSS & JS minified after
running a script.

View File

@ -0,0 +1,16 @@
# Function calls
A function is called with parenthesis.
```misti
// No parameters: place opening and closing paren
debugState()
// 1 parameter
val result = fibonacci(20)
// 2 or more parameters: separate the parameters with commas
val remainder = substract(50, 30)
val total = add(60, -30, 90)
```

View File

@ -0,0 +1,3 @@
# Indentation rules
TBD

View File

@ -0,0 +1,80 @@
# Operators
Misti has similar operators to JS.
```md-warning
Misti will enforce type checking in operators at compile time.
<p>
However, due to how JS works, automatic type casting may still occur if you combine the Misti output with JS.
</p>
```
## Basic operators
```misti
4 + 2
4 - 2
4 * 2
4 / 2
4 % 2
4 ** 2
```
## Asignment operators
```misti
i += 1
i -= 1
i *= 2
i /= 2
i %= 2
i **= 2
```
## Bitwise operators
Not considered at the moment.
## Comparison
```misti
1 == 2
1 != 2
1 > 2
1 < 2
1 >= 2
1 <= 2
```
```md-warning
In Misti there's only double equals `==`.
<br>
<br>
<code>x == y</code> will ALWAYS compile to <code>x === y</code>
```
## Logical operators
```misti
true && false
true || false
!true
```
```md-warning
Multiple `!` are invalid, since there is no automatic type casting.
<br>
<br>
<code>!!</code> would be considered a different operator.
```
```md-warning
There is no short-circuit like so something like:
<br>
<br>
<code>true && "value"</code> will throw an error at compile time.
```

View File

@ -0,0 +1,35 @@
# Simple datatypes
The following are the primitive datatypes. They have literal representations.
## Num
Equivalent to a number in JS.
```misti
val f0 = 322
val f1 = 10.304
val f2 = -34.343223
val f3 = 0.234234e+2
val f4 = 1e+4
```
A floating point number __must__ have a digit before and after the dot.
```misti
val valid1 = 0.45
val valid2 = 13.0
// Will not be considered as floating point numbers
val invalid1 = .45 // Will be interpreted as the operator `.` and the integer 45
val invalid2 = 13. // Will be interpreted as the integer 13 and the operator `.`
```
## Bool
True and false
```
true
false
```

View File

@ -0,0 +1,61 @@
# Tuples
Tuples contain a fixed number of values of any datatype. They are denoted with
a hash and parenthesis.
```misti
val person = #("John", "Doe", 25)
val result = #(true, 200)
```
## Signature
```misti
// A tuple of Str, Str and Int
#(Str, Str, Int)
// An array of tuples. These tuples have a Str, Int and Bool
Array[#(Str, Int, Bool)]
// A function that takes a Str and Int, and return a tuple of Str and Int
(Str, Int) -> #(Str, Int)
// A function that takes a tuple of Str and Int, and returns a Bool
(#(Str, Int)) -> Bool
```
## Destructuring
In variable declaration
```misti
val data = #("String", 322, true)
val #(string, number, boolean) = data
val #(string, _, _) = data
```
In function parameters
```misti
// Without parameter destructuring
fun destructure(#(Str, Int) data) {
val #(name, age) = data
// Computations with name, age
}
// With parameter destructuring
fun destructure(#(Str name, Int age)) {
// Computations with name, age
// Note that now there is no way to refer to the whole tuple
}
// Parameter destructuring with tuple preservation
fun destructure(#(Str name, Int age) data) {
// Computations with name, age
// The tuple `data` can still be referred to
}
```

View File

@ -0,0 +1,108 @@
# Variables and Constants
Misti uses `var` for variables and `val` for constant reference variables.
Variables and constants must always be initialized.
```misti
// A variable, its value can be modified
var accumulator = 0
accumulator += 1
```
```misti
// A "constant", its value cannot be modified
val name = "Bob"
// Illegal, will raise an error in compile time
name = "Mike"
```
```md-info
If a constant's value is a primitive value, it cannot be changed.
<br />
However, if it is a reference value, its inner attributes can still
be changed, but not the reference itself.
```
## Identifiers
Identifiers start with a lower case letter or underscore,
and then can contain letters, numbers and underscores.
They can not start with a dollar sign.
```misti
variable
_variable
var1
v4r
```
If an identifier starts with an upper case letter, it is considered to be
a Datatype.
```misti
Str
Num
Bool
Array
Map
CustomDatatype
```
## Type inference
Variable declarations have type inference.
```misti
val anInteger = 40
val aFloat = 10.20e+4
var aBoolean = true
```
The datatype can be optionally specified by placing it before `var` or `val`.
```misti
Int val anInteger = 40
Float val aFloat = 10.20e+4
Bool var aBoolean = true
```
However, if the variable is a constant created with `val`,
this keyword is optional.
So, the following are equivalent.
```misti
Str val name = "Juan"
// is equivalent to
Str name = "Juan"
```
It is not possible to omit `var`. So the following will not mean the same.
```misti
Str var age = 20
// is not equivalent to
Str age = 20
// the previous statement is equivalent to:
// Str val age = 20
```
The second statement will declare a constant, not a variable.
## Assign a block to a variable
Assigning a block to a variable will execute the block,
and the last expression will be the value of the variable.
```misti
val roi =
val income = someIncomeCalculation()
val investment = 25000
income / investment // This will be the value of `roi`
```

View File

@ -0,0 +1,15 @@
# Classes
```misti
class Token(Str value, Int lineNumber, Int position)
val token1 = Token("if", 0, 0)
val token2 = Token(value: "else", lineNumber: 1, position: 4)
```
```misti
class FunToken(Int lineNumber, Int position)
-> Token("fun", lineNumber, position)
val funToken1 = FunToken(3, 0)
```

View File

@ -0,0 +1,49 @@
# Arrays
Arrays in Misti don't have special syntax for declaration.
They are created the following way instead:
```misti
// Array[Int]
val numbers = Array(10, 20, 30)
// Array[Str]
val names = Array("Pablo", "Kim", "Mike")
```
Accessing or mutating the array use a similar syntax to other languages.
```misti
// Access. Note the dot
val secondNumber = numbers.[1]
// Mutation. Note the dot
names.[2] = "Josh"
```
```md-warning
Place a dot between the array and square brackets to access or mutate an array.
<br>
<br>
If you don't place a dot, it will be interpreted as a generic parameter.
```
## Importance of placing a dot
If there is no dot between the array and square brackets, then it is parsed
as a generic parameter.
```misti
// Access or mutation
variable.[index]
val n = numbers.[0]
numbers.[1] = 20
// Generic parameter
arrayOf[Datatype]
arrayOf[Str]
arrayOf[Bool]
```

View File

@ -0,0 +1,33 @@
# Conditionals
Conditionals in Misti surround the condition with keywords,
and the body of each condition is defined with indentation.
```Misti
if condition do
// code...
else if anotherCondition do
// code...
else
// more code...
```
Conditionals are expressions, they evaluate to the last expression
in each branch.
```misti
val result = if condition do value1 else value2
```
## Early return
If you need to return early based on a condition,
you can use `ret` instead of `do` in a confition. The last expression of
the block will be returned
```misti
if condition ret
// code...
computedValue // this will be returned
```

View File

@ -0,0 +1,25 @@
# Loops
Loops are indentation-sensitive.
## For each
```misti
// Loop through an object
for key in object do
print(key)
// Loop through an array
for value of array do
print(value)
```
## While
```misti
while condition do
print("loop")
```

View File

@ -0,0 +1,89 @@
# Function definition
Functions are defined with `fun` followed by the name of the function,
the parameters, the return type, `=` and an expression.
## Function with no parameters
To declare a function with no parameters include `()`, and call it with `()`.
```misti
fun getName() =
// code...
val name = getName()
```
## Function that returns void/nothing
In Misti we return `Unit` instead of `void`, `null`, `undefined` or others.
So a function that doesn't return anything, would return `Unit`.
```misti
// This function just prints Hello and returns
fun printHello() -> Unit =
print("Hello")
```
This type, `Unit`, is treated like `void`, so it is ignored.
If a function doesn't return anything, `Unit` can be omitted.
```misti
// This first declaration
fun doSomething() -> Unit =
something()
// is equivalent to this one
fun doSomething() =
something()
```
## Function with return
First, the return type must be defined in the declaration.
Let's say that a function `getLuckyNumber` returns a Float, then it
would be declared like this:
```misti
fun getLuckyNumber() -> Float =
// Body of the function
```
And finally, the return value is the last expression in the function.
The following function will return 7.
```misti
fun getLuckyNumber() -> Float =
// This '7' is the last expression, so it will be returned
7
val number = getLuckyNumber() // number = 7
```
## Return multiple values
We can use a tuple if we need to return multiple values.
```misti
fun getPerson() -> #(Str, Int) =
// Logic...
#("Kim", 33)
fun tupleContains(#(Str, Int) data, Str key) -> #(Bool, Int) =
val #(currentKey, value) = data
if currentKey == key do
#(true, value)
else
#(false, 0)
tupleContains(#("Test", 200), "Test")
```

View File

@ -0,0 +1,67 @@
# Anonymous functions/Lambdas
```md-info
Subject to change
```
An anonymous consists of the `fn` keyword, parameters and body.
```misti
fn (x, y) {
// Body
x + y
}
```
The following types are optional, if we can be able to infer them:
- The types of the parameters
- The return type
If used, they would look like this:
```misti
fn (Int x, Int y) -> Int {
// Body
x + y
}
```
## Lambdas
If an anonymous function doesn't have parameters, the `fn` keyword may be omitted.
This is called a lambda.
```misti
{ doSomething() }
// The above lambda is equivalent to:
fn () {
doSomething()
}
```
## Inferred arguments
If the arguments of the lambda don't need names, the following
syntax can be used.
```misti
{ $1 + $2 }
```
Inside a short lambda you can use `$1`, `$2`, `$3`, etc. to refer to the
parameters of the lambda.
So the following are the same:
```misti
{ $1 + $2 }
// The same as:
fn (x, y) {
x + y
}
```

View File

@ -0,0 +1,101 @@
# Function parameters
## Function with 1 parameter
Place the parameter's datatype after the function's name, then the name of the parameter.
For example, a function that takes a `Str` as parameter is defined as follows:
```misti
fun sayHello(Str name) =
// Body of the function
```
Then the parameter `name` can be used.
```misti
fun sayHello(Str name) =
print("Hello {name}")
```
## Function with 2 or more parameters
The parameters are separated with commas:
```misti
// 2 parameters: x and y, both Int
fun add(Int x, Int y) -> Int =
x + y
```
```misti
// 3 parameters
fun substring(Str input, Int start, Int end) -> Str =
// Logic...
```
And so on.
## Generic parameters
Generic parameters consist of an uppercase letter enclosed in square brackets.
They are placed after the function name, but before the parameters list.
```misti
fun getItemAt[T](Array[T] arr, Int pos) -> T =
// Function body
```
When calling the function, the generic parameter is placed in the same position.
```misti
val thirdName = getItemAt[String](names, 2)
```
If the generic parameter can be inferred, it's not necessary to put it.
```misti
// Will be a String, inferred
val thirdName = getItemAt(names, 2)
```
## Named parameters
When calling a function you can link the name of an argument to its value.
In the following function, `substring` has 3 parameters: `string`, `start` and `end`.
```misti
fun substring(Str string, Int start, Int end) =
// Body of the function
```
Then, when calling the function, you can specify each parameter and their values.
```misti
// Without named parameters
substring("Hello, world!", 7, 12)
// With named parameters
substring(string: "Hello, world!", start: 7, end: 12)
substring(
string: "Hello, world!",
start: 7,
end: 12,
)
```
This will return `"world"`.
You can do computations with named parameters as well.
```misti
substring(string: "Hello, world!", start: 12 - 5, end: 48 / 4)
substring(
string: "Hello, world!",
start: 12 - 5,
end: 48 / 4,
)
```

356
doc-generator/markdown/en/docs/latest/index.md Normal file → Executable file
View File

@ -1,3 +1,355 @@
# Hello world! # Welcome
Misti is _yet another_ toy language to replace JavaScript.
__Misti is indentation based.__
It's objectives are:
- Reduce compilation times using Rust.
- Improve code quality by making the language more expressive.
- Make the language easy to understand by using a consistent syntax (at the expense of familiarity).
- Integrate with existing TypeScript definitions by importing and exporting `.d.ts` files.
- Serve as a side project.
The purpose of the language is to address many of the limitations of JS.
To serve that end, __many concepts from JS may be completely omitted
or replaced with different syntax/semantics__.
Such things will be noted in the documentation where neccesary.
## Syntax summary
```misti
//
// Variables and constants
//
var aVariable = 20
val aConstant = 30
aVariable = 40
// | semi colons not required
// Specify the datatype of a constant
Num aConstant = 30 // <- `val` is optional
// Specify the datatype of a variable
Num var aVariable = 20 // <- `var` required
// You can assign the result of many operations to a variable
val roi =
val income = someIncomeCalculation()
val investment = 25000
income / investment // This will be the value of `roi`
```
```misti
//
// Basic datatypes
//
Num number = 40.12345
Bool boolean = true
Str string = "John Doe"
```
```misti
//
// Conditionals
//
if name == "John Doe" do
val message = "Hello John"
console.log(message)
else if name == "Mark" do
console.log("Hi Mark!")
else
console.log("Hello there")
// You can use conditionals as expressions
val response = if risk < 0.2 do "Go ahead" else "Don't"
// There is no ternary conditional
```
```misti
//
// Arrays
//
val dates = Array(1990, 1995, 2014, 2015, 2017)
// | There isn't special syntax for array declaration
// so you can't do `[1990, 1995, ...]`
val firstDate = dates.[0]
// | Notice the dot for access
dates.[4] = 2018
// | Dot for mutation
// Array signature
Array[Num] dates = Array(1990, 1995, 2014, 2015, 2017)
// | Square brackets are used for generics
// instead of angle brackes.
```
```misti
//
// Tuples
//
val person = #("John", 30, true)
// Destructuring
var #(name, age, isMarried) = person
// Tuple signature
#(Str, Num, Bool) signature = #("John", 30, true)
```
```misti
//
// Loops
//
for key in object do
console.log("key: {key}, value: {object.[key]}")
for value of array do
console.log("value: {value}")
while condition do
print("while")
```
```misti
//
// Functions
//
console.log("Enclose the parameters in parens")
add(10, 20)
// Named parameters
substring(input: "Hello, world!", start: 7, end: 12)
// Funtion declaration
fun add(Num x, Num y) -> Num =
x + y
// Function with default value
fun calculate(Num price, Num discount = 0.0) =
val total = price * (1.0 - discount)
console.log("Your total is {total}$")
calculate(100, 0.25) // "Your total is 75$"
calculate(100) // "Your total is 100$"
```
```misti
//
// Objects
//
type Person = #{
Str name,
Num age,
}
val john = Person #{
name: "John",
age: 21,
}
// An object with arbitrary keys/values
val randomObject = #{
key1: "Any value"
key2: 322,
key3: true,
key4: #{
key5: "zzz",
},
key6: Person #{
name: "Sarah",
age: 20,
},
}
```
```misti
//
// Classes
//
// Declare a simple class
class Shape
// Classes can not be extended by default.
// To allow inheritance, use @open
@open
class Shape =
// By default methods can not be overrided.
// To allow it, use @open
@open
fun printName() =
print("Generic Shape")
val shape = Shape()
// | There's no `new` keyword, just call the class
shape.printName() // "Generic Shape"
@open
class Rectangle(Num height, Num length) -> Shape() =
// | Constructor parameters
// Properties are always private
val vertexCount = 4
// Methods are private by default
fun perimeter() -> Num =
(height + length) * 2
// To make a method public add @pub
@pub
fun area() -> Num =
height * length
// Method override
@override
fun printName() =
print("A rectangle")
val rectangle = Rectangle(10, 20)
rectangle.area() // 200
rectangle.printName() // "A rectangle"
class Square(Num length) -> Rectangle(length, length) =
// | Inheritance
@override
fun printName() =
console.log("A square")
fun printInfo() =
// Use $ to refer to methods/properties of the parent class
console.log("A square with perimeter = {$perimeter()} and area = {$area()}")
```
```misti
//
// Null safety
//
// Operations that may fail return an Option value
fun divide(Int numerator, Int denominator) -> Option[Num] =
if denominator == 0 do
None // Equivalent to `null`
else
Some(numerator / denominator)
val possibleResult = divide(10, 5)
if val Some(result) = possibleResult do
print("The result of the division is {result}")
else
print("Division by zero")
// `Type?` is syntax sugar for Option[Type]
Num? roi = divide(income, investment)
```
```misti
//
// Error handling
//
// A recoverable error
fun testVersionNumber(Str version) -> Result[Int, Str] =
if version == "10" do
Ok(10)
else if version == "11" do
Ok(11)
else
Err("Invalid version")
// Legacy try-catch (may change)
try problematicExpression() with
| Error(e) ->
// do something
// must return an expression
10
```
```misti
//
// Pattern matching
//
match age with
| 10 ->
// executes when age == 10
| 11 | 12 | 13 ->
// when age == 11, 12 or 13
| _ ->
// when none of the conditions match
Str? result = someOperation()
match result with
| Some(value) ->
// value is a Str
// do operations with v
| None ->
// Handle empty return
Result[Num, Str] result = someOtherOperation()
match result with
| Ok(number) ->
// number is Num
| Err(reason) ->
// reason is Str
Result[Num, Str] result = someOtherOperation()
match result with
| Ok(number) if number > 18 ->
// This matches if number > 18
| Ok(number) ->
// This matches if number <= 18
| Err(reason) ->
// reason is Str
```
```misti
//
// JSX
//
val element = &lt;div>This is JSX&lt;/div>
val list = items.map fun (item, count) {&lt;li key={count}>{item}&lt;/li>}
```
Sample index file

View File

@ -0,0 +1,34 @@
# Modules
```md-info
Subject to change
```
## Idea 1: Copy ES2015 modules
```misti
import React, {useState} from "react"
import "./utils/math"
```
## Idea 2: Python-like ES2015 modules
```misti
from "react" import React, {useState}
import "./utils/math"
```
## Idea 3: F#-like modules
```misti
use React
use Math
```
## Idea 4: Java-like modules
```misti
use React
use utils.Math
```

View File

@ -0,0 +1,34 @@
# Definition
Objects are defined with the syntax `#{}`
Objects should have a definition that specifies which fields it accepts.
```misti
type Position = #{
Num latitude,
Num longitude,
}
val position = Position #{
latitude: -93.0838749,
longitude: 80.2847561,
}
// Destructure
val Position #{latitude: lat, longitude: long} = position
```
## Arbitrary keys and values
```misti
val object2 = #{
key1: "sample",
key2: "text",
key3: 322,
}
object2.key1
```

View File

@ -13,7 +13,6 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<style> <style>
#transition { #transition {
width: 100%; width: 100%;
@ -22,7 +21,7 @@
} }
</style> </style>
</head> </head>
<body > <body>
<!-- <!--
<div class="py-6 pt-12 flex justify-center"> <div class="py-6 pt-12 flex justify-center">
<img src="/svg/logo_color.svg" alt="Misti logo" height="200" /> <img src="/svg/logo_color.svg" alt="Misti logo" height="200" />

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/tailwind/output.css" rel="stylesheet">
<link href="/styles/global.css" rel="stylesheet" />
<title>Misti</title>
<!-- Google fonts - Inter -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>
<body>
{{markdown}}
<script>
// Inter - Google fonts - load here as to not interrupt the page
const linkEl = document.createElement("link");
linkEl.href = "https://fonts.googleapis.com/css2?family=Inter:wght@100;300;400;500;700&display=swap";
linkEl.rel = "stylesheet";
document.head.appendChild(linkEl);
</script>
</body>
</html>