all repos — min @ 3a0530559016543a1dbd3ea531d0127b267fa195

A small but practical concatenative programming language.

site/contents/_includes/_learn-extending.md

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
{@ _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 three options:

* Implement new min modules in min
* Embed min in your [Nim](https://nim-lang.org) program
* Implemet min modules as dynamic libraries in Nim

## 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.

The {#link-operator||lang||module#} (and the **+** sigil) allows you to create a new min module:

```
(
  (dup *)             :pow2

  (dup dup * *)       :pow3

  (dup dup dup * * *) :pow4
  
) +quickpows

```

Save your code to a file (e.g. *quickpows.min*) and you can use it in other nim files using the {#link-operator||lang||load#} operator and the {#link-operator||lang||import#}:

```
'quickpows load
'quickpows import

2 pow3 pow2 puts ;prints 64
```

## 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 packages/min/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/lib) of the min repository, which contains all the min modules included in the standard library.


## Implementing min modules as dynamic libraries

> %warning%
> Warning
> 
> This technique is currently experimental, it has not been tested extensively and it may not even work on Windows.

If you just want to add a new module to min providing functinalities that cannot be built natively with min operators, you can also implement a min module in Nim and compile it to a dynamic library which can be linked dynamically when min is started.

In order to do this, you don't even need to download the whole min source code, you just need to download the [mindyn.nim](https://github.com/h3rald/min/blob/master/mindyn.nim) file and import it in your Nim program. 

The following code shows how to create a simple min module called *dyntest* containing only a single operator *dynplus*, which essentially returns the sum of two numbers:

```
import mindyn

proc dyntest*(i: In) {.dynlib, exportc.} =

  let def = i.define()

  def.symbol("dynplus") do (i: In):
    let vals = i.expect("num", "num")
    let a = vals[0]
    let b = vals[1]
    if a.isInt:
      if b.isInt:
        i.push newVal(a.intVal + b.intVal)
      else:
        i.push newVal(a.intVal.float + b.floatVal)
    else:
      if b.isFloat:
        i.push newVal(a.floatVal + b.floatVal)
      else:
        i.push newVal(a.floatVal + b.intVal.float)

  def.finalize("dyntest")
```

Note that the `mindym.nim` file contains the signatures of all the `proc`s that are commonly used to define min modules, but not their implementation. Such `proc`s will become available at run time when the dynamic library is linked to the min executable.

You can compile the following library by running the following command:

> %min-terminal%
> [$](class:prompt) nim c --app:lib -d:release --noMain dyntest.nim

If you are using [clang](https://clang.llvm.org/) to compile Nim code, you may need to run the following command instead:

> %min-terminal%
> [$](class:prompt) nim c --app:lib -d:release --noMain  -l:"-undefined dynamic\_lookup" dyntest.nim

Now you should have a `libdyntest.so|dyn|dll` file. To make min load it and link it automatically when it starts, just run:

> %min-terminal%
> [$](class:prompt) min --install:libdyntest.dyn

This command will copy the library file to `$HOME/.minlibs/` (`%HOMEPATH%\.minlibs\` on Windows). min looks for dynamic libraries in this folder when it starts.

> %note%
> Notes
> 
> * The dynamic library file must have the same name as the module it defines (*dyntest* in this case).
> * At startup, min links all your installed dynamic libraries but does not import the modules automatically.

If you wish to uninstall the library, run the following command instead:

> %min-terminal%
> [$](class:prompt) min --uninstall:libdyntest.dyn