### 5 releases

0.1.4 | Dec 18, 2023 |
---|---|

0.1.3 | Dec 18, 2023 |

0.1.2 | Dec 18, 2023 |

0.1.1 | Dec 17, 2023 |

0.1.0 | Dec 17, 2023 |

#**106** in Programming languages

**MIT/Apache**

290KB

7K
SLoC

# The Nope Script

Nope is a scripting programming language, optimised for small and fun programs

### Nope is

- Fun
- Expression based
- Garbage collected
- Imperative with a sprinkle of functional
- Focused on solving practical problems
- Separates data from logic
- Can represent JSON and XML natively
- A single binary
- Built with Rust
- Will include a fully featured stdlib
- Will have an eventloop concurrency model

## Run and Install

Install rust / cargo then

cargo install nope-lang

You can then launch the interactive repl with

nope

Or run a script with

nope myscript.nope

If you use vim you can install syntax support with

nope --install-vim-plugin

## Roadmap

This is project is currently at a very very early stage

- evaluate expressions
- global, local variables and scopes
- constant & operators
- math stdlib
- loops
- functions
- dictionaries and arrays
- garbage collector
- errors, try catch
- string stdlib
- parsing & serialization
- utils stdlib
- resource type
- os stdlib
- unit tests
- v1.0
- async
- async stdlib
- v2.0
- web server
- v3.0
- modules & packages
- v4.0
- perf

## Types

The following table should give you an idea of the basic types and allowed data models. Keep in mind arrays and objects are not implemented at the moment

`[`
null`:` null`,`
void`:` `[`void `_` `(``)``]`
`bool``:` `[``true` `false``]`
num`:` `[``0` `1` `99` `3.``14` `-``1_000_000` `0xdead` `0b10101` NaN Inf `PI``]`
string`:` `[``'`foo`'` `"`bar`"` `~`hello`]`
arrays`:` `[``1` `2` `true` null `[``]``]`
dicts`:` `{`key`:``32` val`:``99``}`
mixed`:` `[``'`foo`'` key`:``'`value`'``]`
`]`

All data in nope is a combination of the above types and structures.

Note that numbers are 64bit floats, and the strings are unicode.

## Code structure

Let's look at basic nope program.

`let` x `=` `d6``(``)` `+` `d6``(``)`
var winning `=` `false`
`if` x `>=` `10` `(`
set winning `=` `true`
print `'haha``,` yes`!` `:``)``'`
) `else` `(`
print `'oh` no `:``(``'`
`)`

In the first line, we define a variable called

, with an initial value defined
by an expression which calls two functions 'd6' and adds the results. The variable
'x' is available in all subsequent expressions in the current scope. Since it
is defined with `x`

, it cannot later be changed with `let`

.`set`

In the second line we declare another variable, but this time it can be modified.

We then evaluate a classic if-else conditional. Note that unlike other languages,
the code blocks are not defined by curly braces

/`{`

but by parenthesis `}`

/`(`

.
The reason is that nope is an expression based language, so every nope construct is
an expression that produces a value.`)`

The following example puts those principles in action

`let` res `=` `if` `flip_coin``(``)``,` `"`heads`"` `else` `"`tails`"`

The

returns a value, which depending on the result of `if`

will be
either the string "heads" or "tails".`flip_coin``(``)`

You can surround expressions with parenthesis, and you can also surround multiple expressions with parenthesis. In the later case, all expressions are evaluated in order, but only the last expression produces a value.

This is what we've used to both change the variable

with the `winning`

expression, but also to print a message.`set winning = true`

Note as well that the print expression

ommits parenthesis around its argument
This is not a special case of the print function. In nope, all parenthesis and commas for
functions arguments are optional.`print "hey"`

`let` clamped_0_100 `=` max `0` min value `100`

This is also applies to functions without parameters

`let` score `=` d6 `+` d6 `+` d6

Note that function application has the highest precedence so

prints `print 1 + 1`

`1`

since the addition is performed afterwards. This is not always what you want. One way
is to use parenthesis `print``(``1` `+` `1``)`

, `print ``(``1` `+` `1``)`

. Note
that the space between the function name and the first parenthesis is meaningful. Without
space, the full list of arguments is expected, while with the space, it's just parenthesis
around a single argument; `max``(``1``,``2``)`

