6.6 KiB
Executable File
6.6 KiB
Executable File
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
Variables and constants
//
// 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`
Basic datatypes
//
// Basic datatypes
//
Num number = 40.12345
Bool boolean = true
Str string = "John Doe"
Conditionals
//
// 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
Arrays
//
// 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.
Tuples
//
// Tuples
//
val person = #("John", 30, true)
// Destructuring
var #(name, age, isMarried) = person
// Tuple signature
#(Str, Num, Bool) signature = #("John", 30, true)
Loops
//
// 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")
Functions
//
// 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$"
Objects
//
// 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,
},
}
Classes
//
// 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()}")
Null safety
//
// 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)
Error handling
//
// 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
Pattern matching
//
// 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
JSX
//
// JSX
//
val element = <div>This is JSX</div>
val list = items.map fun (item, count) {<li key={count}>{item}</li>}