# Chap
[![forthebadge made-with-rust](http://ForTheBadge.com/images/badges/made-with-rust.svg)](https://www.rust-lang.org/)\
[![Rust](https://github.com/ali77gh/Chap/actions/workflows/rust.yml/badge.svg?branch=stable)](https://github.com/ali77gh/Chap/actions/workflows/rust.yml)
[![GitHub license](https://badgen.net/github/license/ali77gh/chap)](https://github.com/ali77gh/chap/blob/master/LICENSE)
Chap is an easy to learn, dynamic, interpretive, and keyword-less language written in Rust.
Remember, Chap is not a tool! its Art.
Syntax is something between [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)), [Assembly](https://en.wikipedia.org/wiki/Assembly_language) and [PHP](https://www.php.net/).
[ChapApp](https://github.com/ali77gh/chapAPP) is an offline Chap Editor/Compiler on Browser (Powered by WASM). ChapApp is written in Rust([Dioxus](https://dioxuslabs.com/)) as well.
Open ChapApp in a new tab.
## Table of content
1. [Why was it named 'Chap'?](#name)
1. [Features](#features)
1. [Keywords](#keywords)
1. [Syntax](#syntax)
1. [Operators](#operators)
1. [ControlFlow](#control-flow)
1. [Samples](#samples)
1. [Data Types](#datatypes)
1. [Memory Management](#memory-management)
1. [Installation](#installation)
1. [How to use](#how-to-use)
1. [Builtin function](#builtin-functions)
## Name
Rust or راست in persian means right and Chap or چپ means left.
If you code in rust(right) too much, you gradually become capitalist after a while. So you need to write some chap(left) to escape from the matrix.
Chap unlocks **Two-Dimensional** Full Stack Development. Front⬆️End, Back⬇️End, Rust➡️End, Chap⬅️End.
## Features
1. Easy to learn.
2. Cross platform (It runs on Linux, MacOS, Windows, Web(WASM))
## Keywords
What makes a programming language hard to learn?
```chp
"Keywords"
```
| Language | Keywords | Difficulty level |
|----------|-----------|------------------|
| C# | 102 | 5/5 |
| Java | 48 | 4/5 |
| Python | 35 | 3/5 |
| Lua | 22 | 2/5 |
| Chap | 0 | 0/5 |
There are no keywords in Chap.
## Syntax
A normal line of code in chap has 3 chunks separated with -> operator:
```chp
chunk1 -> chunk2 -> chunk3
```
| Chunk 1 | Chunk 2 | Chunk 3 |
|--------------|---------------|-----------------|
| input params | function name | output variable |
```chp
param1, param2 -> function_name -> $output_variable
```
For example:
```chp
1, 2 -> add -> $sum
```
1 and 2 separated by "," are input params.\
These input params are moving to "add" function.\
Finally $sum is a variable that holds the add result in it.
Note: "add" is not a keyword, it's a builtin function.
## Ok but why?
English language is a **"left to right"** (aka LTR) language, and programming languages should follow the same rule, right?
Wrong:
```javascript
// c base languages:
result = send(sqrt(1 + 2).toString());
↑ ↑ ↑ ↑ ↑
5 4 2 1 3
```
But chap:
```chp
// chap
1,2 -> add -> sqrt -> to_string -> send -> $result
↑ ↑ ↑ ↑ ↑
1 2 3 4 5
```
This is actually left to right like normal english.
Note: "Chain" syntax is added in version 2.0.0
## Syntax Rules
Make a comment with // and anything you write on the right side will be ignored by compiler.
```chp
1, 2 -> add -> $sum // this is a comment
```
You can write many lines of code in one line by separating lines by ";"
```chp
1 -> $a; $a, 2-> sum -> $b; $b -> print -> $_
```
Input params are separated by comma character ",".
Input params can be:
1. Variable
1. String with " character around like: "hello world"
1. Int just a number: 5
1. Float just a normal form of floating point number 3.14
1. Bool is a boolean value which is a true or false
1. Tags start with @. [(more on control flow)](#control-flow)
```chp
$a, "hello", 5, 3.14, false -> function_name -> $output_var
```
Function names are not case-sensitive.
Function names are not sensitive about anything else:
```chp
// to_string = ToString = TOSTRING = to string = t o s t r_i_n_g
```
Variables should start with $ which is known as the most loved feature of PHP.
Variable name rules:
```chp
$12 // Ok
$sp a ce // OK
$#^3 // Ok
$a,b // comma not allowed
$really? // question mark at the end not allowed
$rea?lly // OK
$some->thing // "->" is not allowed
```
## Short syntax features
If a function has no output variable you can remove chunk3:
```chp
"hello world" -> print
↑ ↑ ↑
input function removed chunk3
```
If a function has no input param you can remove chunk1:
```chp
input -> $user_input
↑ ↑ ↑
nothing function output
```
Removing chunk2 (function name) means assigning a variable:
```chp
1 -> $variable
// it's actually short for:
// 1 -> assign -> $variable
```
If a function has no input param and output_var you just write function name:
```chp
exit
```
If a function has output var but you removed chunk3 the result of function will get printed:
```chp
1, 2 -> add
// it's short for:
// 1, 2 -> add -> print
```
If you just write some params. chap will print them:
```chp
1, 2
// result: 1, 2
// or
$a
// prints whatever $a is
```
As you can guess, we have the world's smallest hello world:
```chp
"Hello World"
```
I wish I could remove double quotes too :)
## Chain syntax (aka pipe)
Sometimes you have a collection of function calls like this:
```chp
1, 2 -> add -> $tmp1
$tmp1 -> sqrt -> $tmp2
$tmp2 -> print
```
As you can see, output of a function call is input of the next function call.
In this case, you can use piping syntax to write functions next to each other and get rid of temp variables:
```chp
1, 2 -> add -> sqrt -> print
```
## Parentheses
You can't use Piping when one of the functions has more than one param.
```chp
1,2 -> add -> add -> print
↑
This needs two input params
```
In this case you can use Parentheses:
```chp
(1,2 -> add), (3 -> sqrt) -> add -> print
```
This converts two:
```chp
1,2 -> add -> $TMP1
3 -> sqrt -> $TMP2
$TMP1, $TMP2 -> add -> print
```
## Operators
There is one operator -> which moves data from left to right and it is language logo.
Why are operators bad?\
Because they behave different with different types.
Look at this python example:
```python
number = input("Enter a number:")
result = number * 5 # multiply number by 5
print(number, "* 5 =", result)
```
Following code has a bug and the result will be:
```python
Enter a number: 3
3 * 5 = 33333
# no runtime error
```
Why? Because Python uses the same operator for math.multiply and strings.repeat.
So * operator **"IS NOT A TYPE SAFE"** operator and it will **"DO UNEXPECTED THINGS"** when your forget to pass the right type to it and it will happen without throwing runtime errors (which is bad).
Same code in Chap:
```chp
input -> $number
$number, 5 -> multiply -> $result
$result
// error in line 2: multiply function works only with numbers int and float
```
Runtime errors are much better than logical errors, and in chap we have the repeat function:
```chp
"foo ", 3 -> repeat
// foo foo foo
```
In many languages "+" operator has the same problem:
```python
# Python
def add(a, b):
a + b # concat or add? both?
add("1", "2") # 12
add(1, 2) # 3
```
```chp
// Chap:
"1", "2" -> concat // 12
1, 2 -> concat // 12 // you can concat integers safely
1, 2 -> add // 3
"1", "2" -> add // runtime error
```
## Debugger
You can put a ? at the end of function name to debug that line:
```chp
1 -> $a
2 -> $b
$a, $b -> add? -> $c
// result 1, 2 -> add -> 3
```
Chap also has a function called "dump" which prints every variable you have.
## Control Flow
You can create a tag like this:
```chp
@tag_name
```
And you can jump to it:
```chp
@tag_name -> jump
// or
@tag_name, true -> jump_if
// or
@tag_name, 1, 1 -> jump_if_equal
// or
@tag_name, 1, 0 -> jump_if_not_equal
```
## loop
Jumping backward makes loops:
```chp
@l
"Hello until your battery dies"
@l -> jump
```
## if
```chp
@i, 1, 1 -> jump_if_equal
"this will not print"
@i
```
Note: Indention is not necessary
## Array
Initialize:
```chp
[1 2 3 4] -> $myArray
```
Insert:
```chp
$myArray, 5 -> insert
```
Pop:
```chp
$myArray-> pop -> $last_item
```
Get item by index:
```chp
$myArray, 1 -> get -> $first_item
// arrays index start from 1
```
## Samples
Note: You can test and tweak samples at [ChapApp](https://ali77gh.github.io/ChapApp/).
## hello_world.chp
```chp
"Hello world"
```
```sh
Hello world
```
## counter.chp
```chp
0 -> $counter
@l
$counter -> increase
@l, $counter, 100 -> jump_if_not_equal
$counter
```
```sh
100
```
## number_guess_game.chp
```chp
1,10 -> random_number -> $answer
@loop
input -> $guess
$guess -> to_int -> $guess
@win, $answer, $guess -> jump_if_equal
"wrong"
@loop -> jump
@win
"you win"
```
```sh
1
wrong
2
wrong
3
you win
```
## christmas_tree.chp
```chp
// Editable
0 -> $counter
@loop
$counter -> increase
$counter, 2 -> multiply -> $stars_size
10, $counter -> minus -> $space_size
"*", $stars_size -> repeat -> $stars
" ", $space_size -> repeat -> $spaces
$spaces, $stars -> cat
@loop, $counter, 10 -> jump if not equal
```
```sh
**
****
******
********
**********
************
**************
****************
******************
********************
```
## christmas_tree_with_trunk.chp
```chp
// Editable
0 -> $counter
@loop
$counter -> increase
$counter, 1 -> multiply -> $stars_size
19, $counter -> minus -> $space_size
" * ", $stars_size -> repeat -> $stars
" ", $space_size -> repeat -> $spaces
$spaces, $stars -> cat
"`*-", $stars_size -> repeat -> $stars
" ", $space_size -> repeat -> $spaces
$spaces, $stars -> cat
@loop, $counter, 10 -> jump if not equal
3 -> $c
@loop
$c-> increase
$c, 2 -> multiply -> $stars_size
22, $c-> minus -> $space_size
"*", $stars_size -> repeat -> $stars
" ", $space_size -> repeat -> $spaces
$spaces, $stars -> cat
@loop, $c, 7 -> jump if not equal
```
```sh
*
`*-
* *
`*-`*-
* * *
`*-`*-`*-
* * * *
`*-`*-`*-`*-
* * * * *
`*-`*-`*-`*-`*-
* * * * * *
`*-`*-`*-`*-`*-`*-
* * * * * * *
`*-`*-`*-`*-`*-`*-`*-
* * * * * * * *
`*-`*-`*-`*-`*-`*-`*-`*-
* * * * * * * * *
`*-`*-`*-`*-`*-`*-`*-`*-`*-
* * * * * * * * * *
`*-`*-`*-`*-`*-`*-`*-`*-`*-`*-
********
**********
************
**************
```
## DataTypes
```chp
1 -> type_of
int
3.14 -> type of
float
"ali" -> TypeOf
string
true -> type
boolean
-> [1 2 3] -> type
list
```
## Memory Management
Your OS will free memory after process is done!
## Installation
### Download release
[link](https://github.com/ali77gh/Chap/releases)
### Build from source
```bash
git clone https://github.com/ali77gh/Chap
cargo build --release
sudo cp ./target/release/chap /usr/bin
```
## How To Use
### REPL (Run Execute Print Loop)
[./repl/mod.rs](https://github.com/ali77gh/Chap/blob/master/src/repl/mod.rs)
```bash
❯ chap
-> "hello world"
hello world
->
```
### File_executor
[./file_executor/mod.rs](https://github.com/ali77gh/Chap/blob/master/src/file_executor/mod.rs)
```bash
❯ chap number_guess_game.chp
1
wrong
2
wrong
3
you win answer was: 3
```
### Use As lib
[./lib.rs](https://github.com/ali77gh/Chap/blob/master/src/lib.rs)
```bash
cargo add chap # this include eval function
```
or
```bash
cargo build --release --lib
```
## Release Note version 2.0.0
- [x] Arrays
- [x] fix: 'random' module will not work on WASM
- [x] eval function
- [x] [ChapApp](https://github.com/ali77gh/ChapApp)
- [x] Piping syntax (1, 2 -> add -> toString -> print)
- [x] Parentheses (1, 2 -> add), (2, 3 -> add) -> concat -> $var // 35
- [x] New debugger syntax 1,2 -> add? -> $sum
## Stars
[![Stargazers over time](https://starchart.cc/ali77gh/chap.svg)](https://starchart.cc/ali77gh/chap)
## Builtin Functions
[runtime/builtin_function](https://github.com/ali77gh/Chap/tree/master/src/runtime/builtin_function)\
Chap has 49 builtin function(version 2.0.0) (less than Java's keywords)
| Names | Input params | output | description |
|-------------------------|-------------------|----------|-------------------------------------------------------------|
| assign | any | any | put a value or variable in other variable 1 -> $a |
| std_out, print, show | any, any, any,... | any | prints params to console |
| std_in, input | nothing | string | read user input from console |
| exit, quit, kill, end | nothing | nothing | ends execution |
| jump | @tag | nothing | moves executor curser to closest tag with specified name |
| jump_if | @tag, bool | nothing | jumps to tag if 1st param is true |
| jump_if_not | @tag, bool | nothing | jumps to tag if 1st param is false |
| jump_if_equal, jeq | @tag, any, any | nothing | jumps to tag if 2th and 3th params are equal |
| jump_if_not_equal, jneq | @tag, any, any | nothing | jumps to tag if 2th and 3th params are not equal |
| new_tag | @tag | nothing | creates tag (you can call this just by writing tag name |
| add | num, num | num | adds two numbers 1 + 2 = 3 or 1.5 + 1 = 2.5 |
| add_many, add_all | num, num, num,... | num | adds many numbers 1 + 2 + 3 = 6 |
| minus | num, num | num | minus two numbers 3 - 2 = 1 |
| multiply | num, num | num | minus two numbers 3 * 2 = 6 |
| divide | num, num | num | divide two numbers 3 / 2 = 1.5 |
| modulus, mod | num, num | num | divide remaining 3 / 2 = 1 |
| power, pow | num, num | num | power 3 ** 2 = 9 |
| square_root, sqrt | num | num | square root 9 -> sqrt -> 3 |
| increase, inc | $num | nothing | adds one to variable short form of: $a,1 -> add -> $a |
| decrease, dec | $num | nothing | minus one from variable short form of: $a,1 -> minus -> $a |
| equal, eq | any, any | bool | true if 1st and 2nd are equal and false if they are not |
| not_equal, neq | any, any | bool | true if 1st and 2nd are not equal and false if they are |
| and | bool, bool | bool | and logical gate |
| or | bool, bool | bool | or logical gate |
| not | bool | bool | not logical gate |
| greater_than, gt | num, num | bool | true if 1st param is bigger than 2nd param 3,2 -> true |
| less_than, lt | num, num | bool | true if 1st param is less than 2nd param 3,2 -> false |
| concat, cat | any, any | string | convert inputs to string and concat them "al","i" -> "ali" |
| repeat | any, int | string | convert inputs to string and repeat "a",3 -> "aaa" |
| length, len | any | int | convert input to string and returns length 456 -> 3 |
| contains, has | any | bool | convert inputs to string and returns 1st contains 2nd 11,1->true |
| slice, sub_string | any, int, int | string | "hello", 1, 3 -> "el" |
| insert | array, any | nothing | insert an item to list |
| get | array, int | any | get nth item of list second param is index of item |
| pop | array | any | remove last item of list and returns it |
| last | array | any | return lsat item of list (without removing it) |
| has | array, any | bool | check if an item exist in a list |
| remove | array, any | nothing | removes a given item from list |
| remove_at | array, int | nothing | removes item at index of second param |
| index_of | array, any | int | search for an item on list and returns index |
| to_string | any | string | convert input to string 1 -> "1" |
| to_float | string | float | convert input to float "1.5" -> 1.5 ; "a"->error |
| to_int | string | int | convert input to int "1" -> 1 ; "a"->error |
| dump, dump_memory | nothing | nothing | prints all variables with values |
| type_of, type | any | str | prints type of param 1 -> int; "s" -> string |
| now_sec, now, unixtime | nothing | float | unix time standard in seconds |
| wait_mil, wait_millis | int | nothing | delay code execution for 1st milliseconds |
| wait_sec, wait_sec | int | nothing | delay code execution for 1st seconds |
| wait_min, wait_minute | int | nothing | delay code execution for 1st minutes |
| wait_hour,wait_hour | int | nothing | delay code execution for 1st hours |
| wait_hour,wait_hour | int | nothing | delay code execution for 1st hours |