/ `max ``(``1``)` `(``2``)`

Another way is to use the left arrow

operator. This operator simply evaluates the complete expression
on the right. So you can do your print like this `<``-`

.`print <- 1 + 1`

By convention, all functions in nope take the data they operate on as the last argument.

`let` txt `=` read_text `'file``.`txt`'`
`let` txt2 `=` upper txt
write_txt `'file2``.`txt`'` txt2

With the help of the left arrow

operator you could have instead written the following,`<``-`

`write_txt ``'file2``.`txt`'` `<``-` upper `<``-` read_text `'file``.`txt`'`

The right arrow

operator (not yet implemented) does the same but the other way around.`->`

`read_text ``'file``.`txt`'` `->` upper `->` write_txt `'file2``.`txt`'`

## Operators

#### Equality `==`

, `!=`

`==`

`!=`Check that the operands are of the same type, and if that's the case compare their values or references

#### Comparison `<`

, `>`

, `<=`

, `>=`

`<`

`>`

`<=`

`>=`First converts the number to their number equivalent (NaN for strings and arrays) then compares

The

and `+``-=`

compare numbers for equality up to `!``+``-=`

precision`EPSILON`

#### Arithmetic `+`

, `-`

, `*`

, `/`

, `%`

, `*``*`

,

`+`

`-`

`*`

`/`

`%`

`*``*`The usual math operations. Operands are converted to their number equivalent (NaN for string)

Addition

of a string will perform string concatenation, and convert the other operand to string`+`

#### Integer & Bitwise Arithmetic

All the arithmetic operators prefixed with

will first convert operands to int32 then perform the integer arithmetic operation.`~`

For example

is `10` `~``/` `4``2`

The bitwise operators

, `~``!`

, `~``|`

, `~``&`

, `~``^`

, `~``<``<`

, `~``>``>`

convert the operands to int32 then perform the bitwise operations`~``>``>``>`

#### Boolean `!`

, `||`

, `&&`

`!`

`||`

`&&`The boolean equivalent of an operand is

if`false`

,`null`

or`void``0`

otherwise`true`

The operators

negates the boolean equivalent`!`

returns the first operand if falsy, otherwise the second`&&`

returns the first operand if truthy, otherwise the second`||`

#### Default `?``?`

`?``?`Will return the second operand if the first is

or `null`

otherwise the first`void`

#### Repeat `*``:`

`*``:`The repeat operator will evaluate and sum the second operand N times, where N is the first operand.

For example, this will throw the dice 3 times

`print``(``3` `*``:` d6`)`

Note that the first operand is first converted to a number. If the number is zero or negative, we return

.`void`

## Loops

Nope supports two looping mechanism,

which endlessly repeats the expression that follows and `loop`

,
which evaluates a condition and repeats the next expression as long as the condition stays truthy.`while`

`var i ``=` `0``,` `while` i `<` `10` `(`
set i `=` print i `+` `1`
`)`

will jump directly to the next iteration, and `continue`

will stop the iteration`break`

`var i ``=` `0``,` `loop` `(`
`if` i `<` `10` `(`
set i `=` i `+` `1`
`continue`
`)`
`break`
`)`

loops are expressions too and return the last value of their expression.

returns void, `break`

will break
and return the next expression`break_as`

`var i ``=` `0``,` `let` res `=` `loop` `(`
`if` i `<` `10` `(`
set i `=` i `+` `1`
`)` `else` `(`
break_as `'done``!``'`
`)`
`)`

## Printing to the terminal

and `print`

are similar functions, they take one argument, print the value to the terminal, and returns it. The difference is that `echo`

prints the raw string converted value, while `print`

prints a colored internal representation of the value.`echo`

In the repl, each submission is echoed after execution.

Note that since both

and `print`

return their argument, you can use them inside expressions to display temporary values.`echo`

`var i ``=` `0``,` `while` i `<` `10` `(`
set x `=` print x `+` `1`
`)`

## Types check & conversions

The following functions convert to their type,

, `to_num`

, `to_bool``to_str`

The following function test the types:

, `is_void`

, `is_null`

, `is_bool`

, `is_num`

, `is_int`

, `is_nan`

, `is_odd`

