Skip to content

Latest commit

 

History

History
378 lines (274 loc) · 6.47 KB

Syntax.md

File metadata and controls

378 lines (274 loc) · 6.47 KB

Light Syntax

This document specify the core syntax rules for the language.

General Rules

  • no inheritance - this is made with composition (Rusty like)
  • named parameters (based on OCalm link)
  • case sensitive
  • LISP like syntax

Comments

Simple comments (ELM):

-- Comments are markdown by default

Multiline comments (ELM) are Markdown by default:

{- a multiline comment based on ELM
   {- can be nested -}
-}

Multiline typed comments (Light) gives information about how comments are rendered:

{-xml The `let` keyword defines an (immutable) value -} -- rendered as XML
{-sql select * from table -}                            -- rendered as SQL
{-md select * from table -}                             -- rendered as Markdown

Type annotations (CoffeeScript):

{-# This comment will be transpiled together #-} -- for Zig will be transpiled to // This comment will be transpiled together 

Types

i8 i16 i32 i64 i128 i256 -- i integers (Zig)
u8 u16 u32 u64 u128 u256 -- u unsigned integers (Zig)
f32 f64 -- float numbers (Zig)
f32.31 -- signed float number with 32 bits and 31 bits for mantissa -- TODO How many bits mantissa can use? (Light)
f64.32 -- signed float number with 64 bits and 32 bits for mantissa (Light)
uf32.31 -- unsigned float number with 32 bits and 31 bits for mantissa (Light)
uf64.32 -- unsigned float number with 64 bits and 32 bits for mantissa (Light)
c8 c16 -- c chars -- TODO
s8 s16 -- s strings -- TODO
b1 b8  -- b boolean -- TODO Do booleans always have 8 bits?
:a :b  -- atoms (Elixir, LISP)
binary -- something like userdata on Fennel

Rust: * Zig: *

Values

"hello"           -- or ["hello"] one string value
["hello" "world"] -- two string values
3.14              -- or [3.14] one float value
[3.14 4.15]       -- two float values (tuple)
[3.14 4.15 5.15]  -- three float values (tuple)
date 2023 12 3    -- dates are always in the order year, month, day

Variables

(let my_name) ; default value
(let my_name "Adelar") ; custom value
(let my_name _) ; no initialization

(let "my name") ; default value
(let "my name" "Adelar") ; custom value
(let "my name" _) ; no initialization

Operators (C based symbols)

Operators as functions. Predefined operators:

Comparation:

  • (== 2 2)
  • (!= 2 3)
  • (< 2 3 5) -- incresing operator
  • (> 2 3 5) -- decreasing operator
  • (<= 2 3 5) -- incresing operator
  • (>= 2 3 5) -- decreasing or equal operator

Aritmetic:

  • (+ 1), (+ 1 3), (+ 1 3 4)
  • (- 3), (- 3 2), (- 3 2 4)
  • (/ 4), (/ 4 2), (/ 4 2 4)
  • (* 2), (* 2 4), (* 2 4 6)
  • (% 2), (% 2 4), (% 2 4 5) -- remainder
  • (%% 2 4) -- canonical modulus operation

Logical:

  • (and true true)
  • (or false true)
  • (not false)
  • (nand true true)
  • (nor true true)
  • (xor true false)
  • (xnor true true)
  • (mux true true)
  • (demux true true true)

Binaries:

  • (& 3 2)

  • (| 3 2)

  • (^ 3 2)

  • (>> 3 2)

  • (<< 3 2)

  • (>>> 3 2)

  • *

Functions

-- Closures are defined with -> 
(-> [x y]
   (x + y))

-- Functions are defined with fn
(fn sum [x y]
    (x + y))

-- Defined return type
(: sum i32 i32 i32)
(fn sum [x y]
    (x + y))
   
-- Multiple return types (confirm)
(: sumOrSub i32 i32 [i32 i32])
(fn sumOrSub [x y]
    (x + y)
    (x - y))
   
-- Defining new operators
(fn * [x y]
    (100))
    
-- Defining function names as strings
-- ? defines a test
(test "returns a sum"
   (let s = sum 10 20)
   (assert = 30 s))

Default values:

(: sum i32 i32 i32)
(fn sum [(x 10) y]
    (x + y))

(: (list i32) (?))
(fn array2list [(list [10,10,10])]
    (...))

Generics

Most of the cases there is no need to specify types. Something like F# uses.

Closures

Closures are funcions without name:

// Closures are defined with -> 
(-> [x y] (+ x y))

Defining operators

(: _ _ i32)
(fn * [x y]
    (100))

(: a a a)
(fn * [x y]
    (100))

Another Types

-- Generic record, with the type parameter in angle brackets
(: a a a)
(type MyRecord
     (Field1)
     (Field2))

-- Generic discriminated union
(: a a a*a) -- TODO
(type MyUnion =
    (| (Choice1)
       (Choice2)))

Complex Types

Tuple

(tuple [1 2])

Array

A raw array that can be acessed by an integer index

(array [1 3 4 5])

List

A linked list:

(list [1 3 4 5])

Sequence

Itens are generated by demand:

(seq [1 2 3 4])

Flux Control

Conditionals

if

(if (> a 11)
  ("> 11")   -- true
  ("<= 11")) -- false

1

case

(case maybeList
  (Just xs xs)
  (Nothing []))

(case xs
  ([] Nothing)
  (first :: rest (Just (first, rest))))

(case n
  (0 1)
  (1 1)
  (_ fib (n-1) + fib (n-2)))

Loops

(for ((i 0) (< i 10) (++ i))
   (print i)
   (print "...")
)

(for (i (.. 0 10 ))
   (print i)
   (print "...")
)

Low Level

Pointers and References

(let a 1)
(let pointer ^a)
(let reference a^)

1

Core Library

Default functions

  • len - give value lenght

  • try - same as try from Zig link

(try calculate result) ; same as `const result = try calculate();`  
  • map
(map myfunction values)
  • reduce
(reduce myfunction values)
  • |> - same as |> operator on F#
(|> values
    f1
    f2)
  • . - fluent function. Call a number of functions for the value, returning a tupple
(. value
    f1
    f2)
  • .. - generate sequence
(.. 1 10) ; 1 2 3 4 5 6 7 8 9 10
  • / - string split link
(/ "first line\nsecond line" "\n")
  • cast - convert one type to another
(cast int32 int64 9)
  • ? - returns first non error/empty value. Something like ternary operators, but for multiple values
(? none error "value")
  • ?. - conditional member access
(?. level1 level2 level3 value)
if(level1 != null && level1.level2 != null && level1.level2.level3 != null){ ... }