🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

nock.js

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nock.js

Nock interpreter

latest
Source
npmnpm
Version
1.1.0
Version published
Maintainers
1
Created
Source

nock.js

Nock is a combinator interpreter on nouns. A noun is an atom or a cell. An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.

Nock is the foundational layer of Urbit.

nock.js is a toy interpreter, built for the fun of it.

usage

  • install from npm: npm install nock.js
var nock = require('nock.js')
nock.nock(1, [0, 1])
// => 1
  • or, clone and run
git clone https://github.com/joemfb/nock.js.git
cd nock.js
node example.js
  • run unit tests
npm install
npm test
  • load it in the browser (nock.js is a UMD module):
<script src="./nock.js"></script>
<script>
  nock.nock(1, [0, 1])
  // => 1
</script>

methods

See urbit.org/docs/nock/definition/ for an explanation of the pseudocode reduction rules that make up the Nock spec.

nock
nock(a)          *a
[a b c]          [a [b c]]
*[a [b c] d]     [*[a b c] *[a d]]
*a               *a

nock() recursively applies formulas (tail of its argument) to the subject (head of its argument).

nock.nock(1, [0, 1])
// 1

Nock nouns are always atoms (unsigned integers) or cells (a pair of nouns). The JS analogue to a cell is Array(2), so nock() converts Array arguments into nouns, associating right:

nock.nock([1, 2, 3], [0, 1])
// [1,[2,3]]

The subject can be omitted if the formula doesn't reference it:

nock.nock([1, 1])
// 1

Formulas without a subject are evaluated against [1, 0], which is Hoon null (~).

For convenience in evaluating generated formulas, arguments can be passed as strings (see generating formulas below):

nock.nock("[1 2 3]", "[0 1]")
// [1,[2,3]]
operators

Nock defines four operators:

?[a b]           0
?a               1
+[a b]           +[a b]
+a               1 + a
=[a a]           0
=[a b]           1
=a               =a

/[1 a]           a
/[2 a b]         a
/[3 a b]         b
/[(a + a) b]     /[2 /[a b]]
/[(a + a + 1) b] /[3 /[a b]]
/a               /a
  • wut (?): test for an atom (1) or cell (0)
  • lus (+): increment an atom
  • tis (=): test equality
  • fas (/): resolve a tree address

See urbit.org/docs/hoon/syntax for an explanation of the the method names

Operators are exported in the nock.operators namespace:

nock.operators.fas(2, [5, 9])
// 5

Unlike nock(), operators require both arguments to be present and valid nouns.

formulas

Nock defines 6 primitive formulas:

*[a 0 b]         /[b a]
*[a 1 b]         b
*[a 2 b c]       *[*[a b] *[a c]]
*[a 3 b]         ?*[a b]
*[a 4 b]         +*[a b]
*[a 5 b]         =*[a b]
  • slot (0): resolve a tree address
  • constant (1): return the formula regardless of subject
  • evaluate (2): evaluate the product of second formula against the product of the first
  • cell (3): test if the product is a cell
  • incr (4): increment the product
  • eq (5): test for equality between nouns in the product

And five additional formulas, reducible to the 6 above:

*[a 6 b c d]     *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
*[a 7 b c]       *[a 2 b 1 c]
*[a 8 b c]       *[a 7 [[7 [0 1] b] 0 1] c]
*[a 9 b c]       *[a 7 c 2 [0 1] 0 b]
*[a 10 [b c] d]  *[a 8 c 7 [0 3] d]
*[a 10 b c]      *[a c]
  • ife (6): if/then/else
  • compose (7): evaluate formulas composed left-to-right
  • extend (8): evaluate the second formula against [product of first, subject]
  • invoke (9): construct a core and evaluate one of it's arms against it
  • hint (10): skip first formula, evaluate second

Formulas are exported in the nock.formulas namespace:

nock.nock(2, [8, [[4, [1, 1]], [0, 1]]])
// [2, 2]
nock.formulas.eq(2, [8, [[4, [1, 1]], [0, 1]]])
// 0

As in the case of nock.operators, formulas require both arguments to be present and valid nouns.

Formulas 6-10 are implemented in two ways: directly by the interpreter, and as evaluated macro expansions:

nock.formulas.extend(42, [[4, [0, 1]], [0, 1]])
// [43, 42]
nock.formulas.macroExtend(42, [[4, [0, 1]], [0, 1]])
// [43, 42]

By default, the direct implementations are used. To use the macro expansions instead:

nock.useMacros()
nock.nock(42, [8, [[4, [0, 1]], [0, 1]]])
// [43, 42]

generating formulas

Hoon, the native language of Urbit, is also the language of dojo, the Urbit shell. Hoon expressions are compiled into Nock formulas, which are interpreted.

~novlen-hanweb:dojo> 1
1

Hoon -> Nock compilation is a first class primitive in Hoon (:code or !=):

~novlen-hanweb:dojo> !=(1)
[1 1]

as is the Nock formula itself (:nock or .*):

~novlen-hanweb:dojo> .*(. [1 1])
1
~novlen-hanweb:dojo> .*(. !=(1))
1

As previously noted, nock() can evaluate formulas passed as strings:

nock.nock('[1 1]')
// => 1

For convenience, convert your Nock formula to a string directly in dojo (technically, print your noun to a tape):

~novlen-hanweb:dojo> <!=(1)>
"[1 1]"

generating decrement

Hoon provides a decrement function in it's standard library:

~novlen-hanweb:dojo> (dec 10)
9

The implemention for dec is in a core - compiling it to Nock results in a formula that references that core, not a standalone decrement implementation:

~novlen-hanweb:dojo> !=((dec 10))
[8 [9 24.834.031 0 31] 9 2 [0 4] [7 [0 3] 1 10] 0 11]

There's probably a way to de-reference that core address (24.834.031) and compile the implementation - but I don't know it... Instead, we can evaluate the standard-library decrement implementation directly:

++  dec                                                 ::  decrement
  ~/  %dec
  |=  a/@
  ~|  %decrement-underflow
  ?<  =(0 a)
  =+  b=0
  |-  ^-  @
  ?:  =(a +(b))  b
  $(b +(b))

from urbit.org/docs/hoon/library/1a/#-dec

Converting the linked implementation from tall-form to flat-form (and removing the hint instructions) results in this expression:

|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b))))))))

which we can evaluate:

~novlen-hanweb:dojo> (|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10)
9

compile to Nock (with !=):

~novlen-hanweb:dojo> !=((|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10))
[ 8
  [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1]
  9
  2
  [0 4]
  [7 [0 3] 1 10]
  0
  11
]

evaluate the compiled Nock (with .*):

~novlen-hanweb:dojo> .*(~ !=((|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10)))
9

print to a tape (with <...>):

~novlen-hanweb:dojo> <!=((|=(a/@ ?<(=(0 a) =+(b=0 |-(^-(@ ?:(=(a +(b)) b $(b +(b)))))))) 10))>
"[8 [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1] 9 2 [0 4] [7 [0 3] 1 10] 0 11]"

and, finally, evaluate in nock.js:

nock.nock("[8 [8 [1 0] [1 6 [5 [1 0] 0 6] [0 0] 8 [1 0] 8 [1 6 [5 [0 30] 4 0 6] [0 6] 9 2 [0 2] [4 0 6] 0 7] 9 2 0 1] 0 1] 9 2 [0 4] [7 [0 3] 1 10] 0 11]")
// 9

To get up and and running with an urbit, see github.com/urbit/urbit and urbit.org/docs/using/install/.

Keywords

nock

FAQs

Package last updated on 03 Jun 2016

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts