all repos — mn @ af5c39e04bdc44b38227aab6d8b60d6af16d69c6

A truly minimal concatenative programming language.

Added selected docs from min and guide task.
h3rald h3rald@h3rald.com
Sat, 27 Mar 2021 17:49:54 +0000
commit

af5c39e04bdc44b38227aab6d8b60d6af16d69c6

parent

fade7297a45e8660f982651553f85f983bca0eba

M .gitignore.gitignore

@@ -2,4 +2,6 @@ nimcache/

nimblecache/ htmldocs/ mn.exe -mn_v*+mn_v* +*.htm +mn
A Mn_DeveloperGuide.md

@@ -0,0 +1,168 @@

+% mn Language Developer Guide +% Fabio Cevasco +% - + +<style> +.reference-title { + font-size: 120%; + font-weight: 600; +} +.min-terminal { + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + margin: 10px auto; + padding: 2px 4px 0 4px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); + color: #eee; + background-color: #222; + border: 1px solid #ccc; + white-space: pre; + padding: 0 3px; + border: 2px solid #999; + border-top: 10px solid #999; +} +.min-terminal p { + margin: 0 auto; +} +.min-terminal p, .min-terminal p:first-child { + margin-top: 0; + margin-bottom: 0; + text-shadow: none; + font-weight: normal; + font-family: "Source Code Pro", "Monaco", "DejaVu Sans Mono", "Courier New", monospace; + font-size: 85%; + color: #eee; +} +</style> + +## About min + +{@ docs/about.md || 1 @} + +## Get Started + +{@ docs/get-started.md || 1 @} + +## Learning the min Language + +{@ docs/learn.md || 1 @} + +### Data Types + +{@ docs/learn-data-types.md || 2 @} + +### Quotations + +{@ docs/learn-quotations.md || 2 @} + +### Operators + +{@ docs/learn-operators.md || 2 @} + +### Definitions + +{@ docs/learn-definitions.md || 2 @} + +### Scopes + +{@ docs/learn-scopes.md || 2 @} + +### Control Flow + +{@ docs/learn-control-flow.md || 2 @} + +## Extending mn + +{@ docs/learn-extending.md || 1 @} + +## Reference + +{@ docs/reference.md || 1 @} + + +### `lang` Module + +{@ docs/reference-lang.md || 1 @} + +### `stack` Module + +{@ docs/reference-stack.md || 1 @} + +### `seq` Module + +{@ docs/reference-seq.md || 1 @} + +### `io` Module + +{@ docs/reference-io.md || 1 @} + +### `logic` Module + +{@ docs/reference-logic.md || 1 @} + +### `str` Module + +{@ docs/reference-str.md || 1 @} + +### `sys` Module + +{@ docs/reference-sys.md || 1 @} + +### `num` Module + +{@ docs/reference-num.md || 1 @} + +### `time` Module + +{@ docs/reference-time.md || 1 @} + +### `math` Module + +{@ docs/reference-math.md || 1 @} + + +{#op => +<a id="min-operator-id-$1"></a> +[$1](class:reference-title) + +> %operator% +> [ $2 **&rArr;** $3](class:kwd) +> +> $4 + #} + + +{#alias => +[$1](class:reference-title) + +> %operator% +> [ $1 **&rArr;** $2](class:kwd) +> +> See [$2](#min-operator-id-$2). + #} + +{#sig => +[$1](class:reference-title) [](class:sigil) + +> %operator% +> [ $1{{s}} **&rArr;** {{s}} $2](class:kwd) +> +> See [$2](#min-operator-id-$2). + #} + +{# link-page => $2 #} + +{# link-module => [$1 Module](#<code>$1</code>-Module) #} + +{# link-operator => [$2](#min-operator-id-$2) #} + +{# link-learn => #} + +{{learn-links => }} + +{{guide-download => }}
A docs/_defs_.md

@@ -0,0 +1,118 @@

+{{q => [quot](class:kwd)}} +{{q1 => [quot<sub>1</sub>](class:kwd)}} +{{q2 => [quot<sub>2</sub>](class:kwd)}} +{{q3 => [quot<sub>3</sub>](class:kwd)}} +{{q4 => [quot<sub>4</sub>](class:kwd)}} +{{1 => [<sub>1</sub>](class:kwd)}} +{{2 => [<sub>2</sub>](class:kwd)}} +{{3 => [<sub>3</sub>](class:kwd)}} +{{4 => [<sub>4</sub>](class:kwd)}} +{{e => [dict:error](class:kwd)}} +{{tinfo => [dict:timeinfo](class:kwd)}} +{{dstore => [dict:datastore](class:kwd)}} +{{d => [dict](class:kwd)}} +{{d1 => [dict<sub>1</sub>](class:kwd)}} +{{d2 => [dict<sub>2</sub>](class:kwd)}} +{{d0p => [dict<sub>\*</sub>](class:kwd)}} +{{flt => [flt](class:kwd)}} +{{i => [int](class:kwd)}} +{{i1 => [int<sub>1</sub>](class:kwd)}} +{{i2 => [int<sub>2</sub>](class:kwd)}} +{{i3 => [int<sub>3</sub>](class:kwd)}} +{{n => [num](class:kwd)}} +{{n1 => [num<sub>1</sub>](class:kwd)}} +{{n2 => [num<sub>2</sub>](class:kwd)}} +{{n3 => [num<sub>3</sub>](class:kwd)}} +{{any => [a](class:kwd)}} +{{a1 => [a<sub>1</sub>](class:kwd)}} +{{a2 => [a<sub>2</sub>](class:kwd)}} +{{a3 => [a<sub>3</sub>](class:kwd)}} +{{a0p => [a<sub>\*</sub>](class:kwd)}} +{{s0p => [str<sub>\*</sub>](class:kwd)}} +{{s => [str](class:kwd)}} +{{s1 => [str<sub>1</sub>](class:kwd)}} +{{s2 => [str<sub>2</sub>](class:kwd)}} +{{s3 => [str<sub>3</sub>](class:kwd)}} +{{s4 => [str<sub>4</sub>](class:kwd)}} +{{b => [bool](class:kwd)}} +{{b1 => [bool<sub>1</sub>](class:kwd)}} +{{b2 => [bool<sub>2</sub>](class:kwd)}} +{{b3 => [bool<sub>3</sub>](class:kwd)}} +{{01 => [<sub>?</sub>](class:kwd)}} +{{0p => [<sub>\*</sub>](class:kwd)}} +{{1p => [<sub>\+</sub>](class:kwd)}} +{{sl => [&apos;sym](class:kwd)}} +{{sl1 => [&apos;sym<sub>1</sub>](class:kwd)}} +{{sl2 => [&apos;sym<sub>2</sub>](class:kwd)}} +{{sym => [sym](class:kwd)}} +{{f => [false](class:kwd)}} +{{t => [true](class:kwd)}} +{{null => [null](class:kwd)}} +{{none => &#x2205;}} +{{no-win => (not supported on Windows systems)}} +{{help => [dict:help](class:kwd)}} +{{sock => [dict:socket](class:kwd)}} +{{url => [dict:url](class:kwd)}} +{{req => [dict:http-request](class:kwd)}} +{{res => [dict:http-response](class:kwd)}} +{{sock1 => [dict:socket<sub>1</sub>](class:kwd)}} +{{sock2 => [dict:socket<sub>2</sub>](class:kwd)}} +{{m => _min_}} + +{{pcre => [Perl Compatible Regular Expression](https://www.pcre.org/)}} + +{#op => +<a id="op-$1"></a> +## $1 + +> %operator% +> [ $2 **&rArr;** $3](class:kwd) +> +> $4 + #} + +{#alias => +## $1 + +> %operator% +> [ $1 **&rArr;** $2](class:kwd) +> +> See [$2](#op-$2). + #} + +{#sig => +## $1 [](class:sigil) + +> %operator% +> [ $1{{s}} **&rArr;** {{s}} $2](class:kwd) +> +> See [$2](#op-$2). + #} + +{# link-page => [$2](/$1/) #} + +{# link-module => [`$1` Module](/reference-$1/) #} + +{# link-operator => [`$2`](/reference-$1#op-$2) #} + +{# link-learn => &rarr; Continue to [*$2*](/learn-$1) #} + +{{ learn-links => +> %tip% +> Quick Links +> +> * [Data Types](/learn-data-types) +> * [Operators](/learn-operators) +> * [Quotations](/learn-quotations) +> * [Definitions](/learn-definitions) +> * [Scopes](/learn-scopes) +> * [Control Flow](/learn-control-flow) +> * [Shell](/learn-shell) +> * [Extending min](/learn-extending) +}} + +{{guide-download => +> %tip% +> Tip +> +> A printable, self-contained guide containing more or less the same content of this web site can be downloaded from [here](https://h3rald.com/min/Min_DeveloperGuide.htm). }}
A docs/about.md

@@ -0,0 +1,42 @@

+----- +content-type: "page" +title: "About" +----- +{@ _defs_.md || 0 @} + +**min** is a concatenative, fully-homoiconic, functional, interpreted programming language. + +This basically means that: + +* It is based on a somewhat obscure and slightly unintuitive programming paradigm, think of [Forth](http://www.forth.org/), [Factor](http://factorcode.org/) and [Joy](http://www.kevinalbrecht.com/code/joy-mirror/) but with parentheses for an extra [Lisp](https://common-lisp.net/)y flavor. +* Programs written in min are actually written using *quotations*, i.e. lists. +* It comes with map, filter, find, map-reduce, and loads of other functional goodies. See the {#link-module||seq#} for more. +* It is probably slower than the average production-ready programming language. + +## Why? + +Because creating a programming language is something that every programmer needs to do, at some point in life. And also because there are way too few [concatenative](http://concatenative.org/wiki/view/Front%20Page) programming language out there -- so people are likely to be _less_ pissed off than if I made a yet another Lisp instead. + +I always wanted to build a minimalist language, but that could also be used for real work and provided a standard library for common tasks and functionalities like regular expression support, cryptography, execution of external programs, shell-like operators, and keywords to work with files, and more. + +Additionally, I wanted it to be fully self-contained, cross-platform, and small. Not stupidly small, but I feel it's a good compromise compared to the alternatives out there, considering that you only need _one file_ to run any min program. + + I also created a static site generator called [HastySite](https://github.com/h3rald/hastysite), which also powers <https://min-lang.org>. HastySite internally uses min as the language to write the [rules](https://github.com/h3rald/min/blob/master/site/rules.min) to process the source files of the site, and also all its [scripts](https://github.com/h3rald/min/tree/master/site/scripts). + +Finally, I think more and more people should get to know concatenative programming languages, because [concatenative programming matters](http://evincarofautumn.blogspot.it/2012/02/why-concatenative-programming-matters.html). + +## How? + +min is developed entirely in [Nim](https://nim-lang.org) -- the name is (almost) entirely a coincidence. I wanted to call it _minim_ but then shortened it for more... minimalism. + +min's parser started off as a fork of Nim's JSON parser -- adapted to process a concatenative programming language with less primitive types than JSON. It is interpreted in the traditional sense: no bytecode, no JIT, just plain read, parse, and run. + +## Who? + +min was created and implemented by [Fabio Cevasco](https://h3rald.com), with contributions by [Peter Munch-Ellingsen](https://peterme.net), [Yanis Zafirópulos](https://github.com/drkameleon), and [baykus871](https://github.com/baykus871). + +Special thanks to [mwgkgk](https://github.com/mwgkgk) for contributing to the design of native dictionaries. + +## When? + +min source code [repository](https://github.com/h3rald/min) was created on November 8^th 2014. This only means that I've been very slowly developing something that was actually made public at the end of July 2017.
A docs/get-started.md

@@ -0,0 +1,149 @@

+----- +content-type: "page" +title: "Get Started" +----- +{@ _defs_.md || 0 @} + + +You can download one of the following pre-built min binaries: + +* {#release||{{$version}}||macosx||macOS||x64#} +* {#release||{{$version}}||windows||Windows||x64#} +* {#release||{{$version}}||linux||Linux||x64#} + +{#release -> [min v$1 for $3 ($4)](https://github.com/h3rald/min/releases/download/v$1/min\_v$1\_$2\_$4.zip) #} + +{{guide-download}} + +## Building from source + +Alternatively, you can build min from source in one of the following ways: + +### Using nimble + +If you already installed [nim](https://nim-lang.org), you probably already have the [nimble](https://github.com/nim-lang/nimble) package manager installed. + +If that's the case, simply run **nimble install min**. This will actually install and run [nifty](https://github.com/h3rald/nifty) which will download min dependencies for you before compiling. + +### Without using nimble + +1. Download and install [nim](https://nim-lang.org). +2. Download and build [nifty](https://github.com/h3rald/nifty), and put the nifty executable somewhere in your [$PATH](class:kwd). +3. Clone the min [repository](https://github.com/h3rald/min). +4. Navigate to the min repository local folder. +5. Run **nifty install** to download min’s dependencies. +7. Run **nim c -d:release min.nim**. + +### Additional build options + +#### -d:ssl + +If the **-d:ssl** flag is specified when compiling, min will be built with SSL support, so it will be possible to: +* perform HTTPS requests with the {#link-module||http#}. +* use all the cryptographic symbols defined in the {#link-module||crypto#}. + +If this flag is not specified: +* It will not be possible to perform HTTPS requests +* Only the following symbols will be exposed by the {#link-module||crypto#}: + * {#link-operator||crypto||md5#} + * {#link-operator||crypto||sha1#} + * {#link-operator||crypto||encode#} + * {#link-operator||crypto||decode#} + * {#link-operator||crypto||aes#} + +## Building a Docker image + +[Yanis Zafirópulos](https://github.com/drkameleon) contributed a Dockerfile that you can use to create your own Docker image for min based on Alpine Linux. + +To build the image locally, execute the following command from the repository root directory: + +> %terminal% +> docker build \-t mindocker . + +To run it, execute: + +> %terminal% +> docker run \-it mindocker + +## Running the min Shell + +To start the min shell, run [min](class:cmd) with no arguments. You will be presented with a prompt displaying the path to the current directory: + +> %min-terminal% +> min shell v$versio +> [[/Users/h3rald/test]$](class:prompt) + +You can type min code and press [ENTER](class:kbd) to evaluate it immediately: + +> %min-terminal% +> [[/Users/h3rald/test]$](class:prompt) 2 2 + +> 4 +> [[/Users/h3rald/test]$](class:prompt) + +The result of each operation will be placed on top of the stack, and it will be available to subsequent operation + +> %min-terminal% +> [[/Users/h3rald/test]$](class:prompt) dup * +> 16 +> [[/Users/h3rald/test]$](class:prompt) + +To exit min shell, press [CTRL+C](class:kbd) or type [0 exit](class:cmd) and press [ENTER](class:kbd). + +> %tip% +> Tip +> +> By default, the min shell provides advanced features like tab-completion, history, etc. If however, you run into problems, you can disable these features by running [min -j](class:cmd) instead, and run min shell with a bare-bones REPL. + +## Executing a min Program + +To execute a min script, you can: + +* Run `min -e:"... program ..."` to execute a program inline. +* Run `min myfile.min` to execute a program contained in a file. + +min also supports running programs from standard input, so the following command can also be used (on Unix-like system) to run a program saved in [myfile.min](class:file): + +> %min-terminal% +> +> [$](class:prompt) cat myfile.min | min + +## Compiling a min Program + +min programs can be compiled to a single executable simply by specifying the `-c` (or `--compile`) flag when executing a min file: + +> %min-terminal% +> +> [$](class:prompt) min -c myfile.min + +Essentially, this will: + +1. Generate a [myfile.nim](class:file) containing the equivalent Nim code of your min program. +2. Call the Nim compiler to do the rest ;) + +If you want to pass any options to the Nim compiler (like `-d:release` for example) you can do so by using the `-n` (or `--passN`) option: + +> %min-terminal% +> +> [$](class:prompt) min -c myfile.min -n:-d:release + +Additionally, you can also use `-m:<path>` (or `--module-path`) to specify one path containing [.min](class:ext) files which will be compiled as well (but not executed) along with the specified file. Whenever a {#link-operator||lang||load#} or a {#link-operator||lang||require#} symbol is used to load/require an external [.min](class:ext) file, it will attempt to retrieve its contents from the pre-loaded files first before searching the filesystem. + +For example, the following command executed in the root folder of the min project will compile [run.min](class:file) along with all [.min](class:ext) files included in the [tasks](class:dir) folder and its subfolders: + +> %min-terminal% +> +> [$](class:prompt) min -c run.min -m:tasks + +Similarly, you can also bundle additional files in the executable by specifying the `-a:<path>` (or `--asset-path`) option. At runtime, the compiled min program will attempt to lookup bundled asset files before checking the filesystem. + +> %note% +> Note +> +> In order to successfully compile [.min](class.ext) files, Nim must be installed on your system and min must be installed via nimble. + +## Syntax Highlighting + +* If you are using [Visual Studio Code](https://code.visualstudio.com/), you can install the official [min extension](https://marketplace.visualstudio.com/items?itemName=h3rald.vscode-min-lang) which provides syntax highlighting support, code folding, and auto-indentation. +* If you are using [Vim](https://www.vim.org), a [min.vim](https://github.com/h3rald/min/blob/master/min.vim) syntax definition file is available in the min repo. +* If you are using [Sublime Text 3](https://www.sublimetext.com/3), Rafael Carrasco created a min syntax definition file that is available [here](https://github.com/rscarrasco/min-sublime-syntax). +* If you are hsing [Notepad++](https://notepad-plus-plus.org), a [Notepad++ language file](https://github.com/h3rald/min/blob/master/minNotepad++.xml) contributed by baykus871 is available in tbe repo.
A docs/learn-control-flow.md

@@ -0,0 +1,83 @@

+----- +content-type: "page" +title: "Learn: Control Flow" +----- +{@ _defs_.md || 0 @} + + +The {#link-module||lang#} provide some symbols that can be used for the most common control flow statements. Unlike most programming languages, min does not differentiate between functions and statements -- control flow statements are just ordinary symbols that manipulate the main stack. + + +## Conditionals + +The following symbols provide ways to implement common conditional statements: + +* {#link-operator||lang||case#} +* {#link-operator||lang||if#} +* {#link-operator||lang||unless#} +* {#link-operator||lang||when#} + +For example, consider the following program: + + ( + ( + "" :type + (("\.(md|markdown)$") ("markdown" @type)) + (("\.txt$") ("text" @type)) + (("\.min$") ("min" @type)) + (("\.html?$") ("HTML" @type)) + ((true) ("unknown" @type)) + ) case + "This is a $1 file." (type) % echo + ) ^display-file-info + +This program defines a symbol `display-file-info` that takes a file name and outputs a message displaying its type if known. + + +## Loops + +The following symbols provide ways to implement common loops: + +* {#link-operator||lang||foreach#} +* {#link-operator||lang||times#} +* {#link-operator||lang||while#} + + +For example, consider the following program: + + ( + :n + 1 :i + 1 :f + (i n <=) + ( + f i * @f + i succ @i + ) while + f + ) ^factorial + +This program defines a symbol `factorial` that calculates the factorial of an integer iteratively using the symbol {#link-operator||lang||while#}. + +## Error handling + +The following symbols provide ways to manage errors in min: + +* {#link-operator||lang||format-error#} +* {#link-operator||lang||raise#} +* {#link-operator||lang||try#} + +For example, consider the following program: + + . ls + ( + ( + (fsize) + (pop 0) + ) try + ) map + 1 (+) reduce + +This program calculates the size in bytes of all files included in the current directory. Because the {#link-operator||fs||fsize#} symbol throws an error if the argument provided is not a file (for example, if it is a directory), the `try` symbol is used to remove the error from the stack and push `0` on the stack instead. + +{#link-learn||shell||Shell#}
A docs/learn-data-types.md

@@ -0,0 +1,62 @@

+----- +content-type: "page" +title: "Learn: Data Types" +----- +{@ _defs_.md || 0 @} + + +The following data types are availanle in {{m}} (with the corresponding shorthand symbols used in operator signatures in brackets): + +null (null) +: null value. +boolean (bool) +: **true** or **false**. +integer (int) +: A 64-bit integer number like 1, 27, or -15. +float (flt) +: A 64-bit floating-point number like 3.14 or -56.9876. +string (str) +: A series of characters wrapped in double quotes: "Hello, World!". +quotation (quot) +: A list of elements, which may also contain symbols. Quotations can be used to create heterogenous lists of elements of any data type, and also to create a block of code that will be evaluated later on (quoted program). Example: (1 2 3 + \*) +dictionary (dict) +: A key/value table. Dictionaries are implemented as an immediately-dequoted quotation, are enclosed in curly braces, and are represented by their symbol definitions. Note that dictionary keys must start with `:`and be followed by a double-quoted string, or a single word (which can be written witbout double quotes). The {#link-module||dict#} provides some operators on dictionaries. + + > %sidebar% + > Example + > + > The following is a simple dictionary containing three keys: *name*, *paradigm*, and *first-release-year*: + > + > { + > "min" :name + > "concatenative" :paradigm + > 2017 :"first release year" + > } + +Additionally, dictionaries can also be typed to denote complex objects like sockets, errors, etc. For example, the following dictionary defines an error: + + { + "MyError" :error + "An error occurred" :message + "symbol1" :symbol + "dir1/file1.min" :filename + 3 :line + 13 :column + ;error + } + +> %tip% +> Tip +> +> The {#link-operator||dict||dtype#} operator can be used to set the type of a dictionary. + +The {#link-module||logic#} provides predicate operators to check if an element belongs to a particular data type or pseudo-type (`boolean?`, `number?`, `integer?`, `float?`, ...). + +Additionally, the {#link-module||lang#} provides operators to convert values from a data type to another (e.g. {#link-operator||lang||integer#}, {#link-operator||lang||string#}, and so on). + +> %note% +> Note +> +> Most of the operators defined in the {#link-module||num#} are able to operate on both integers and floats. + +{#link-learn||operators||Operators#}
A docs/learn-definitions.md

@@ -0,0 +1,81 @@

+----- +content-type: "page" +title: "Learn: Definitions" +----- +{@ _defs_.md || 0 @} + + +Being a concatenative language, min does not really need named parameters or variables: symbols just pop elements off the main stack in order, and that's normally enough. There is however one small problem with the traditional concatenative paradigm; consider the following program for example: + + dup dup + "\.zip$" match + swap fsize 1000000 > and + swap mtime now 3600 - > + +This program takes a single string corresponding to a file path and returns true if it's a .zip file bigger than 1MB that was modified in the last hour. Sure, it is remarkable that no variables are needed for such a program, but it is not very readable: because no variables are used, it is often necessary to make copies of elements and push them to the end of the stack -- that's what the {#link-operator||stack||dup#} and {#link-operator||stack||swap#} are used for. + +The good news is that you can use the {#link-operator||lang||define#} operator and the `:` sigil to define new symbols, and symbols can also be set to literals of course. + +Consider the following program: + + :filepath + filepath "\.zip$" match + filepath fsize 1000000 > + filepath mtime now 3600 - > + and and + +In this case, the `filepath` symbol is defined and then used on the following three lines, each of which defines a condition to be evaluated. The last line contains just two {#link-operator||logic||and#} symbols necessary to compare the three conditions. + + +## Lexical scoping and binding + +min, like many other programming languages, uses [lexical scoping](https://en.wikipedia.org/wiki/Scope_\(computer_science\)#Lexical_scope_vs._dynamic_scope) to resolve symbols. + +Consider the following program: + + + 4 :a + ( + a 3 + :a + ( + a 1 + :a + (a dup * :a) dequote + ) dequote + ) dequote + +...What is the value of the symbol `a` after executing it? + +Simple: `4`. Every quotation defines its own scope, and in each scope, a new variable called `a` is defined. In the innermost scope containing the quotation `(a dup * :a)` the value of `a` is set to `64`, but this value is not propagated to the outer scopes. Note also that the value of `a` in the innermost scope is first retrieved from the outer scope (8). + +If we want to change the value of the original `a` symbol defined in the outermost scope, we have to use the {#link-operator||lang||bind#} or its shorthand sigil `@`, so that the program becomes the following: + + 4 :a ;First definition of the symbol a + ( + a 3 + @a ;The value of a is updated to 7. + ( + a 1 + @a ;The value of a is updated to 8 + (a dup * @a) dequote ;The value of a is now 64 + ) dequote + ) dequote + +## Sealing symbols + +Finally, symbols can be sealed to prevent accidental updates or deletions. By default, all symbols defined in the core min modules are sealed, so the following code if run in min shell will result in an error: + + 5 :quote + +...because the symbol quote is already defined in the root scope. However, note that the following code will _not_ return an error: + + (5 :quote quote dup *) -> ;returns 25 + +...because the `quote` symbol is only defined in the root scope and can therefore be redefined in child scopes. + +If you want, you can {#link-operator||lang||seal#} your own symbols so that they may not be redefined using the {#link-operator||lang||bind#} operator or deleted using the {#link-operator||lang||delete#}. + +> %note% +> Note +> +> The {#link-operator||lang||unseal-symbol#} operator can be used to effectively un-seal a previously-sealed symbol. Use with caution! + + +{#link-learn||scopes||Scopes#}
A docs/learn-extending.md

@@ -0,0 +1,115 @@

+----- +content-type: "page" +title: "Learn: Extending min" +----- +{@ _defs_.md || 0 @} + +min provides a fairly complete standard library with many useful modules. However, you may feel the need to extend min in order to perform more specialized tasks. + +In such situations, you basically have the following options: + +* Implementing new min modules using min itself +* Specifying your custom prelude program +* Embedding min in your [Nim](https://nim-lang.org) program + +## Implementing new min modules using min itself + +When you just want to create more high-level min operator using functionalities that are already available in min, the easiest way is to create your own reusable min modules. + +To create a new module, simply create a file containing your operator definitions implemented using either the {#link-operator||lang||operator#} operator or the {#link-operator||lang||lambda#} operator + +``` +(dup *) ^pow2 +(dup dup * *) ^pow3 +(dup dup dup * * *) ^pow4 + +``` + +Save your code to a file (e.g. *quickpows.min*) and you can use it in other nim files using the {#link-operator||lang||require#} operator and the {#link-operator||lang||import#} (if you want to import the operators in the current scope): + +``` +'quickpows require :qp + +2 \*qp/pow3 \*qp/pow2 puts ;prints 64 +``` + +## Specifying your custom prelude program + +By default, when min is started it loads the following *prelude.min* program: + +``` +; Imports +'str import +'io import +'logic import +'num import +'sys import +'stack import +'seq import +'dict import +'time import +'fs import +'crypto import +'math import +'net import +'http import +; Unseal prompt symbol +'prompt unseal-symbol +``` + +Essentially, this causes min to import *all* the modules and unseals the {#link-operator||lang||prompt#} symbol so that it can be customized. If you want, you can provide your own prelude file to specify your custom behaviors, selectively import modules, and define your own symbols, like this: + +> %min-terminal% +> [$](class:prompt) min -i -p:myfile.min + +## Embedding min in your Nim program + +If you'd like to use min as a scripting language within your own program, and maybe extend it by implementing additional operators, you can use min as a Nim library. + +To do so: + +1. Install min sources using Nifty as explained in the {#link-page||download||Download#} section. +2. Import it in your Nim file. +3. Implement a new `proc` to define the module. + +The following code is taken from [HastySite](https://github.com/h3rald/hastysite) and shows how to define a new `hastysite` module containing some symbols (`preprocess`, `postprocess`, `process-rules`, ...): + +``` +import min + +proc hastysite_module*(i: In, hs1: HastySite) = + var hs = hs1 + let def = i.define() + + def.symbol("preprocess") do (i: In): + hs.preprocess() + + def.symbol("postprocess") do (i: In): + hs.postprocess() + + def.symbol("process-rules") do (i: In): + hs.interpret(hs.files.rules) + + # ... + + def.finalize("hastysite") +``` + +Then you need to: + +4. Instantiate a new min interpreter using the `newMinInterpreter` proc. +5. Run the `proc` used to define the module. +6. Call the `interpret` method to interpret a min file or string: + +``` +proc interpret(hs: HastySite, file: string) = + var i = newMinInterpreter(file, file.parentDir) + i.hastysite_module(hs) + i.interpret(newFileStream(file, fmRead)) +``` + +> %tip% +> Tip +> +> For more information on how to create new modules with Nim, have a look in the [lib folder](https://github.com/h3rald/min/tree/master/minpkg/lib) of the min repository, which contains all the min modules included in the standard library. +
A docs/learn-operators.md

@@ -0,0 +1,337 @@

+----- +content-type: "page" +title: "Learn: Operators" +----- +{@ _defs_.md || 0 @} + +Every min program needs _operators_ to: + +* Manipulate elements on the stack +* Perform operations on data +* Provide side effects (read/print to standard input/output/files, etc.) + +There are two types of operators: _symbols_ and _sigils_. + +## Symbols + +_Symbols_ are the most common type of operator. A min symbol is a single word that is either provided by one of the predefined min {#link-page||reference||modules#} like `dup` or `.` or defined by the user. User-defined symbols must: + +* Start with a letter or an underscore (\_). +* Contain zero or more letters, numbers and/or any of the following characters: `/ ! ? + * . _ -` + +It is possible to define operator symbols using the {#link-operator||lang||operator#} symbol. The following min program defines a new symbol called square that duplicates the first element on the stack and multiplies the two elements: + + ( + symbol square + (num :n ==> num :result) + (n dup * @result) + ) operator + ;; Calculates the square of n. + + The {#link-operator||lang||operator#} symbol provides way to: + * Specify the name of the symbol operator (**square** in this case) + * Specify a signature to identify the type of the input and output values (in this case, the operator takes a numeric input value and produces a numeric output value). Also, note how inputs and outputs are captured into the `n` and `result` symbols in the signature quotation and then referenced in the body quotation. + * Specify a quotation containing the code that the operator will execute. + +Also, symbol operator definitions can be annotated with documentation comments (starting with `;;` or wrapped in `#|| ... ||#`)) so that a help text can be displayed using the {#link-operator||lang||help#} symbol. + +### Using the lambda operator + +Sometimes you just want to bind a piece of code to a symbol to reuse it later, typically something simple and easy-to-read. In these cases, you can use the {#link-operator||lang||lambda#} operator (or the `^` sigil). For example, the previous `square` operator definition could be rewritten simply as the following. + + (dup *) ^square + +Note that this feels like using {#link-operator||lang||define#}, but the main difference between {#link-operator||lang||lambda#} and {#link-operator||lang||define#} is that `lambda` only works on quotations doesn't auto-quote them, so that they are immediately evaluated when the corresponding symbol is pushed on the stack. + +Also note that unlike with {#link-operator||lang||operator#}, symbols defined with {#link-operator||lang||lambda#}: +* have no built-in validation of input and output values. +* do not support the `return` symbol to immediately end their execution. +* have no built-in stack pollution checks. + +> %tip +> Tip +> +> You can use {#link-operator||lang||lambda-bind#} to re-set a previously set lambda. + +## Sigils + +Besides symbols, you can also define sigils. min provides a set of predefined _sigils_ as abbreviations for for commonly-used symbols. + +A sigil can be prepended to a double-quoted string or a single word (with no spaces) which will be treated as a string instead of using the corresponding symbol. + +For example, the following executes the command `ls -al` and pushes the command return code on the stack: + + !"ls -al"` + +Currently min provides the following sigils: + +' +: Alias for {#link-operator||lang||quote#}. +\: +: Alias for {#link-operator||lang||define#}. +* +: Alias for {#link-operator||lang||invoke#}. +@ +: Alias for {#link-operator||lang||bind#}. +^ +: Alias for {#link-operator||lang||lambda#}. +> +: Alias for {#link-operator||lang||save-symbol#}. +< +: Alias for {#link-operator||lang||load-symbol#}. +/ +: Alias for {#link-operator||dict||dget#}. +% +: Alias for {#link-operator||dict||dset#}. +? +: Alias for {#link-operator||lang||help#}. +! +: Alias for {#link-operator||sys||system#}. +& +: Alias for {#link-operator||sys||run#}. +$ +: Alias for {#link-operator||sys||get-env#}. + +Besides system sigils, you can also create your own sigils. Unlike system sigils however, user defined sigils: + +* have the same character restrictions as symbols +* can only be prepended to double-quoted strings +* can be unsealed, deleted, redefined, and sealed. + +Sigils can be a very powerful construct and a way to reduce boulerplate code: you can define a sigil to use as you would use any symbol which requires a single string or quoted symbol on the stack. + +Like symbols, sigils can be defined with the {#link-operator||lang||operator#} operator, like this: + + ( + sigil j + (string :json ==> a :result) + (json from-json @result) + ) operator + +This definition will add a `j` sigil that will process the follwing string as JSON code, so for example: + + j"{\"test\": true}" + +...will push the following dictionary on the stack: + + {true :test} + +Also, sigil definitions can be annotated with documentation comments (starting with `;;` or wrapped in `#|| ... ||#`)`) so that a help text can be displayed using the {#link-operator||lang||help#} symbol. + +## Auto-popping + +Typically, but not always, operators push one or more value to the stack. While this is typically the desired behavior, in some cases you may want to keep the stack clear so in these cases you can append a `!` character to any symbol to cause the symbol {#link-operator||lang||pop#} to be pushed on the stack immediately afterwards. + + "test" puts ;Prints "test" and pushes "test" on the stack. + "test" puts! ;Prints "test" without pushing anything on the stack. + +## Operator signatures + +When defining symbols and sigils witb the {#link-operator||lang||operator#} operator, you must specify a *signature* that will be used to validate and captuee input and output values: + + ( + symbol square + (num :n ==> num :result) + (n dup * @result) + ) operator + +In this case for example tbe `square` symbol expects a number on the stack, which will be captured to tbe symbol `n` and it will place a number on the stack which needs to be bound in the operator body to the symbol `result`. + +In a signature, a type expression must precede the capturing symbol. Such type expression can be: + +* One of the following shorthand symbols identifying a well-known {{m}} base type (see the {#link-page||reference||reference#} section for more information): `a`, `bool`, `null`, `str`, `int`, `num`, `flt`, `'sym`, `quot`, or `dict`. +* A typed dictionary like `dict:module` or `dict:datastore`. +* A type class (see below). +* a type expression like `str|int`. + +> %note% +> Note +> +> If the operator you are defining doesn't require any input value or doesn't leave ang output value on the srack, simply don't put anything before or after the `==>` separator, respectively. For example, the signature of the {#link-operator||lang||puts!#} operator could be written like `(a ==>)`. + +### Type classes + +Besides standard base types, you can define your own *type classes* to express custom constraints/validations for operator input and output values. + +Consider the following type class definition validating a quotation containing strings: + + ( + typeclass strquot + (quot :q ==> bool :o) + (q (string?) all? @o) + ) :: + +The {#link-operator||lang||operator#} operator can be used to define a symbol prefixed with `typeclass:` (`typeclass:strquot` in this case) corresponding to a type class that can be used in operator signatures in place of a type, like this: + + ( + symbol join-strings + (strquot :q ==> str :result) + ( + q "" (suffix) reduce @result + ) + ) + +This operator will raise an error if anything other than a quotation of strings is found on the stack. + +> %tip% +> Tip +> +> `typeclass:`-prefixed symbols are just like ordinary shmbols: they are lexically scoped, they can be sealed, unsealed and deleted. + +#### Capturing lambdas + +You can also specify a lambda to be captured to an output value, like this: + + ( + symbol square + (==> quot ^o) + ( + (dup *) ~o + ) + ) :: + +Essentially, this allows you to push a lambda on the stack from an operator. + +Note that: + +* Lambdas must be captured using the `^` sigil in signatures and bound using {#link-operator||lang||lambda-bind#} in the operator body. +* Lambdas cannot be captured in input values (they have already been pushed on the stack). +* Requiring a lambda as an output value effectively bypasses stack pollution checks. While this can be useful at times, use with caution! + +### Type expressions + +When specifying types in operator signatures or through the {#link-operator||lang||expect#} operator, you can specify a logical expression containing types and type classes joined with one of the following operators: + +* `|` (or) +* `&` (and) +* `!` (not) + +Suppose for example you defined the following type classes: + +``` +(typeclass fiveplus + (int :n ==> bool :o) + ( + n 5 > @o + ) +) :: + +(typeclass tenminus + (int :n ==> bool :o) + ( + n 10 < @o + ) +) :: + +(typeclass even + (int :n ==> bool :o) + ( + n 2 mod 0 == @o + ) +) :: +``` + +You can combine them in a type expression as following: + +``` +(symbol test + (!even|tenminus&fiveplus :n ==> bool :o) + ( + true @o + ) +) :: +4 test ; error +6 test ; true +11 test ; true +``` + +### Type aliases + +As you can see, type expressions can quickly become quite long and complex. To avoid this, you can define *type aliases* using the {#link-operator||lang||typealias#} operator. + +For example, you can create an alias of part of the type expression used in the previous example, like this: + +``` +'tenminus&fiveplus 'five-to-ten typealias + +(symbol test + (!even|five-to-ten :n ==> bool :o) + ( + true @o + ) +) :: +``` + +Note that: + +* Type aliases be used to create an alias for any type expression. +* Aliased type expressions can contain standard {{m}} types, dictionary types, type classes, and even other type aliases. +* The {#link-operator||lang||typealias#} operator actually creates lexically-scoped, `typealias:`-prefixed symbols that can be sealed, unsealed, and deleted exactly like other symbols. + +### Generics + +{{m}} supports generics in operator signatures. in other words, you can define a custom type alias on-the-fly directly in an operator signature, like this: + +``` +( + symbol add + ((str|num|quot :t) :a t :b ==> t :result) + ( + (a type "str" ==) + (a b suffix @result return) + when + (a type "num" ==) + (a b + @result return) + when + (a type "quot" ==) + (a b concat #result return) + when + ) +) :: +``` + +In this case, `t` is set to the type union `stribg|num|quot`, and the `add` method above can be use too sum two numbers or join two strings or quotations. + +Note that the value of `t` is evaluated to the type of the first value that is processed. In other words, the following programs will work as expected: + + 3 5 add ;outputs 8 + + "hello, " "world" ;outputs "hello, world" + +while tbe fullowing will raise an error, because the value of `t` from `num` to `quot` within the same operator use: + + 12 "test" add ;raises an error + +> %sidebar% +> Generics vs type unions +> +> Generics allow to specify a type as a type union, but the type will remain the same one throughout the same operator call. +> By contrast, using the same type union several times within the same signature allows different types to be used in the same call, and that is probably something you dont want! + +### Constructors + +The {#link-operator||lang||operator#} operator can also be used to create *constructor* symbols. A constructor is a particular type of operator that is used to create a new typed dictionary. + +Consider the following example: + + ( + constructor point + (num :x num :y ==> dict :out) + ( + {} + x %x + y %y + @out + ) + ) :: + +The operator above creates a `point` constructor symbol that can be used to create a new `dict:point` typed dictionary by popping two numbers from the stack: + + 2 3 point ; {2 :x 3 :y ;point} + +> %note% +> Tip +> +> Except for some native symbols, constructors represent the only way to create new typed dictionaries. The more validations you perform in a constructor, the most effective checking for a specific type using the {#link-operator||logic||type?#} operator will be, as `type?` only checks if a specific type annotation is present on a typed dictionary, nothing else. + +{#link-learn||quotations||Quotations#}
A docs/learn-quotations.md

@@ -0,0 +1,61 @@

+----- +content-type: "page" +title: "Learn: Quotations" +----- +{@ _defs_.md || 0 @} + +Quotations are the most important thing to understand in min. Besides being the data type used for lists, they are also used to delimit blocks of min code that is not going to be immediately executed. + +Consider for example the following min code which returns all the files present in the current folder sorted by name: + + . ls (ftype "file" ==) filter '> sort + +The symbol {#link-operator||seq||filter#} takes two quotations as arguments -- the first quotation on the stack is applied to all the elements of the second quotation on the stack, to determine which elements of the second quotation will be part of the resulting quotation. This is an example of how quotations can be used both as lists and programs. + +Let's examine this program step-by-step: + +{{fdlist => ("dir1" "dir2" file1.txt "file2.txt" "file3.md" "file4.md")}} +{{flist => ("file1.txt" "file2.txt" "file3.md" "file4.md")}} + +1. The `.` symbol is pushed on the stack, and it is immediately evaluated to the full path to the current directory. +2. The `ls` symbol is pushed on the stack, it consumes the string already on the stack and returns a quotation containing all files and directories within the current directory. +3. The quotation `(ftype 'file ==)` is pushed on the stack. It is treated exactly like a list of data and it is not evaluated. +4. The `filter` symbol is pushed on the stack. This symbol takes two quotations as input, and applies the result of the first quotation on the stack (`(ftype "file" ==)`) to all elements of the second quotation of the stack (the list of files and directories), returning a new quotation containing only those elements of the second quotation on the stack that satisfy the result of the first quotation. In this case, it returns a new quotation containing only files. +5. `'>` is pushed on the stack. The `'` sigil can be used instead of the `quote` symbol to quote a single symbol, `<` in this case. In other words, it is instantly evaluated to the quotation `(>)`. +6. The symbol `sort` is pushed on the stack. This symbol, like `filter`, takes two quotations as input, and applies the first quotation to each element of the second quotation, effectively sorting each element of the second quotation using the predicate expressed by the first quotation. In this case, all files are sorted by name in ascending order. + +> %tip% +> Tip +> +> The {#link-module||seq#} provides several symbols to work with quotations in a functional way. + + +## Quoting, dequoting, and applying + +When a quotation is created, it is treated as data, no matter what it contains: it is placed on the stack, like an integer or a string would. However, unlike other data types, a quotation can be evaluated in certain situations and when it happens its contents are pushed on the stack. + +Consider the following program: + + (1 2 3 4 5 6 7) (odd?) filter + +This program returns a new quotation containing all odd numbers contained in quotation `(1 2 3 4 5 6 7)`. + +In this case, the second quotation is used to _quote_ the symbol `odd?` so that instead of being executed immediately, it will be executed by the symbol `filter` on each element of the first quotation. In this way, we may say that `(odd?)` is _dequoted_ by the symbol `filter`. + +The symbol {#link-operator||lang||dequote#} or its alias `->` can be used to dequote a quotation by pushing all its elements on the main stack. Essentially, this *executes* the quotation in the current context. + +For example, the following program leaves the elements `1` and `-1` on the stack: + + (1 2 3 -) -> + +Alternatively, the symbol {#link-operator||lang||apply#} or its alias `=>` can also be used to dequote a quotation but in this case it will not push its elements on the main stack, instead it will: + +1. Create a temporary empty stack. +2. Push all elements on it, one by one. +3. Push the entire temporary stack as a quotation back on the main stack. + +For example, the following program leaves the element `(1 -1)` on the stack: + + (1 2 3 -) => + +{#link-learn||definitions||Definitions#}
A docs/learn-scopes.md

@@ -0,0 +1,61 @@

+----- +content-type: "page" +title: "Scopes" +----- +{@ _defs_.md || 0 @} + +As explained in [Definitions](/learn-definitions), min uses lexical scoping to resolve symbols and sigils. A *scope* is an execution context (a symbol table really) that: + +* is created while a new quotation is being dequoted or a dictionary is created. +* is destroyed after a quotation has been dequoted. +* is attached to a dictionary. + +The main, root-level scope in min can be accessed using the {#link-operator||lang||ROOT#} symbol and it typically contains all symbols and sigils imported from all the standard library modules. The ROOT symbol pushes a module on the stack that references the ROOT scope: + +> %min-terminal% +> [[/Users/h3rald/test]$](class:prompt) ROOT +> { +> &lt;native&gt; :! +> &lt;native&gt; :!= +> ... +> &lt;native&gt; :xor +> &lt;native&gt; :zip +> ;module +> } + +> %note% +> Note +> +> &lt;native&gt; values cannot be retrieved using the {#link-operator||dict||dget#} operator. + +## Accessing the current scope + +You can access the current scope using the {#link-operator||lang||scope#} operator, which pushes a module on the stack that references the current scope. + +Consider the following program: + + {} :innerscope ("This is a test" :test scope @myscope) -> myscope scope-symbols + +In this case: + +1. A new variable called `innerscope` is defined on the ROOT scope. +2. A quotation is dequoted, but its scope is retrieved using the `scope` operator and bound to `innerscope`. +3. After the quotation is dequoted, myscope is accessed and its symbols (`test` in this case) are pushed on the stack using the {#link-operator||lang||scope-symbols#} operator. + +Note that scopes can only be accessed if they are bound to a dictionary, hence the `ROOT` and `scope` operators push a module on the stack, and a module is nothing but a typed dictionary. + +## Dequoting a quotation within the context of a specific scope + +The {#link-operator||lang||with#} operator can be used to dequote a quotation within a specific scope instead of the current one. + +Consider the following program, which leaves `2` on the stack: + + (4 2 minus) {'- :minus} with -> + +In this case, when `with` is pushed on the stack, it will dequote `(4 2 minus)`. Note that the symbol `minus` is defined in the dictionary that will be used by `with` as the current scope, so after `with` is pushed on the stack, the stack contents are: + + 4 2 (-) + +At this point, the {#link-operator||lang||dequote#} operator is pushed on the stack and the subtraction is executed leaving `2` on the stack. + +{#link-learn||control-flow||Control Flow#}
A docs/learn.md

@@ -0,0 +1,37 @@

+----- +content-type: "page" +title: "Learn" +----- +{@ _defs_.md || 0 @} + +{{learn-links}} + +{{m}} is a stack-based, concatenative programming language that uses postfix notation. If you already know [Forth](http://www.forth.org/), [Factor](http://factorcode.org/) or [Joy](http://www.kevinalbrecht.com/code/joy-mirror/), or if you ever used an [RPN](https://en.wikipedia.org/wiki/Reverse_Polish_notation) calculator, then min will look somewhat familiar to you. + +If not, well, here's how a short min program looks like: + + ; This is a comment + (1 2 3 4 5) (dup *) map + #| This is a... + ...multiline comment |# + +This program returns a list containing the square values of the first five integer numbers: + + (1 4 9 16 25) + +Let's see how it works: + +1. First, a list containing the first five integers is pushed on the stack. +2. Then, another list containing two symbols (`dup` and `*`) is pushed on the stack. This constitutes a quoted program which, when executed duplicates the first element on the stack &mdash; this is done by `dup`&mdash; and then multiplies &mdash; with `*`&mdash; the two elements together. +3. Finally, the symbol `map` is pushed on the stack. Map takes a list of elements and a quoted program and applies the program to each element. + +Note that: + +* There are no variable assignments. +* elements are pushed on the stack one by one. +* Parentheses are used to group one or more elements together so that they are treated as a single element and they are not evaluated immediately. +* *Symbols* (typically single words, or several words joined by dashes) are used to execute code that performs operations on the whole stack. + +Unlike more traditional programming languages, in a concatenative programming language, there is no inherent need for variables or named parameters, as symbols act as stack operators that consume elements that are placed in order on top of a stack. + +{#link-learn||data-types||Data Types#}
A docs/reference-io.md

@@ -0,0 +1,99 @@

+----- +content-type: "page" +title: "io Module" +----- +{@ _defs_.md || 0 @} + +{#op||ask||{{s1}}||{{s2}}|| +Prints {{s1}} (prompt), reads a line from STDIN and places it on top of the stack as a string.#} + +{#op||choose||(({{s1}} {{q1}}){{1p}}) {{s2}}||{{a0p}}|| +> Prints {{s2}}, then prints all {{s1}} included in the quotation prepended with a number, and waits from valid input from the user. +> +> If the user enters a number that matches one of the choices, then the corresponding quotation {{q1}} is executed, otherwise the choice menu is displayed again until a valid choice is made. #} + +{#op||clear||{{none}}||{{none}}|| +Clears the screen.#} + +{#op||column-print||{{q}} {{i}}||{{any}}|| +Prints all elements of {{q}} to STDOUT, in {{i}} columns.#} + +{#op||confirm||{{s}}||{{b}}|| +> Prints {{s}} (prompt) appending `" [yes/no]: "`, reads a line from STDIN and: +> +> * if it matches `/^y(es)?$/i`, puts {{t}} on the stack. +> * if it matches `/^no?$/i`, puts {{f}} on the stack. +> * Otherwise, it prints `Invalid answer. Please enter 'yes' or 'no': ` and waits for a new answer. #} + +{#op||debug||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDOUT, if logging level is set to [debug](class:kwd) or lower.#} + +{#op||error||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDERR, if logging level is set to [error](class:kwd) or lower.#} + +{#op||fappend||{{s1}} {{s2}}||{{none}}|| +Appends {{s1}} to the end of file {{s2}}. #} + +{#op||fatal||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDERR, and exists the program with error code `100`.#} + +{#op||fread||{{s}}||{{s}}|| +Reads the file {{s}} and puts its contents on the top of the stack as a string.#} + +{#op||fwrite||{{s1}} {{s2}}||{{none}}|| +Writes {{s1}} to the file {{s2}}, erasing all its contents first. #} + +{#op||getchr||{{none}}||{{i}}|| +Reads single character from STDIN without waiting for ENTER key and places its ASCII code on top of the stack.#} + +{#op||info||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDOUT, if logging level is set to [info](class:kwd) or lower.#} + +{#op||mapkey||{{q}} {{sl}}||{{none}}|| +> Maps the named key/key combination {{sl}} to the quotation {{q}}, so that {{q}} is executed when key {{sl}} is pressed. +> +> > %note% +> > Notes +> > +> > * At present, only the key names and sequences defined in the [nimline](https://h3rald.com/nimline/nimline.html) library are supported. +> > * The quotation will be executed by a copy of the min interpreter created when the mapping was defined. In other words, quotations executed by key bindings will not affect the current stack. +> +> > %sidebar% +> > Example +> > +> > The following program: +> > +> > (clear) 'ctrl+l keymap +> > +> > causes the `CTRL+L` key to clear the screen. #} + +{#op||newline||{{none}}||{{none}}|| +Prints a new line to STDOUT.#} + +{#op||notice||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDOUT, if logging level is set to [notice](class:kwd) (default) or lower.#} + +{#op||password||{{none}}||{{s}}|| +Reads a line from STDIN displaying \* for each typed character, and places it on top of the stack as a string.#} + +{#op||print||{{any}}||{{any}}|| +Prints {{any}} to STDOUT.#} + +{#op||putchr||{{s}}||{{any}}|| +Prints {{s}} to STDOUT without printing a new line ({{s}} must contain only one character).#} + +{#op||type||{{any}}||{{s}}|| +Puts the data type of {{any}} on the stack. In cased of typed dictionaries, the type name is prefixed by `dict:`, e.g. `dict:module`, `dict:socket`, etc.#} + +{#op||unmapkey||{{sl}}||{{none}}|| +> Unmaps a previously-mapped key or key-combination {{sl}}, restoring the default mapping if available. +> +> > %note% +> > Notes +> > +> > * At present, only the key names and sequences defined in the [nimline](https://h3rald.com/nimline/nimline.html) library are supported. +> > * At present, all the default mappings of min are those provided by the [nimline](https://h3rald.com/nimline/nimline.html) library. + #} + +{#op||warning||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDERR, if logging level is set to [warning](class:kwd) or lower.#}
A docs/reference-lang.md

@@ -0,0 +1,534 @@

+----- +content-type: "page" +title: "lang Module" +----- +{@ _defs_.md || 0 @} + +{#sig||&apos;||quotesym#} + +{#alias||&apos;||quotesym#} + +{#sig||:||define#} + +{#alias||:||define#} + +{#alias||::||operator#} + +{#sig||?||help#} + +{#alias||?||help#} + +{#sig||&ast;||invoke#} + +{#sig||@||bind#} + +{#alias||@||bind#} + +{#sig||&gt;||save-symbol#} + +{#sig||&lt;||load-symbol#} + +{#alias||->||dequote#} + +{#alias||&gt;&gt;||prefix-dequote#} + +{#alias||&gt;&lt;||infix-dequote#} + +{#alias||=&gt;||apply#} + +{#op||==&gt;||{{none}}||{{none}}|| +Symbol used to separate input and output values in operator signatures.#} + +{#alias||=-=||expect-empty-stack#} + +{#sig||^||lambda#} + +{#alias||^||lambda#} + +{#op||apply||{{q}}||({{a0p}})|| +Returns a new quotation obtained by evaluating each element of {{q}} in a separate stack. #} + +{#op||args||{{none}}||{{q}}|| +Returns a list of all arguments passed to the current program.#} + +{#op||bind||{{any}} {{sl}}||{{none}}|| +Binds the specified value (auto-quoted) to an existing symbol {{sl}}.#} + +{#op||bool||{{any}}||{{b}}|| +> Converts {{any}} to a boolean value based on the following rules: +> +> * If {{any}} is a boolean value, no conversion is performed. +> * If {{any}} is {{null}}, it is converted to {{f}}. +> * If {{any}} is a numeric value, zero is converted to {{f}}, otherwise it is converted to {{t}}. +> * If {{any}} is a quotation or a dictionary, the empty quotation or dictionary is converted to {{f}}, otherwise it is converted to {{t}}. +> * If {{any}} is a string, the empty string, and `"false"` are converted to {{f}}, otherwise it is converted to {{t}}.#} + +{#op||case||(({{q1}} {{q2}}){{0p}})||{{a0p}}|| +> This operator takes a quotation containing _n_ different conditional branches. +> +> Each branch must be a quotation containing two quotations, and it is processed as follows: +> +> * if {{q1}} evaluates to {{t}}, then the {{q2}} is executed. +> * if {{q1}} evaluates to {{f}}, then the following branch is processed (if any). +> +> > %sidebar% +> > Example +> > +> > The following program prints "Smaller than 3": +> > +> > 2 ( +> > ((> 3) ("Greater than 3" put!)) +> > ((< 3) ("Smaller than 3" put!)) +> > ((true) ("Exactly 3" put!)) +> > ) case #} + +{#op||compiled?||{{none}}||{{b}}|| +Returns {{t}} if the current program has been compiled.#} + +{#op||define||{{any}} {{sl}}||{{none}}|| +Defines a new symbol {{sl}}, containing the specified value.#} + +{#op||define-sigil||{{any}} {{sl}}||{{none}}|| +Defines a new sigil {{sl}}, containing the specified value (auto-quoted if not already a quotation).#} + +{#op||defined-symbol?||{{sl}}||{{b}}|| +Returns {{t}} if the symbol {{sl}} is defined, {{f}} otherwise.#} + +{#op||defined-sigil?||{{sl}}||{{b}}|| +Returns {{t}} if the symbol {{sl}} is defined, {{f}} otherwise.#} + +{#op||delete-sigil||{{sl}}||{{none}}|| +Deletes the specified symbol {{sl}}.#} + +{#op||delete-sigil||{{sl}}||{{none}}|| +Deletes the specified user-defined sigil {{sl}}.#} + +{#op||dequote||{{q}}||{{a0p}}|| +> Pushes the contents of quotation {{q}} on the stack. +> +> Each element is pushed on the stack one by one. If any error occurs, {{q}} is restored on the stack.#} + +{#op||eval||{{s}}||{{a0p}}|| +Parses and interprets {{s}}. #} + +{#op||exit||{{i}}||{{none}}|| +Exits the program or shell with {{i}} as return code. #} + +{#op||expect||{{q1}}||{{q2}}|| +> Validates the first _n_ elements of the stack against the type descriptions specified in {{q1}} (_n_ is {{q1}}'s length) and if all the elements are valid returns them wrapped in {{q2}} (in reverse order). + +> > %tip% +> > Tips +> > +> > * You can specify a typed dictionary by prepending the type name with `dict:`. Example: `dict:socket` +> > * You can specify two or more matching types by separating combined together in a logical type expression, e.g.: `string|quot` + +> > %sidebar% +> > Example +> > +> > Assuming that the following elements are on the stack (from top to bottom): +> > +> > `1 "test" 3.4` +> > +> > the following program evaluates to `true`: +> > +> > `(int string num) expect (3.4 "test" 1) ==`#} + +{#op||expect-empty-stack||{{none}}||{{none}}|| +Raises an error if the stack is not empty.#} + +{#op||float||{{any}}||{{flt}}|| +> Converts {{any}} to a float value based on the following rules: +> +> * If {{any}} is {{t}}, it is converted to `1.0`. +> * If {{any}} is {{f}}, it is converted to `0.0`. +> * If {{any}} is {{null}}, it is converted to `0.0` +>. * If {{any}} is a integer, it is converted to float value. +> * If {{any}} is a float, no conversion is performed. +> * If {{any}} is a string, it is parsed as a float value.#} + +{#op||foreach||{{q1}} {{q2}}||{{a0p}}|| +Applies the quotation {{q2}} to each element of {{q1}}.#} + +{#op||format-error||{{e}}||{{s}}|| +> Formats the error {{e}} as a string. +> > %sidebar% +> > Example +> > +> > The following code: +> > +> > ( +> > ( +> > {"MyError" :error "This is a test error" :message} raise +> > ) +> > (format-error) +> > ) try +> > +> > produces: `"This is a test error"`#} + +{#op||from-json||{{s}}||{{any}}|| +Converts a JSON string into {{m}} data.#} + +{#op||from-yaml||{{s}}||{{any}}|| +> Converts a YAML string into {{m}} data. +> > %note% +> > Note +> > +> > At present, only YAML objects containing string values are supported.#} + +{#op||gets||{{none}}||{{s}}|| +Reads a line from STDIN and places it on top of the stack as a string.#} + +{#op||help||{{sl}}||{{none}}|| +Prints the help text for {{sl}}, if available. #} + +{#op||if||{{q1}} {{q2}} {{q3}}||{{a0p}}|| +If {{q1}} evaluates to {{t}} then evaluates {{q2}}, otherwise evaluates {{q3}}.#} + +{#op||import||{{sl}}||{{none}}|| +Imports the a previously-loaded module {{sl}}, defining all its symbols in the current scope. #} + +{#op||infix-dequote||{{q}}||{{any}}|| +> Dequotes {{q}} using infix notation. +> +> Note that no special operator preference is defined, symbols precedence is always left-to-right. However, you can use parentheses (quotes) to evaluate expressions before others. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `17` on the stack: +> > +> > (2 + (3 * 5)) infix-dequote +> > +> > while this program leaves `25` on the stack: +> > +> > (2 + 3 * 5) infix-dequote + #} + +{#op||integer||{{any}}||{{i}}|| +> Converts {{any}} to an integer value based on the following rules: +> +> * If {{any}} is {{t}}, it is converted to `1`. +> * If {{any}} is {{f}}, it is converted to `0`. +> * If {{any}} is {{null}}, it is converted to `0`. +> * If {{any}} is an integer, no conversion is performed. +> * If {{any}} is a float, it is converted to an integer value by truncating its decimal part. +> * If {{any}} is a string, it is parsed as an integer value.#} + +{#op||invoke||{{sl}}||{{a0p}}|| +> Assming that {{sl}} is a formatted like *dictionary*/*symbol*, calls *symbol* defined in *dictionary* (note that this also works for nested dictionaries. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `100` on the stack: +> > +> > {{100 :b} :a} :test *test/a/b + #} + + {#op||lambda||{{q}} {{sl}}||{{none}}|| +Defines a new symbol {{sl}}, containing the specified quotation {{q}}. Unlike with `define`, in this case {{q}} will not be quoted, so its values will be pushed on the stack when the symbol {{sl}} is pushed on the stack. + +Essentially, this symbol allows you to define an operator without any validation of constraints and bind it to a symbol.#} + +{#op||line-info||{{none}}||{{d}}|| +Returns a dictionary {{d}} containing a **filename**, **line**, and **column** properties identifying the filename, line and column of the current symbol.#} + +{#op||linrec||{{q1}} {{q2}} {{q3}} {{q4}}||{{a0p}}|| +> Implements linear recursions as follows: +> +> 1. Evaluates {{q1}}. +> * If {{q1}} evaluates to {{t}}, then it evaluates {{q2}}. +> * Otherwises it executes {{q3}} and recurses using the same four quotations. +> 2. Finally, it executes {{q4}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `120` on the stack, the factorial of 5: +> > +> > 5 (dup 0 ==) 'succ (dup pred) '* linrec + #} + +{#op||load||{{sl}}||{{a0p}}|| +Parses and interprets the specified {{m}} file {{sl}}, adding [.min](class:ext) if not specified. #} + +{#op||load-symbol||{{sl}}||{{a0p}}|| +Loads the contents of symbol {{sl}} from the [.min\_symbols](class:file) file. #} + +{#op||loglevel||{{sl}}||{{none}}|| +> Sets the current logging level to {{sl}}. {{sl}} must be one of the following strings or quoted symbols: +> +> * debug +> * info +> * notice +> * warn +> * error +> * fatal +> +> > %note% +> > Note +> > +> > The default logging level is _notice_.#} + +{#op||loglevel?||{{none}}||{{s}}|| +Returns the current log level (debug, info, notive, warn, error or fatal). #} + +{#op||operator||{{q}}||{{a0p}}|| +> Provides a way to define a new operator (symbol, sigil, or typeclass) on the current scope performing additional checks (compared to `define` and `define-sigil`), and automatically mapping inputs and outputs. +> +> {{q}} is a quotation containing: +> +> * A symbol identifying the type of operator to define (`symbol`, `sigil`, or `typeclass`). +> * A symbol identifying the name of the operator. +> * A quotation defining the signature of the operatorm containing input and output values identified by their type and a capturing symbol, separated by the `==>` symbol. +> * A quotation identifying the body of the operator. +> +> The main additional features offered by this way of defining operators are the following: +> +> * Both input and output values are checked against a type (like when using the `expect` operator *and* automatically captured in a symbol that can be referenced in the operator body quotation. +> * The full signature of the operator is declared, making the resulting code easier to understand at quick glance. +> * An exception is automatically raised if the operator body pollutes the stack by adding or removing elementa from the stack (besides adding the declared output values). +> * It is possible to use the `return` symbol within the body quotation to immediately stop the evaluation of the body quotation and automatically push the output values on the stack. +> +> > %sidebar% +> > Example +> > +> > The following program defines a `pow` operator that calculates the power of a number providing its base and exponent, and handling some NaN results using the `return` symbol: +> > +> > ( +> > symbol pow +> > (num :base int :exp ==> num :result) +> > ( +> > (base 0 == exp 0 == and) +> > (nan @result return) +> > when +> > (base 1 == exp inf == and) +> > (nan @result return) +> > when +> > (base inf == exp 0 == and) +> > (nan @result return) +> > when +> > exp 1 - :n +> > base (dup) n times (*) n times @result +> > ) +> > ) :: + #} + +{#op||opts||{{none}}||{{d}}|| +Returns a dictionary of all options passed to the current program, with their respective values.#} + +{#op||parent-scope||{{d1}}||{{d2}}|| +Returns a dictionary {{d2}} holding a reference to the parent scope of {{d1}} or {{null}} if {{d1}} is ROOT.#} + +{#op||parse||{{s}}||{{q}}|| +Parses {{s}} and returns a quoted program {{q}}. #} + +{#op||prefix-dequote||{{q}}||{{any}}|| +> Dequotes {{q}} using prefix notation (essentially it reverses {{q}} and dequotes it). +> +> > %sidebar% +> > Example +> > +> > The following program leaves `4` on the stack: +> > +> > (* 8 4) prefix-dequote + #} + +{#op||prompt||{{none}}||{{s}}|| +> This symbol is used to configure the prompt of the min shell. By default, it is set to the following quotation: +> +> ("[$1]$$ " (.) => %) +> +> Unlike other predefined symbols, this symbol is _unsealed_, which means it can be modified.#} + +{#op||publish||{{sl}} {{d}}||{{none}}|| +> Publishes symbol {{sl}} to the scope of {{d}}. +> +> > %sidebar% +> > Example +> > +> Publish symbol [my-local-symbol](class:kwd) to [ROOT](class:kwd) scope: +> > `'my-local-symbol ROOT publish` #} + +{#op||puts||{{any}}||{{any}}|| +Prints {{any}} and a new line to STDOUT.#} + +{#op||quit||{{none}}||{{none}}|| +Exits the program or shell with 0 as return code. #} + +{#op||quote||{{any}}||({{any}})|| +Wraps {{any}} in a quotation. #} + +{#op||quotesym||{{s}}||({{sym}})|| +Creates a symbol with the value of {{s}} and wraps it in a quotation. #} + + +{#op||raise||{{e}}||{{none}}|| +Raises the error specified via the dictionary {{e}}.#} + +{#op||raw-args||{{none}}||{{q}}|| +Returns a list of all arguments and (non-parsed) options passed to the current program.#} + +{#op||remove-symbol||{{sl}}||{{none}}|| +Removes the symbol {{sl}} from the [.min\_symbols](class:file) file. #} + +{#op||require||{{sl}}||{{d}}|| +Parses and interprets (in a separater interpreter) the specified {{m}} file {{sl}}, adding [.min](class:ext) if not specified, and returns a module dictionary {{d}} containing all the symbols defined in {{sl}}. #} + +{#op||return||{{none}}||{{none}}|| +If used within the body quotation of an operator definition, causes the interpreter to stop pushing further body elements on the stack and start pushing tbe operator output values on the stack. + +If used outside of the body quotation of an operator definition, it raises an exception.#} + +{#op||ROOT||{{none}}||{{d}}|| +Returns a module holding a reference to the [ROOT](class:kwd) scope. + +> > %tip% +> > Tip +> > +> > This symbol is very useful in conjunction with the **with** operator. + #} + +{#op||save-symbol||{{sl}}||{{none}}|| +Saves the contents of symbol {{sl}} to the [.min\_symbols](class:file) file. #} + +{#op||scope||{{none}}||{{d}}|| +> Returns a dictionary {{d}} holding a reference to the current scope. +> +> This can be useful to save a reference to a given execution scope to access later on. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `{(2) :two ;module}` on the stack: +> > +> > {} :myscope (2 :two scope @myscope) -> + #} + +{#op||saved-symbols||{{none}}||({{s0p}})|| +Returns a quotation containing all symbols saved in the [.min\_symbols](class:file) file. #} + +{#op||scope-sigils||{{d}}||({{s0p}})|| +Returns a list of all sigils defined in dictionary {{d}}.#} + +{#op||scope-symbols||{{d}}||({{s0p}})|| +Returns a list of all symbols defined in dictionary {{d}}.#} + +{#op||seal-symbol||{{sl}}||{{none}}|| +Seals symbol {{sl}}, so that it cannot be re-assigned. #} + +{#op||seal-sigil||{{sl}}||{{none}}|| +Seals the user-defined sigil {{sl}}, so that it cannot be re-defined. #} + +{#op||sealed-symbol?||{{sl}}||{{b}}|| +Returns {{t}} if the symbol {{sl}} is sealed, {{f}} otherwise.#} + +{#op||sealed-sigil?||{{sl}}||{{b}}|| +Returns {{t}} if the sigil {{sl}} is sealed, {{f}} otherwise.#} + +{#op||sigil-help||{{sl}}||{{help}}|{{null}}|| +Returns the help dictionary for the sigil {{sl}}, if available, {{null}} otherwise. #} + +{#op||sigils||{{none}}||({{s0p}})|| +Returns a list of all sigils defined in the [ROOT](class:kwd) scope.#} + +{#op||source||{{sl}}||{{q}}|| +Display the source code of symbol {{sl}} (if it has been implemented a {{m}} quotation). #} + +{#op||string||{{any}}||{{s}}|| +Converts {{any}} to its string representation.#} + +{#op||symbols||{{none}}||({{s0p}})|| +Returns a list of all symbols defined in the [ROOT](class:kwd) scope.#} + +{#op||symbol-help||{{sl}}||{{help}}|{{null}}|| +Returns the help dictionary for the symbol {{sl}}, if available, {{null}} otherwise. #} + +{#op||tap||{{any}} {{q}}||{{any}}|| +> Performs the following operations: +> +> 1. Removes {{any}} from the stack. +> 2. For each quotation defined in {{q}} (which is a quotation of quotations each requiring one argument and returning one argument): +> 1. Pushes {{any}} back to the stack. +> 2. Dequotes the quotation and saves the result as {{any}}. +> 3. Push the resulting {{any}} back on the stack. +> +> > %sidebar% +> > Example +> > +> > The following program: +> > +> > {1 :a 2 :b 3 :c} ( +> > (dup /a succ succ %a) +> > (dup /b succ %b) +> > ) tap +> > +> > Returns `{3 :a 3 :b 3 :c}`.#} + +{#op||times||{{q}} {{i}}||{{a0p}}|| +Applies the quotation {{q}} {{i}} times.#} + +{#op||to-json||{{any}}||{{s}}|| +Converts {{any}} into a JSON string.#} + +{#op||to-yaml||{{any}}||{{s}}|| +> Converts {{any}} into a YAML string. +> +> > %note% +> > Note +> > +> > At present, only {{m}} dictionaries containing string values are supported.#} + +{#op||try||({{q1}} {{q}}{{2}}{{01}} {{q}}{{3}}{{01}})||{{a0p}}|| +> Evaluates a quotation as a try/catch/finally block. +> +> The must contain the following elements: +> +> 1. A quotation {{q1}} containing the code to be evaluated (_try_ block). +> 1. _(optional)_ A quotation {{q2}} containing the code to execute in case of error (_catch_ block). +> 1. _(optional)_ A quotation {{q3}} containing the code to execute after the code has been evaluated, whether an error occurred or not (_finally_ block). +> +> > %sidebar% +> > Example +> > +> > The following program executed on an empty stack prints the message "Insufficient items on the stack" and pushes 0 on the stack: +> > +> > ( +> > (pop) +> > (format-error puts) +> > (0) +> > ) try #} + +{#op||typealias||{{sl1}} {{sl2}}||{{none}}|| +Creates a type alias {{sl1}} for type expression {{sl2}}.#} + +{#op||unless||{{q1}} {{q2}}||{{a0p}}|| +If {{1}} evaluates to {{f}} then evaluates {{2}}.#} + +{#op||unseal-symbol||{{sl}}||{{none}}|| +Unseals the user-defined symbol {{sl}}, so that it can be re-assigned. #} + +{#op||unseal-sigil||{{sl}}||{{none}}|| +Unseals sigil {{sl}}, so that it can be re-defined (system sigils cannot be unsealed). #} + +{#op||version||{{none}}||{{s}}|| +Returns the current min version number. #} + +{#op||when||{{q1}} {{q2}}||{{a0p}}|| +If {{q1}} evaluates to {{t}} then evaluates {{q2}}.#} + +{#op||while||{{q1}} {{q2}}||{{a0p}}|| +> Executes {{q2}} while {{q1}} evaluates to {{t}}. +> +> > %sidebar% +> > Example +> > +> > The following program prints all natural numbers from 0 to 10: +> > +> > 0 :count +> > (count 10 <=) +> > (count puts succ @count) while #} + +{#op||with||{{q1}} {{q2}}||{{a0p}}|| +Pushes each item of {{q1}} on the stack using the scope of {{q2}} as scope. #}
A docs/reference-logic.md

@@ -0,0 +1,90 @@

+----- +content-type: "page" +title: "logic Module" +----- +{@ _defs_.md || 0 @} + +{#op||&gt;||{{a1}} {{a2}}||{{b}}|| +> Returns {{t}} if {{a1}} is greater than {{a2}}, {{f}} otherwise. +> > %note% +> > Note +> > +> > Only comparisons among two numbers or two strings are supported.#} + +{#op||&gt;=||{{a1}} {{a2}}||{{b}}|| +> Returns {{t}} if {{a1}} is greater than or equal to {{a2}}, {{f}} otherwise. +> > %note% +> > Note +> > +> > Only comparisons among two numbers or two strings are supported.#} + +{#op||&lt;||{{a1}} {{a2}}||{{b}}|| +> Returns {{t}} if {{a1}} is smaller than {{a2}}, {{f}} otherwise. +> > %note% +> > Note +> > +> > Only comparisons among two numbers or two strings are supported.#} + +{#op||&lt;=||{{a1}} {{a2}}||{{b}}|| +> Returns {{t}} if {{a1}} is smaller than or equal to {{a2}}, {{f}} otherwise. +> > %note% +> > Note +> > +> > Only comparisons among two numbers or two strings are supported.#} + +{#op||==||{{a1}} {{a2}}||{{b}}|| +Returns {{t}} if {{a1}} is equal to {{a2}}, {{f}} otherwise. #} + +{#op||!=||{{a1}} {{a2}}||{{b}}|| +Returns {{t}} if {{a1}} is not equal to {{a2}}, {{f}} otherwise. #} + +{#op||and||{{b1}} {{b2}}||{{b3}}|| +Returns {{t}} if {{b1}} is equal to {{b2}}, {{f}} otherwise.#} + +{#op||boolean?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a boolean, {{f}} otherwise. #} + +{#op||dictionary?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a dictionary, {{f}} otherwise. #} + +{#op||expect-all||{{q}}||{{b}}|| +Assuming that {{q}} is a quotation of quotations each evaluating to a boolean value, it pushes {{t}} on the stack if they all evaluate to {{t}}, {{f}} otherwise. + #} + +{#op||expect-any||{{q}}||{{b}}|| +Assuming that {{q}} is a quotation of quotations each evaluating to a boolean value, it pushes {{t}} on the stack if any evaluates to {{t}}, {{f}} otherwise. + #} + +{#op||float?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a float, {{f}} otherwise. #} + +{#op||or||{{b1}} {{b2}}||{{b3}}|| +Returns {{t}} if {{b1}} or {{b2}} is {{t}}, {{f}} otherwise.#} + +{#op||integer?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is an integer, {{f}} otherwise. #} + +{#op||not||{{b1}}||{{b2}}|| +Negates {{b1}}.#} + +{#op||null?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is {{null}}, {{f}} otherwise. #} + +{#op||number?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a number, {{f}} otherwise. #} + +{#op||quotation?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a quotation, {{f}} otherwise. #} + +{#op||string?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a string, {{f}} otherwise. #} + +{#op||stringlike?||{{any}}||{{b}}|| +Returns {{t}} if {{any}} is a string or a quoted symbol, {{f}} otherwise. #} + +{#op||type?||{{any}} {{sl}}||{{b}}|| +Returns {{t}} if the data type of {{any}} satisfies the specified type expression {{sl}}, {{f}} otherwise. #} + +{#op||xor||{{b1}} {{b2}}||{{b3}}|| +Returns {{t}} if {{b1}} and {{b2}} are different, {{f}} otherwise.#} +
A docs/reference-math.md

@@ -0,0 +1,77 @@

+----- +content-type: "page" +title: "math Module" +----- +{@ _defs_.md || 0 @} + +{#op||abs||{{n1}}||{{n2}}|| +Calculates tbe absolute value of {{n1}}. #} + +{#op||acos||{{n1}}||{{n2}}|| +Calculates the arc cosine of {{n1}} (in radians). #} + +{#op||asin||{{n1}}||{{n2}}|| +Calculates the arc sine of {{n1}} (in radians). #} + +{#op||atan||{{n1}}||{{n2}}|| +Calculates the arc tangent of {{n1}} (in radians). #} + +{#op||ceil||{{n}}||{{i}}|| +Returns the smallest integer {{i}} that is not smaller than {{n}}. #} + +{#op||cos||{{n1}}||{{n2}}|| +Calculates the cosine of {{n1}} (in radians). #} + +{#op||cosh||{{n1}}||{{n2}}|| +Calculates the hyperbolic cosine of {{n1}} (in radians). #} + +{#op||d2r||{{n1}}||{{n2}}|| +Converts {{n1}} from degrees to radians. #} + +{#op||e||{{none}}||{{n}}|| +Returns the value of the _e_ constant (Euler's number). #} + +{#op||floor||{{n}}||{{i}}|| +Returns the largest integer {{i}} that is not greater than {{n}}. #} + +{#op||ln||{{n1}}||{{n2}}|| +Calculates the natural logarithm of {{n1}}. #} + +{#op||log10||{{n1}}||{{n2}}|| +Calculates the common logarithm of {{n1}}. #} + +{#op||log2||{{n1}}||{{n2}}|| +Calculates the binary logarithm of {{n1}}. #} + +{#op||pi||{{none}}||{{n}}|| +Returns the value of the &pi; constant. #} + +{#op||pow||{{n1}} {{n2}}||{{n3}}|| +Computes {{n1}} to power raised of {{n2}}.#} + +{#op||r2d||{{n1}}||{{n2}}|| +Converts {{n1}} from radians to degrees. #} + +{#op||round||{{n1}} {{i}}||{{n2}}|| +Rounds {{n1}} to the {{i}}^th decimal place. #} + +{#op||sin||{{n1}}||{{n2}}|| +Calculates the sine of {{n1}} (in radians). #} + +{#op||sinh||{{n1}}||{{n2}}|| +Calculates the hyperbolic sine of {{n1}} (in radians). #} + +{#op||sqrt||{{n1}}||{{n2}}|| +Returns square root of {{n1}}. #} + +{#op||tan||{{n1}}||{{n2}}|| +Calculates the tangent of {{n1}} (in radians). #} + +{#op||tanh||{{n1}}||{{n2}}|| +Calculates the hyperbolic tangent of {{n1}} (in radians). #} + +{#op||tau||{{none}}||{{n}}|| +Returns the value of the &tau; constant (2&pi;). #} + +{#op||trunc||{{n1}}||{{n2}}|| +Truncates {{n}} to the decimal point. #}
A docs/reference-net.md

@@ -0,0 +1,118 @@

+----- +content-type: "page" +title: "net Module" +----- +{@ _defs_.md || 0 @} + +{#op||accept||{{sock1}} {{sock2}}||{{sock1}}|| +Makes {{sock2}} (server) accept a connection from {{sock1}} (client). Returns the client socket {{sock1}} from which it will be possible to receive data from. #} + +{#op||close||{{sock}}||{{none}}|| +Closes a previously-opened socket. #} + +{#op||connect||{{sock}} {{s}} {{i}}||{{sock}}|| +> Connects socket {{sock}} to address {{s}} and port {{i}}. +> +> > %sidebar% +> > Example +> > +> > The following code shows how to send a message to a server running on localhost:7777. The message is passed as the first argument to the program. +> > +> > {} socket "localhost" 7777 connect =cli +> > +> > args 1 get :msg +> > +> > "Sending message \"$1\" to localhost:7777..." (msg) => % puts! +> > +> > cli "$1\n" (msg) => % send +> > +> > "Done." puts! +> > +> > cli close + #} + +{#op||listen||{{d}} {{sock1}}||{{sock2}}|| +> Makes socket {{sock1}} listen to the specified address and port. {{d}} can be empty or contain any of the following properties, used to specify the address and port to listen to respectively. +> +> address +> : The address to listen to (default: **0.0.0.0**). +> port +> : The port to listen to (default: **80**). +> +> > %sidebar% +> > Example +> > +> > The following code shows how to create a simple server that listens on port 7777, prints data received from clients, and exits when it receives the string `exit`: +> > +> > {} socket {"127.0.0.1" :address 7777 :port} listen =srv +> > +> > "Server listening on localhost:7777" puts! +> > +> > {} socket =cli +> > "" :line +> > (line "exit" !=) +> > ( +> > srv cli accept #cli +> > cli recv-line @line +> > "Received: $1" (line) => % puts! +> > ) while +> > +> > "Exiting..." puts! +> > +> > srv close + #} + +{#op||recv||{{sock}} {{i}}||{{s}}|| +Waits to receive {{i}} characters from {{sock}} and returns the resulting data {{s}}.#} + +{#op||recv-line||{{sock}}||{{s}}|| +> Waits to receive a line of data from {{sock}} and returns the resulting data {{s}}. `""` is returned if {{sock}} is disconnected. +> +> > %sidebar% +> > Example +> > +> > The following code shows how to make a simple GET request to <http://httpbin.org/uuid> to receive a random UUID and display its response: +> > +> > +> > {} socket "httpbin.org" 80 connect =cli +> > +> > cli "GET /uuid HTTP/1.1\r\nHost: httpbin.org\r\n\r\n" send +> > +> > cli recv-line puts :line +> > (line "\}" match not) +> > ( +> > cli recv-line puts @line +> > ) while + #} + +{#op||send||{{sock}} {{s}}||{{none}}|| +Sends {{s}} to the connected socket {{sock}}. #} + +{#op||socket||{{d}}||{{sock}}|| +> Opens a new socket. +> +> {{d}} can be empty or contain any of the following properties, used to specify the domain, type and protocol of the socket respectively. +> +> domain +> : The socket domain. It can be set to one of the following values: +> +> * **ipv4** (default): Internet Protocol version 4. +> * **ipv6**: Internet Protocol version 6. +> * **unix**: local Unix file {{no-win}}. +> type +> : The socket type. It can be set to one of the following values: +> +> * **stream** (default): Reliable stream-oriented service or Stream Socket. +> * **dgram**: Datagram service or Datagram Socket. +> * **raw**: Raw protocols atop the network layer. +> * **seqpacket**: Reliable sequenced packet service. +> protocol +> : The socket protocol. It can be set to one of the following values: +> +> * **tcp** (default): Transmission Control Protocol. +> * **udp**: User Datagram Protocol. +> * **ipv4**: Internet Protocol version 4 {{no-win}}. +> * **ipv6**: Internet Protocol version 6 {{no-win}}. +> * **raw**: Raw IP Packets protocol {{no-win}}. +> * **icmp**: Internet Control Message Protocol {{no-win}}. + #}
A docs/reference-num.md

@@ -0,0 +1,89 @@

+----- +content-type: "page" +title: "num Module" +----- +{@ _defs_.md || 0 @} + +{#op||+||{{n1}} {{n2}}||{{n3}}|| +Sums {{n1}} and {{n2}}. #} + +{#op||-||{{n1}} {{n2}}||{{n3}}|| +Subtracts {{n2}} from {{n1}}. #} + +{#op||-inf||{{none}}||{{n}}|| +Returns negative infinity. #} + +{#op||&ast;||{{n1}} {{n2}}||{{n3}}|| +Multiplies {{n1}} by {{n2}}. #} + +{#op||/||{{n1}} {{n2}}||{{n3}}|| +Divides {{n1}} by {{n2}}. #} + +{#op||avg||{{q}}||{{n}}|| +Returns the average of the items of {{q}}. #} + +{#op||bitand||{{i1}} {{i2}}||{{i3}}|| +Computes the bitwise *and* of numbers {{i1}} and {{i2}}.#} + +{#op||bitnot||{{i1}}||{{i2}}|| +Computes the bitwise *complement* of {{i1}}.#} + +{#op||bitor||{{i1}} {{i2}}||{{i3}}|| +Computes the bitwise *or* of numbers {{i1}} and {{i2}}.#} + +{#op||bitxor||{{i1}} {{i2}}||{{i3}}|| +Computes the bitwise *xor* of numbers {{i1}} and {{i2}}.#} + +{#op||even?||{{i}}||{{b}}|| +Returns {{t}} if {{i}} is even, {{f}} otherwise. #} + +{#op||div||{{i1}} {{i2}}||{{i3}}|| +Divides {{i1}} by {{i2}} (integer division). #} + +{#op||inf||{{none}}||{{n}}|| +Returns infinity. #} + +{#op||med||{{q}}||{{n}}|| +Returns the median of the items of {{q}}. #} + +{#op||mod||{{i1}} {{i2}}||{{i3}}|| +Returns the integer module of {{i1}} divided by {{i2}}. #} + +{#op||nan||{{none}}||nan|| +Returns **NaN** (not a number). #} + +{#op||odd?||{{i}}||{{b}}|| +Returns {{t}} if {{i}} is odd, {{f}} otherwise. #} + +{#op||pred||{{i1}}||{{i2}}|| +Returns the predecessor of {{i1}}.#} + +{#op||product||{{q}}||{{i}}|| +Returns the product of all items of {{q}}. {{q}} is a quotation of integers. #} + +{#op||random||{{i1}}||{{i2}}|| +> Returns a random number {{i2}} between 0 and {{i1}}-1. +> +> > %note% +> > Note +> > +> > You must call `randomize` to initialize the random number generator, otherwise the same sequence of numbers will be returned.#} + +{#op||randomize||{{none}}||{{null}|| +Initializes the random number generator using a seed based on the current timestamp. #} + +{#op||range||{{q2}}||{{q2}}|| +Takes a quotation {{q1}} of two or three integers in the form of *start*, *end* and an optional *step* (1 if not specified) and generates the sequence and returns the resulting quotation of integers {{q2}}. #} + +{#op||shl||{{i1}} {{i2}}||{{i3}}|| +Computes the *shift left* operation of {{i1}} and {{i2}}.#} + +{#op||shr||{{i1}} {{i2}}||{{i3}}|| +Computes the *shift right* operation of {{i1}} and {{i2}}.#} + +{#op||succ||{{i1}}||{{i2}}|| +Returns the successor of {{i1}}.#} + +{#op||sum||{{q}}||{{i}}|| +Returns the sum of all items of {{q}}. {{q}} is a quotation of integers. #} +
A docs/reference-seq.md

@@ -0,0 +1,209 @@

+----- +content-type: "page" +title: "seq Module" +----- +{@ _defs_.md || 0 @} + +{#op||all?||{{q1}} {{q2}}||{{b}}|| +Applies predicate {{q2}} to each element of {{q1}} and returns {{t}} if all elements of {{q1}} satisfy predicate {{q2}}, {{f}} otherwise. #} + +{#op||any?||{{q1}} {{q2}}||{{b}}|| +Applies predicate {{q2}} to each element of {{q1}} and returns {{t}} if at least one element of {{q1}} satisfies predicate {{q2}}, {{f}} otherwise. #} + +{#op||append||{{any}} {{q}}||({{a0p}} {{any}})|| +Returns a new quotation containing the contents of {{q}} with {{any}} appended. #} + +{#op||get||{{q}} {{i}}||{{any}}|| +Returns the _n^th_ element of {{q}} (zero-based).#} + +{#op||concat||{{q1}} {{q2}}||{{q3}}|| +Concatenates {{q1}} with {{q2}}. #} + +{#op||difference||{{q1}} {{q2}}||{{q3}}|| +> Calculates the difference {{q3}} of {{q1}} and {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(2)` on the stack: +> > +> > (1 2 "test") ("test" "a" true 1) difference #} + +{#op||drop||{{q1}} {{i}}||{{q2}}|| +Returns a quotation {{q2}} containing the remaining elements after the first _n_ values of the input quotation {{q1}}, or an empty quotation if {{i}} is greater than the length of {{q1}}. #} + +{#op||filter||{{q1}} {{q2}}||{{q3}}|| +> Returns a new quotation {{q3}} containing all elements of {{q1}} that satisfy predicate {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(2 6 8 12)` on the stack: +> > +> > (1 37 34 2 6 8 12 21) +> > (dup 20 < swap even? and) filter #} + +{#op||find||{{q1}} {{q2}}||{{i}}|| +> Returns the index of the first element within {{q1}} that satisfies predicate {{q2}}, or -1 if no element satisfies it. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `3` on the stack: +> > +> > (1 2 4 8 16) +> > (5 >) find #} + +{#op||first||{{q}}||{{any}}|| +Returns the first element of {{q}}. #} + +{#op||flatten||{{q1}}||{{q2}}|| +> Flattens all quotations within {{q1}} and returns the resulting sequence {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(1 2 3 4 5 6 7 8)` on the stack: +> > +> > (1 (2 3 4) 5 (6 7) 8) +> > flatten #} + +{#op||harvest||{{q1}}||{{q2}}|| +> Creates a new quotation {{q2}} containing all elements of {{q1}} except for empty quotations. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(1 2 3)` on the stack: +> > +> > (1 () () () 2 () 3) +> > harvest #} + +{#op||in?||{{q}} {{any}}||{{b}}|| +Returns {{t}} if {{any}} is contained in {{q}}, {{f}} otherwise.#} + +{#op||insert||{{q1}} {{any}} {{i}}||{{q2}}|| +Inserts {{any}} as the value of the _n^th_ element {{q1}} (zero-based), and returns the modified copy of the quotation {{q2}}. #} + +{#op||intersection||{{q1}} {{q2}}||{{q3}}|| +> Calculates the intersection {{q3}} of {{q1}} and {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(1 "test")` on the stack: +> > +> > (1 2 "test") ("test" "a" true 1) intersection #} + +{#op||last||{{q}}||{{any}}|| +Returns the last element of {{q}}. #} + +{#op||map||{{q1}} {{q2}}||{{q3}}|| +Returns a new quotation {{q3}} obtained by applying {{q2}} to each element of {{q1}}.#} + +{#op||map-reduce||{{q1}} {{q2}} {{q3}}||{{i}}|| +> Applies {{q2}} (map) to each element of {{q1}} and then applies {{q3}} (reduce) to each successive element of {{q1}}. {{q1}} must have at least one element. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `35` on the stack: +> > +> > (1 3 5) +> > (dup *) (+) map-reduce #} + +{#op||partition||{{q1}} {{q2}}||{{q3}} {{q4}}|| +> Partitions {{q1}} into two quotations: {{q3}} contains all elements of {{q1}} that satisfy predicate {{q2}}, {{q4}} all the others. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(1 3 5) (2 4 6)` on the stack: +> > +> > (1 2 3 4 5 6) +> > (odd?) partition #} + +{#op||one?||{{q1}} {{q2}}||{{b}}|| +Applies predicate {{q2}} to each element of {{q1}} and returns {{t}} if only one element of {{q1}} satisfies predicate {{q2}}, {{f}} otherwise. #} + +{#op||prepend||{{any}} {{q}}||({{any}} {{a0p}})|| +Returns a new quotation containing the contents of {{q}} with {{any}} prepended. #} + +{#op||quote-map||{{q1}}||{{q2}}|| +Returns a new quotation {{q2}} obtained by quoting each element of {{q1}}.#} + +{#op||reduce||{{q1}} {{any}} {{q2}}||{{i}}|| +> Combines each successive element of {{q1}} using {{q2}}. On the first iteration, the first two inputs processed by {{q2}} are {{any}} and the first element of {{q1}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `120` on the stack: +> > +> > (1 2 3 4 5) +> > 1 (*) reduce #} + +{#op||reject||{{q1}} {{q2}}||{{q3}}|| +Returns a new quotatios {{q3}} including all elements of {{q1}} that do not satisfy predicate {{q2}} (i.e. the opposite of `filter`)#} + +{#op||remove||{{q1}} {{i}}||{{q2}}|| +Returns the _n^th_ element of {{q1}} (zero-based), and returns the modified copy of the quotation {{q2}}.#} + +{#op||rest||{{q1}}||{{q2}}|| +Returns a new quotation {{q2}} containing all elements of {{q1}} quotation except for the first. #} + +{#op||reverse||{{q1}}||{{q2}}|| +Returns a new quotation {{q2}} containing all elements of {{q1}} in reverse order. #} + +{#op||set||{{q1}} {{any}} {{i}}||{{q2}}|| +Sets the value of the _n^th_ element {{q1}} (zero-based) to {{any}}, and returns the modified copy of the quotation {{q2}}. #} + +{#op||shorten||{{q1}} {{i}}||{{q2}}|| +Returns a quotation {{q2}} containing the first _n_ values of the input quotation {{q1}}. #} + +{#op||size||{{q}}||{{i}}|| +Returns the length of {{q}}.#} + +{#op||slice||{{q1}} {{i1}} {{i2}}||{{q2}}|| +> Creates a new quotation {{q2}} obtaining by selecting all elements of {{q1}} between indexes {{i1}} and {{i2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(3 4 5)` on the stack: +> > +> > (1 2 3 4 5 6) +> > 2 4 slice #} + +{#op||sort||{{q1}} {{q2}}||{{q3}}|| +> Sorts all elements of {{q1}} according to predicate {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(1 3 5 7 9 13 16)` on the stack: +> > +> > (1 9 5 13 16 3 7) '> sort #} + +{#op||symmetric-difference||{{q1}} {{q2}}||{{q3}}|| +> Calculates the symmetric difference {{q3}} of {{q1}} and {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(true "a" 2)` on the stack: +> > +> > (1 2 "test") ("test" "a" true 1) symmetric-difference #} + +{#op||take||{{q1}} {{i}}||{{q2}}|| +Returns a quotation {{q2}} containing the first _n_ values of the input quotation {{q1}}, or {{q1}} itself if {{i}} is greater than the length of {{q1}}. #} + +{#op||union||{{q1}} {{q2}}||{{q3}}|| +> Calculates the union {{q3}} of {{q1}} and {{q2}}. +> +> > %sidebar% +> > Example +> > +> > The following program leaves `(true 1 "test" "a" 2)` on the stack: +> > +> > (1 2 "test") ("test" "a" true 1) union #}
A docs/reference-stack.md

@@ -0,0 +1,80 @@

+----- +content-type: "page" +title: "stack Module" +----- +{@ _defs_.md || 0 @} + +{#op||clear-stack||{{any}}||{{none}}|| +Empties the stack.#} + +{#op||cleave||{{a1}} ({{q}}{{0p}})||{{a0p}}|| +> Applies each quotation contained in the first element to the second element {{a1}}. +> > %sidebar% +> > Example +> > +> > The following program leaves 2 on the stack: +> > +> > `(1 2 3) ((sum) (size)) cleave /`#} + +{#op||cons||{{a1}} ({{a0p}})||({{a1}} {{a0p}})|| +Prepends {{a1}} to the quotation on top of the stack.#} + +{#op||dip||{{a1}} ({{a2}})||{{a0p}} {{a1}}|| +Removes the first and second element from the stack, dequotes the first element, and restores the second element.#} + +{#op||dup||{{a1}}||{{a1}} {{a1}}|| +Duplicates the first element on the stack.#} + +{#op||get-stack||{{none}}||({{a0p}})|| +Puts a quotation containing the contents of the stack on the stack.#} + +{#op||id||{{none}}||{{none}}|| +Does nothing.#} + +{#op||keep||{{a1}} {{q}}||{{a0p}} {{a1}}|| +> Applies each quotation contained in the first element to each subsequent corresponding element. +> > %sidebar% +> > Example +> > +> > The following program leaves `5 3` on the stack: +> > +> > `2 3 '+ keep` #} + +{#op||nip||{{a1}} {{a2}}||{{a2}}|| +Removes the second element from the stack.#} + +{#op||over||{{a1}} {{a2}}||{{a1}} {{a2}} {{a1}}|| +Pushes a copy of the second element on top of the stack.#} + +{#op||pick||{{a1}} {{a2}} {{a3}}||{{a1}} {{a2}} {{a3}} {{a1}}|| +Pushes a copy of the third element on top of the stack.#} + +{#op||pop||{{any}}||{{none}}|| +Removes the first element from the stack.#} + +{#op||rolldown||{{a1}} {{a2}} {{a3}}||{{a2}} {{a3}} {{a1}}|| +Moves the third element in first position, the second in third position and the the first in second position.#} + +{#op||rollup||{{a1}} {{a2}} {{a3}}||{{a3}} {{a2}} {{a1}}|| +Moves the third and second element into second and third position and moves the first element into third position.#} + +{#op||set-stack||{{q}}||{{a0p}}|| +Substitute the existing stack with the contents of {{q}}.#} + +{#op||sip||{{a1}} ({{a2}})||{{a0p}} {{a1}}|| +Saves the {{a1}}, dequotes {{a2}}, and restores {{a1}}.#} + +{#op||spread||{{a0p}} ({{q}}{{0p}})||{{a0p}}|| +> Applies each quotation contained in the first element to each subsequent corresponding element. +> > %sidebar% +> > Example +> > +> > The following program leaves `(1 4)` on the stack: +> > +> > `(1 2) (3 4) ((0 get) (1 get)) spread` #} + +{#op||swap||{{a1}} {{a2}}||{{a2}} {{a1}}|| +Swaps the first two elements on the stack. #} + +{#op||swons||({{a0p}}) {{a1}}||({{a1}} {{a0p}})|| +Prepends {{a1}} to the quotation that follows it.#}
A docs/reference-str.md

@@ -0,0 +1,181 @@

+----- +content-type: "page" +title: "str Module" +----- +{@ _defs_.md || 0 @} + +{#alias||%||interpolate#} + +{#alias||=%||apply-interpolate#} + +{#alias||=~||regex#} + +{#op||apply-interpolate||{{s}} {{q}}||{{s}}|| +The same as pushing `apply` and then `interpolate` on the stack.#} + +{#op||capitalize||{{sl}}||{{s}}|| +Returns a copy of {{sl}} with the first character capitalized.#} + +{#op||chr||{{i}}||{{s}}|| +Returns the single character {{s}} obtained by interpreting {{i}} as an ASCII code.#} + +{#op||escape||{{sl}}||{{s}}|| +Returns a copy of {{sl}} with quotes and backslashes escaped with a backslash.#} + +{#op||from-semver||{{s}}||{{d}}|| +Given a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}}, +it pushes a dictionary {{d}} on the stack containing a **major**, **minor**, and **patch** key/value pairs.#} + +{#op||indent||{{sl}} {{i}}||{{s}}|| +Returns {{s}} containing {{sl}} indented with {{i}} spaces.#} + +{#op||indexof||{{s1}} {{s2}}||{{i}}|| +If {{s2}} is contained in {{s1}}, returns the index of the first match or -1 if no match is found. #} + +{#op||interpolate||{{s}} {{q}}||{{s}}|| +> Substitutes the placeholders included in {{s}} with the values in {{q}}. +> > %note% +> > Notes +> > +> > * If {{q}} contains symbols or quotations, they are not interpreted. To do so, call `apply` before interpolating or use `apply-interpolate` instead. +> > * You can use the `$#` placeholder to indicate the next placeholder that has not been already referenced in the string. +> > * You can use named placeholders like `$pwd`, but in this case {{q}} must contain a quotation containing both the placeholder names (odd items) and the values (even items). +> +> > %sidebar% +> > Example +> > +> > The following code (executed in a directory called '/Users/h3rald/Development/min' containing 19 files): +> > +> > `"Directory '$1' includes $2 files." (. (. ls 'file? filter size)) apply interpolate` +> > +> > produces: +> > +> > `"Directory '/Users/h3rald/Development/min' includes 19 files."`#} + +{#op||join||{{q}} {{sl}}||{{s}}|| +Joins the elements of {{q}} using separator {{sl}}, producing {{s}}.#} + +{#op||length||{{sl}}||{{i}}|| +Returns the length of {{sl}}.#} + +{#op||lowercase||{{sl}}||{{s}}|| +Returns a copy of {{sl}} converted to lowercase.#} + +{#op||match?||{{s1}} {{s2}}||{{b}}|| +> Returns {{t}} if {{s2}} matches {{s1}}, {{f}} otherwise. +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}#}. + +{#op||ord||{{s}}||{{i}}|| +Returns the ASCII code {{i}} corresponding to the single character {{s}}.#} + +{#op||parse-url||{{s}}||{{url}}|| +Parses the url {{s}} into its components and stores them into {{url}}.#} + +{#op||prefix||{{sl1}} {{sl2}}||{{s}}|| +Prepends {{sl2}} to {{sl1}}.#} + +{#op||repeat||{{sl}} {{i}}||{{s}}|| +Returns {{s}} containing {{sl}} repeated {{i}} times.#} + +{#op||replace||{{s1}} {{s2}} {{s3}}||{{s4}}|| +> Returns a copy of {{s1}} containing all occurrences of {{s2}} replaced by {{s3}} +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}. +> +> > %sidebar% +> > Example +> > +> > The following: +> > +> > `"This is a stupid test. Is it really a stupid test?" " s[a-z]+" " simple" replace` +> > +> > produces: +> > +> > `"This is a simple test. Is it really a simple test?"`#} + +{#op||replace-apply||{{s1}} {{s2}} {{q}}||{{s3}}|| +> Returns a copy of {{s1}} containing all occurrences of {{s2}} replaced by applying {{q}} to each quotation correponding to each match. +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}. +> +> > %sidebar% +> > Example +> > +> > The following: +> > +> > `":1::2::3::4:" ":(\d):" (=m m 1 get :d "-$#-" (d) =%) replace-apply` +> > +> > produces: +> > +> > `"-1--2--3--4-"` +> > +> > Note that for each match the following quotations (each containing tbe full matcb and the captured matches) are produced as input for the replace quotation: +> > ("-1-" "1") +> > ("-2-" "2") +> > ("-3-" "3") +> > ("-4-" "4") #} + +{#op||search||{{s1}} {{s2}}||{{q}}|| +> Returns a quotation containing the first occurrence of {{s2}} within {{s1}}. Note that: +> +> * The first element of {{q}} is the matching substring. +> * Other elements (if any) contain captured substrings. +> * If no matches are found, the quotation contains empty strings. +> +> > %tip% +> > Tip +> > +> > {{s2}} is a {{pcre}}. +> +> > %sidebar% +> > Example +> > +> > The following: +> > +> > `"192.168.1.1, 127.0.0.1" "[0-9]+\.[0-9]+\.([0-9]+)\.([0-9]+)" search` +> > +> > produces: `("192.168.1.1", "1", "1")`#} + +{#op||search-all||{{s1}} {{s2}}||{{q}}|| +Returns a quotation of quotations (like the one returned by the search operator) containing all occurrences of {{s2}} within {{s1}}. #} + +{#op||semver-inc-major||{{s1}}||{{s2}}|| +Increments the major digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver-inc-minor||{{s1}}||{{s2}}|| +Increments the minor digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver-inc-patch||{{s1}}||{{s2}}|| +Increments the patch digit of the [SemVer](https://semver.org)-compliant string (with no additional labels) {{s1}}. #} + +{#op||semver?||{{s}}||{{b}}|| +Checks whether {{s}} is a [SemVer](https://semver.org)-compliant version or not. #} + +{#op||split||{{sl1}} {{sl2}}||{{q}}|| +Splits {{sl1}} using separator {{sl2}} (a {{pcre}}) and returns the resulting strings within the quotation {{q}}. #} + +{#op||strip||{{sl}}||{{s}}|| +Returns {{s}}, which is set to {{sl}} with leading and trailing spaces removed.#} + +{#op||substr||{{s1}} {{i1}} {{i2}}||{{s2}}|| +Returns a substring {{s2}} obtained by retriving {{i2}} characters starting from index {{i1}} within {{s1}}.#} + +{#op||suffix||{{sl1}} {{sl2}}||{{s}}|| +Appends {{sl2}} to {{sl1}}.#} + +{#op||titleize||{{sl}}||{{s}}|| +Returns a copy of {{sl}} in which the first character of each word is capitalized.#} + +{#op||to-semver||{{d}}||{{s}}|| +Given a a dictionary {{d}} containing a **major**, **minor**, and **patch** key/value pairs , it pushes a basic [SemVer](https://semver.org)-compliant string (with no additional labels) {{s}} on the stack.#} + +{#op||uppercase||{{sl1}}||{{sl2}}|| +Returns a copy of {{sl}} converted to uppercase.#} +
A docs/reference-sys.md

@@ -0,0 +1,116 @@

+----- +content-type: "page" +title: "sys Module" +----- +{@ _defs_.md || 0 @} + +{#sig||$||get-env#} + +{#alias||$||get-env#} + +{#sig||&excl;||system#} + +{#alias||&excl;||system#} + +{#alias||&excl;&excl;||system!#} + +{#sig||&||run#} + +{#alias||&||run#} + +{#op||.||{{none}}||{{s}}|| +Returns the full path to the current directory. #} + +{#op||..||{{none}}||{{s}}|| +Returns the full path to the parent directory. #} + +{#op||chmod||{{sl}} {{i}}||{{none}}|| +> Sets the permissions of file or directory {{sl}} to {{i}}. {{i}} is a three-digit representation of user, group and other permissions. See the [Unix Permissions Calculator](http://permissions-calculator.org/) for examples and conversions. +> +> > %sidebar% +> > Example +> > +> > The following program makes the file **/tmp/test.txt** readable, writable and executable by its owner, and readable and executable by users of the same group and all other users: +> > +> > `/tmp/test.txt 755 chmod`#} + +{#op||cd||{{sl}}||{{none}}|| +Change the current directory to {{sl}}. #} + +{#op||cp||{{sl1}} {{sl2}}||{{none}}|| +Copies the file or directory {{sl1}} to {{sl2}}. #} + +{#op||cpu||{{none}}||{{s}}|| +Returns the host CPU. It can be one of the following strings i386, alpha, powerpc, powerpc64, powerpc64el, sparc, amd64, mips, mipsel, arm, arm64. #} + +{#op||env?||{{sl}}||{{b}}|| +Returns {{t}} if environment variable {{sl}} exists, {{f}} otherwise. #} + +{#op||dir?||{{sl}}||{{b}}|| +Returns {{t}} if the specified path {{sl}} exists and is a directory. #} + +{#op||dirname||{{sl}}||{{s}}|| +Returns the path of the directory containing path {{sl}}.#} + +{#op||exists?||{{sl}}||{{b}}|| +Returns {{t}} if the specified file or directory {{sl}} exists. #} + +{#op||file?||{{sl}}||{{b}}|| +Returns {{t}} if the specified path {{sl}} exists and is a file. #} + +{#op||filename||{{sl}}||{{s}}|| +Returns the file name of path {{sl}}.#} + +{#op||get-env||{{sl}}||{{s}}|| +Returns environment variable {{sl}}. #} + +{#op||hardlink||{{sl1}} {{sl2}}||{{none}}|| +Creates hardlink {{sl2}} for file or directory {{sl1}}. #} + +{#op||ls||{{sl}}||{{q}}|| +Returns a quotation {{q}} containing all children (files and directories) of the directory {{sl}}. #} + +{#op||ls-r||{{sl}}||{{q}}|| +Returns a quotation {{q}} containing all children (files and directories) of the directory {{sl}}, recursively. #} + +{#op||mkdir||{{sl}}||{{none}}|| +Creates the specified directory {{sl}}. #} + +{#op||mv||{{sl1}} {{sl2}}||{{none}}|| +Moves the file or directory {{sl1}} to {{sl2}}. #} + +{#op||os||{{none}}||{{s}}|| +Returns the host operating system. It can be one of the following strings: windows, macosx, linux, netbsd, freebsd, openbsd, solaris, aix, standalone. #} + +{#op||put-env||{{sl1}} {{sl2}}||{{s}}|| +Sets environment variable {{sl2}} to {{sl1}}. #} + +{#op||rm||{{sl}}||{{none}}|| +Deletes the specified file {{sl}}. #} + +{#op||rmdir||{{sl}}||{{none}}|| +Deletes the specified directory {{sl}} and all its subdirectories recursively. #} + +{#op||run||{{sl}}||{{d}}|| +Executes the external command {{sl}} in the current directory without displaying its output. Returns a dictionary containing the command output and return code (in keys **output** and **code** respectively). #} + +{#op||sleep||{{i}}||{{none}}|| +Halts program execution for {{i}} milliseconds.#} + +{#op||symlink||{{sl1}} {{sl2}}||{{none}}|| +Creates symlink {{sl2}} for file or directory {{sl1}}. #} + +{#op||symlink?||{{sl}}||{{b}}|| +Returns {{t}} if the specified path {{sl}} exists and is a symbolic link. #} + +{#op||system||{{sl}}||{{i}}|| +Executes the external command {{sl}} in the current directory and pushes its return code on the stack. #} + +{#op||unzip||{{sl1}} {{sl2}}||{{none}}|| +Decompresses zip file {{sl1}} to directory {{sl2}} (created if not present).#} + +{#op||which||{{sl}}||{{s}}|| +Returns the full path to the directory containing executable {{sl}}, or an empty string if the executable is not found in **$PATH**. #} + +{#op||zip||{{q}} {{sl}}||{{none}}|| +Compresses files included in quotation {{q}} into zip file {{sl}}.#}
A docs/reference-time.md

@@ -0,0 +1,28 @@

+----- +content-type: "page" +title: "time Module" +----- +{@ _defs_.md || 0 @} + +{#op||now||{{none}}||{{flt}}|| +Returns the current time as Unix timestamp with microseconds. #} + +{#op||timestamp||{{none}}||{{i}}|| +Returns the current time as Unix timestamp. #} + +{#op||timeinfo||{{i}}||{{tinfo}}|| +Returns a timeinfo dictionary from timestamp {{i}}. #} + +{#op||to-timestamp||{{tinfo}}||{{i}}|| +Converts the timeinfo dictionary {{tinfo}} to the corresponding Unix timestamp. #} + +{#op||datetime||{{i}}||{{s}}|| +Returns an ISO 8601 string representing the combined date and time in UTC of timestamp {{i}}. #} + +{#op||tformat||{{i}} {{s}}||{{s}}|| +> Formats timestamp {{i}} using string {{s}}. +> +> > %tip% +> > Tip +> > +> > For information on special characters in the format string, see the [format](https://nim-lang.org/docs/times.html#format,TimeInfo,string) nim method. #}
A docs/reference.md

@@ -0,0 +1,183 @@

+----- +content-type: "page" +title: "Reference" +----- +{@ _defs_.md || 0 @} + +min includes a small but powerful standard library organized into the following _modules_: + +{#link-module||lang#} +: Defines the basic language constructs, such as control flow, type conversions, symbol definition and binding, exception handling, etc. +{#link-module||stack#} +: Defines combinators and stack-shufflers like dip, dup, swap, cons, etc. +{#link-module||seq#} +: Defines operators for quotations, like map, filter, reduce, etc. +{#link-module||dict#} +: Defines operators for dictionaries, like dget, ddup, dset, etc. +{#link-module||dstore#} +: Provides support for simple, persistent, in-memory JSON stores. +{#link-module||io#} +: Provides operators for reading and writing files as well as printing to STDOUT and reading from STDIN. +{#link-module||fs#} +: Provides operators for accessing file information and properties. +{#link-module||logic#} +: Provides comparison operators for all min data types and other boolean logic operators. +{#link-module||str#} +: Provides operators to perform operations on strings, use regular expressions, interpolation, etc.. +{#link-module||sys#} +: Provides operators to use as basic shell commands, access environment variables, and execute external commands. +{#link-module||num#} +: Provides operators to perform simple mathematical operations on integer and floating point numbers. +{#link-module||time#} +: Provides a few basic operators to manage dates, times, and timestamps. +{#link-module||crypto#} +: Provides operators to compute hashes (MD4, MD5, SHA1, SHA224, SHA256, SHA384, sha512), base64 encoding/decoding, and AES encryption/decryption. +{#link-module||math#} +: Provides many mathematical operators and constants such as trigonometric functions, square root, logarithms, etc. +{#link-module||net#} +: Provides basic supports for sockets (some features are not supported on Windows systems). +{#link-module||http#} +: Provides operators to perform HTTP requests, download files and create basic HTTP servers. + + +## Notation + +The following notation is used in the signature of all min operators: + +### Types and Values + +{{none}} +: No value. +{{null}} +: null value +{{any}} +: A value of any type. +{{b}} +: A boolean value +{{i}} +: An integer value. +{{flt}} +: A float value. +{{n}} +: A numeric (integer or float) value. +{{s}} +: A string value. +{{sl}} +: A string-like value (string or quoted symbol). +{{q}} +: A quotation (also expressed as parenthesis enclosing other values). +{{d}} +: A dictionary value. +{{help}} +: A help dictionary: + + { + "puts" :name + "symbol" :kind + "a ==>" :signature + "Prints a and a new line to STDOUT." :description + ;help + } +{{url}} +: An URL dictionary: + + { + "http" :scheme + "h3rald" :hostname + "" :port + "" :username + "" :password + "/min" :path + "" :anchor + "" :query + ;url + } +{{tinfo}} +: A timeinfo dictionary: + + { + 2017 :year + 7 :month + 8 :day + 6 :weekday + 188 :yearday + 15 :hour + 16 :minute + 25 :second + true :dst + -3600 :timezone + ;timeinfo + } +{{e}} +: An error dictionary: + + { + "MyError" :error + "An error occurred" :message + "symbol1" :symbol + "dir1/file1.min" :filename + 3 :line + 13 :column + ;error + } +{{sock}} +: A socket dictionary that must be created through the {#link-operator||net||socket#} operator: + + { + "ipv4" :domain + "stream" :type + "tcp" :protocol + ;socket + } +{{dstore}} +: A datastore dictionary that must be created through the {#link-operator||dstore||dsinit#} or {#link-operator||dstore||dsread#} operator: + + { + {} :data + "path/to/file.json" :path + ;datastore + } +{{req}} +: A request dictionary, representing an HTTP request to be performed through the operators exposed by the {#link-module||http#}: + + { + "http://httpbin.org/put" :url + "PUT" :method + "1.1" :version ;optional + "h3rald.com" :hostname ;optional + { + "it-id" :Accept-Language + "httpbin.org" :Host + } :headers ;optional + "test body" :body ;optional + } +{{res}} +: A response dictionary, representing an HTTP response returned by some of the operators exposed by the {#link-module||http#}: + + { + "1.1" :version ;optional + 200 :status ;optional + { + "application/json" :Content-Type + } :headers ;optional + "{\"test\": \"This is a test\"}" :body + } + +### Suffixes + +The following suffixes can be placed at the end of a value or type to indicate ordering or quantities. + +{{1}} +: The first value of the specified type. +{{2}} +: The second value of the specified type. +{{3}} +: The third value of the specified type. +{{4}} +: The fourth value of the specified type. +{{01}} +: Zero or one. +{{0p}} +: Zero or more. +{{1p}} +: One or more
A tasks/guide.mn

@@ -0,0 +1,5 @@

+"tasks/pre.mn" read eval + +( + "hastyscribe --field/version=$# Mn_DeveloperGuide.md" (cfg_version) interpolate run +) (guide__default) lambda