diff --git a/README.md b/README.md index 04c0fe2..bc68a1f 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,241 @@ -# yascriptlang +# Yascriptlang + +[![npm version](https://badge.fury.io/js/yascriptlang.svg)](https://www.npmjs.com/package/yascriptlang) +[![Downloads](https://img.shields.io/npm/dm/yascriptlang.svg)](https://www.npmjs.com/package/yascriptlang) +[![Package Size](https://img.shields.io/bundlephobia/min/yascriptlang)](https://www.npmjs.com/package/yascriptlang) **Y**et **A**nother **Script** **Lang**uage +> Because everyone should have their own Lisp + +***Yascriptlang*** is high-level and multi-paradigm language. +It has curly-bracket syntax, strong dynamic typing, recursion, and first-class functions. + +As a multi-paradigm language, ***yascriptlang*** supports functional and imperative programming styles both. + +***Yascriptlang*** can be interpreted as well as **compiled in JavaScript**. + +## Installing + +```bash +npm install -g yascriptlang +``` + +## Documentation + +The documentation is located in the [docs](https://github.com/maxbarsukov/yascriptlang/tree/master/docs) folder. + +## Usage + +Run interpreter: +```bash +yas input.yas +``` + +Compile to **JS**: +```bash +yasc input.yas output.js +``` + +Compile to **JS** and run: +```bash +yasjs input.yas +``` + +## Building + +### Pre-reqs + +To build and run this app locally you will need a few things: + +- Install [Node.js](https://nodejs.org/en/); + +### Getting start + +- Clone the repository +```bash +git clone --depth=1 https://github.com/maxbarsukov/yascriptlang.git +``` +- Install dependencies +```bash +cd yascriptlang +yarn +``` +- Run +```bash +node bin/yas.js input.yas +# or +node bin/yasc.js input.yas output.js +# or +node bin/yasjs.js input.yas +```` + ## Examples of code +Here are some code examples. Go to there [docs](https://github.com/maxbarsukov/yascriptlang/tree/master/docs) to see more. + +Comments: ```ruby ### Comments # comment // comment /* -comment -comment +multi +line comment */ +``` + +Strings: -### Strings +```ruby println("Hello World!"); println('Hello World!'); println('Hello " World!'); println("Hello ' World!"); +``` -### Math -println(2 + 2 * 2); -println(3 ** 3); +Math: + +```ruby +println(2 + 2 * 2); # => 6 +println(3 ** 3); # => 27 +println(10 / 5); # => 2 +println(17 % 3); # => 2 +``` -### Variables +Variables: +(variables are *immutable* by default) + +```ruby def pi = 3.14; println(pi); -### Mutable Variables +def a = { + 10; + 15 # the last semicolon can be missing +}; +print(a); # prints 15 +``` + +Mutable Variables: + +```ruby def mut a = 3 a = 2; -println(a); +println(a); # => 2 +``` + +Functions: -### Functions +```ruby def fib = fn (n) -> if n < 2 then n else fib(n - 1) + fib(n - 2); println(fib(15)); -### Pipes +def print_range = fn(a, b) -> + if a <= b then { + print(a); + if a + 1 <= b { + print(", "); + print_range(a + 1, b); + } else println(""); + }; +print_range(1, 5); # => 1, 2, 3, 4, 5 + +def func = fn-> { + 10; + 20; +}; + +println(func()); # => 20. Functions returns the last var +``` + +Lambdas: + +```ruby +# fn -> {} is short for fn() -> {} + +(fn->{ +println(3 ** 3); +})(); +``` + +Pipes: + +```ruby def k = 200; k |> println; # prints 200 -### Benchmarks +2 |> fn(x) -> (x * x) |> println; # prints 4 +``` + +Benchmarks: + +```ruby time(fn-> { println(fib(15)); }); +``` -### Lambdas -# fn -> {} is short for fn() -> {} -(fn->{ - println(3 ** 3); -})(); +Let: -### Let +```ruby def a = 1; let (mut a = 10) -> { println(a); # => 10 }; println(a); # => 1 -### if / else -edf f = fn-> { true; }; -def a = if f() then "OK" else "FAIL"; -### true / false -if true then print("OK"); +print(let loop(n = 10) -> + if n > 0 then n + loop(n - 1) + else 0); +# => 55 + +let (x = 2, y = x + 1, z = x + y) -> + println(x + y + z); # => 10 + + +let (x = 10) -> { + let (x = x * 2, y = x * x) -> { + println(x); # 20 + println(y); # 400 + }; + println(x); # 10 +}; + +``` + +if / else: + +```ruby +def f = fn-> { true; }; +def a = if f() then "OK" else "FAIL"; # OK +if 1 == 1 && 2 < 5 then print("OK"); # OK +``` + +true / false : + +```ruby +if true then print("OK"); # OK +if !false then print("OK"); # OK if false then print("Won't be printed"); +``` + +Lists: -### Lists +```ruby def list = cons(1, cons(2, cons(3, cons(4, cons(5, NIL))))); print(car(list)); # 1 print(car(cdr(list))); # 2 print(car(cdr(cdr(list)))); # 3 print(car(cdr(cdr(cdr(list))))); # 4 print(car(cdr(cdr(cdr(cdr(list)))))); # 5 +``` + +Yield: -### Yield +```ruby foo = with-yield(fn(yield) -> { yield(1); yield(2); @@ -87,16 +247,21 @@ println(foo()); # 1 println(foo()); # 2 println(foo()); # 3 println(foo()); # DONE +``` + +Some stdlib methods: -### Some stdlib methods -## foreach +```ruby +# foreach foreach(x, println); # prints from 1 to 5 by println -## range +# range foreach(range(1, 8), fn(x) -> println(x * x)); +# or +foreach(range(1, 8), fn(x) -> (x * x) |> println); # prints 1, 4, 9, 16, ... 49, 64 -## throw / catch +# throw / catch exit = false; x = 0; callcc( fn(k) -> exit = k ); @@ -108,3 +273,7 @@ exit(); println("After catch"); throw("foo", "FOO"); ``` + +## License + +The package is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..abd7b83 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,201 @@ +## Examples of code + +Comments: +```ruby +### Comments +# comment +// comment +/* +multi +line +comment +*/ +``` + +Strings: + +```ruby +println("Hello World!"); +println('Hello World!'); +println('Hello " World!'); +println("Hello ' World!"); +``` + +Math: + +```ruby +println(2 + 2 * 2); # => 6 +println(3 ** 3); # => 27 +println(10 / 5); # => 2 +println(17 % 3); # => 2 +``` + +Variables: +(variables are *immutable* by default) + +```ruby +def pi = 3.14; +println(pi); + +def a = { + 10; + 15 # the last semicolon can be missing +}; +print(a); # prints 15 +``` + +Mutable Variables: + +```ruby +def mut a = 3 +a = 2; +println(a); # => 2 +``` + +Functions: + +```ruby +def fib = fn (n) -> if n < 2 then n else fib(n - 1) + fib(n - 2); +println(fib(15)); + +def print_range = fn(a, b) -> + if a <= b then { + print(a); + if a + 1 <= b { + print(", "); + print_range(a + 1, b); + } else println(""); + }; +print_range(1, 5); # => 1, 2, 3, 4, 5 + +def func = fn-> { + 10; + 20; +}; + +println(func()); # => 20. Functions returns the last var +``` + +Lambdas: + +```ruby +# fn -> {} is short for fn() -> {} + +(fn->{ +println(3 ** 3); +})(); +``` + +Pipes: + +```ruby +def k = 200; +k |> println; # prints 200 + +2 |> fn(x) -> (x * x) |> println; # prints 4 +``` + +Benchmarks: + +```ruby +time(fn-> { + println(fib(15)); +}); +``` + +Let: + +```ruby +def a = 1; +let (mut a = 10) -> { + println(a); # => 10 + }; +println(a); # => 1 + + +print(let loop(n = 10) -> + if n > 0 then n + loop(n - 1) + else 0); +# => 55 + +let (x = 2, y = x + 1, z = x + y) -> + println(x + y + z); # => 10 + + +let (x = 10) -> { + let (x = x * 2, y = x * x) -> { + println(x); # 20 + println(y); # 400 + }; + println(x); # 10 +}; + +``` + +if / else: + +```ruby +def f = fn-> { true; }; +def a = if f() then "OK" else "FAIL"; # OK +if 1 == 1 && 2 < 5 then print("OK"); # OK +``` + +true / false : + +```ruby +if true then print("OK"); # OK +if !false then print("OK"); # OK +if false then print("Won't be printed"); +``` + +Lists: + +```ruby +def list = cons(1, cons(2, cons(3, cons(4, cons(5, NIL))))); +print(car(list)); # 1 +print(car(cdr(list))); # 2 +print(car(cdr(cdr(list)))); # 3 +print(car(cdr(cdr(cdr(list))))); # 4 +print(car(cdr(cdr(cdr(cdr(list)))))); # 5 +``` + +Yield: + +```ruby +foo = with-yield(fn(yield) -> { + yield(1); + yield(2); + yield(3); + "DONE"; +}); + +println(foo()); # 1 +println(foo()); # 2 +println(foo()); # 3 +println(foo()); # DONE +``` + +Some stdlib methods: + +```ruby +# foreach +foreach(x, println); # prints from 1 to 5 by println + +# range +foreach(range(1, 8), fn(x) -> println(x * x)); +# or +foreach(range(1, 8), fn(x) -> (x * x) |> println); +# prints 1, 4, 9, 16, ... 49, 64 + +# throw / catch +exit = false; +x = 0; +callcc( fn(k) -> exit = k ); +if x == 0 then catch("foo", fn-> { +println("in catch"); +x = 1; +exit(); +}); +println("After catch"); +throw("foo", "FOO"); +``` diff --git a/docs/examples/hello_world.yas b/docs/examples/hello_world.yas new file mode 100644 index 0000000..eaf6c48 --- /dev/null +++ b/docs/examples/hello_world.yas @@ -0,0 +1 @@ +println('Hello World!'); diff --git a/package.json b/package.json index 099f782..44c3798 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yascriptlang", - "version": "1.0.0", + "version": "1.0.1", "description": "A simple scripting language inspired by Lisp", "main": "./bin/yasjs.js", "homepage": "https://github.com/maxbarsukov/yascriptlang.git", @@ -19,7 +19,10 @@ "language", "programming language", "lisp", - "interpreter" + "interpreter", + "compiler", + "programming", + "javascript" ], "type": "module", "devDependencies": {