, `is_even``is_str`

## Arithmetic Functions and constants

Nope supports the following arithmetic functions

,`floor`

,`ceil`

,`abs`

,`acos`

,`acosh`

,`sin`

,`sinh`

,`asin`

,`asinh`

,`cos`

,`cosh`

,`tan`

,`tanh`

,`atan`

,`atanh``inv`

,`log2`

,`log10`

,`ln`

,`ln1p`

,`exp`

,`expm1`

,`sqrt`

,`cbrt`

,`round`

,`fround`

,`trunc`

,`sign`

,`max`

,`min`

,`pow``atan2`

And the following arithemtic constants

,`NaN`

,`Inf`

,`PI`

,`E`

,`SQRT_2`

,`SQRT_2PI`

,`LN_2`

,`LN_10`

,`LOG2_10`

,`LOG2_E`

,`LOG10_2`

,`LOG10_E`

,`PHI`

,`TAU`

,`EPISLON``MAX``|``MIN_INT`

,`MAX``|``MIN_F64`

,`MAX``|``MIN_I32``|``16``|``8``MAX_U32``|``16``|``8`

## Strings

returns the length of the string (scans the whole string)`len`

,`upper`

transform the case of the string`lower`

removes the whitespace at the beginning and end of the string`trim`

gets the character at string index`char_at``(`idx`,`text`)`

, returns the substring based on character indexes.`substr``(`from_idx`,`to_idx`,`text`)`

is not inclusive. Negative indexes start at the end.`to_idx`

replaces the instances of`replace``(`from`,`to`,`text`)`

in`from`

to`text``to`

, returns the position of`find``(`substr`,``str``)`

in`substr`

or`str``-``1`

returns`contains``(`substr`,``str``)`

if`true`

is a substring of`substr``str`

transforms a number to its bitwise representation as a string`bitstr`

## Randomness

Nope supports the following rng functions

,`random`

,`flip_coin`

,`rand100`

,`d4`

,`d6`

,`d8`

,`d10`

,`d12`

,`d20``d100`

If you want to return the sum of 3 dice throws it is better to use the repeat operator `3``*``:`d6

## Units

Nope allows you to annotate number literal with a unit suffix.

`let` distance `=` cos 45deg `*` `(`10Km `+` 3miles `+` 5yd `+` 3in `+` 5cm`)`

The units convert the number to their SI units equivalent. For example all distances are converted to meters.

The information about the unit of a number is not kept at runtime. Units are nothing more than a convenient syntax trick.

The following units are supported:

, `pi`

, `tau`

, `phi`

, `GT`

, `MT`

, `kT`

, `T`

, `kg`

, `g`

, `mg`

, `ug`

, `ng`

, `Ti`

, `Gi`

, `Mi`

, `ki`

,
`d`

, `h`

, `min`

, `s`

, `ms`

, `us`

, `ns`

, `moon`

, `deg`

, `rad`

, `in`

, `km`

, `m`

, `dm`

, `cm`

, `mm`

, `um`

,
`nm`

, `lb`

, `oz`

, `mile`

, `miles`

, `ft`

, `yd`

, `F`

, `C`

, `K`

, `m3`

, `l`

, `dm3`

, `dl`

, `cl`

, `ml`

,
`cm3`

, `barrel`

, `cuft`

, `ft3`

, `gal`

, `pint`

, `cuin`

, `in3`

, `cuyd`

, `yd3`

, `m2`

, `dm2`

, `cm2`

, `mm2`

,
`a`

, `ha`

, `km2`

, `mile2`

, `yd2`

, `sqyd`

, `ft2`

, `sqft`

, `in2`

, `sqin`

, `belgium`

, `footballfield`

,
`TiB`

, `TB`

, `GiB`

, `GB`

, `MiB`

, `MB`

, `KiB`

, `KB`

, `million`

, `billion`

, `trillion`

, `quadrillon`

,
`milli`

, `thousandth`

, `micro`

, `nano`

,`pico`

It is also possible to convert from one unit to another at runtime with the

and `from_unit`

functions.`to_unit`

`let` area_sqin `=` to_unit `'`sqin`'` `<``-` from_unit `'`ha`'` `<``-` `50`

#### Dependencies

~6–16MB

~180K SLoC