git @ Cat's Eye Technologies Tamsin / master doc / System_Module.markdown
master

Tree @master (Download .tar.gz)

System_Module.markdown @masterview rendered · raw · history · blame

System Module
-------------

    -> Tests for functionality "Intepret Tamsin program"

The module `$` contains a number of built-in productions which would not
be possible or practical to implement in Tamsin.  See Appendix C for a list.

In fact, we have been using the `$` module already!  But our usage of it
has been hidden under some syntactic sugar.  For example, `"k"` is actually...

    | main = $:expect(k).
    + k
    = k

    | main = $:expect(k).
    + l
    ? expected 'k' but found 'l'

The section about aliases needs to be written too.

Here's `$:alnum`, which only consumes tokens where the first character is
alphanumeric.

    | main = "(" & {$:alnum → A} & ")" & A.
    + (abc123deefghi459876jklmnopqRSTUVXYZ0)
    = 0

    | main = "(" & {$:alnum → A} & ")" & A.
    + (abc123deefghi459876!jklmnopqRSTUVXYZ0)
    ? expected ')' but found '!'

Here's `$:upper`, which only consumes tokens where the first character is
uppercase alphabetic.

    | main = "(" & {$:upper → A} & ")" & A.
    + (ABCDEFGHIJKLMNOPQRSTUVWXYZ)
    = Z

    | main = "(" & {$:upper → A} & ")" & A.
    + (ABCDEFGHIJKLMNoPQRSTUVWXYZ)
    ? expected ')' but found 'o'

Here's `$:startswith`, which only consumes tokens which start with
the given term.  (For a single-character scanner this isn't very
impressive.)

    | main = "(" & {$:startswith('A') → A} & ")" & A.
    + (AAAA)
    = A

    | main = "(" & {$:startswith('A') → A} & ")" & A.
    + (AAAABAAA)
    ? expected ')' but found 'B'

Here's `$:mkterm`, which takes an atom and a list and creates a constructor.

    | main = $:mkterm(atom, list(a, list(b, list(c, nil)))).
    = atom(a, b, c)

Here's `$:unquote`, which takes three terms, X, L and R, where L and R
must be atoms.  If X begins with L and ends with R then the contents
in-between will be returned as an atom.  Otherwise fails.

    | main = $:unquote('"hello"', '"', '"').
    = hello

    | main = $:unquote('(hello)', '(', ')').
    = hello

    | main = $:unquote('(hello)', '(', '"').
    ? term '(hello)' is not quoted with '(' and '"'

    | main = $:unquote('(hello)', '[', ')').
    ? term '(hello)' is not quoted with '[' and ')'

The quotes can be Unicode characters.

    | main = $:unquote('“hello”', '“', '”').
    = hello

The quotes can be multiple characters.

    | main = $:unquote('%-hello-%', '%-', '-%').
    = hello

The quotes can even be empty strings.

    | main = $:unquote('hello', '', '').
    = hello

Here's `$:equal`, which takes two terms, L and R.  If L and R are equal,
succeeds and returns that term which they both are.  Otherwise fails.

Two atoms are equal if their texts are identical.

    | main = $:equal('hi', 'hi').
    = hi

    | main = $:equal('hi', 'lo').
    ? term 'hi' does not equal 'lo'

Two constructors are equal if their texts are identical, they have the
same number of subterms, and all of their corresponding subterms are equal.

    | main = $:equal(hi(there), hi(there)).
    = hi(there)

    | main = $:equal(hi(there), lo(there)).
    ? term 'hi(there)' does not equal 'lo(there)'

    | main = $:equal(hi(there), hi(here)).
    ? term 'hi(there)' does not equal 'hi(here)'

    | main = $:equal(hi(there), hi(there, there)).
    ? term 'hi(there)' does not equal 'hi(there, there)'

Here's `$:emit`, which takes an atom and outputs it.  Unlike `print`, which
is meant for debugging, `$:emit` does not append a newline, and is 8-bit-clean.

    | main = $:emit('`') & $:emit('wo') & ''.
    = `wo

    -> Tests for functionality "Intepret Tamsin program (pre- & post-processed)"

`$:emit` is 8-bit-clean: if the atom contains unprintable characters,
`$:emit` does not try to make them readable by UTF-8 or any other encoding.
(`print` may or may not do this, depending on the implementation.)

    | main = $:emit('\x00\x01\x02\xfd\xfe\xff') & ''.
    = 000102fdfeff0a

    -> Tests for functionality "Intepret Tamsin program"

Here's `$:repr`, which takes a term and results in an atom which is the
result of reprifying that term (see section on Terms, above.)

    | main = $:repr(hello).
    = hello

    | main = $:repr('016fo_oZZ').
    = 016fo_oZZ

    | main = $:repr('016fo$oZZ').
    = '016fo$oZZ'

    | main = $:repr('').
    = ''

    | main = $:repr(' ').
    = ' '

    | main = $:repr('016\n016').
    = '016\x0a016'

    | main = $:repr(hello(there, world)).
    = hello(there, world)

    | main = V ← '♡' & $:repr('□'(there, V)).
    = '\xe2\x96\xa1'(there, '\xe2\x99\xa1')

    | main = $:repr(a(b(c('qu\'are\\')))).
    = a(b(c('qu\'are\\')))

    | main = $:repr('\x99').
    = '\x99'

Here's `$:reverse`, which takes a term E, and a term of the form
`X(a, X(b, ... X(z, E)) ... )`, and returns a term of the form
`X(z, X(y, ... X(a, E)) ... )`.  The constructor tag X is often `cons`
or `pair` or `list` and E is often `nil`.

    | main = $:reverse(list(a, list(b, list(c, nil))), nil).
    = list(c, list(b, list(a, nil)))

E need not be an atom.

    | main = $:reverse(list(a, list(b, list(c, hello(world)))), hello(world)).
    = list(c, list(b, list(a, hello(world))))

If the tail of the list isn't E, an error occurs.

    | main = $:reverse(list(a, list(b, list(c, hello(world)))), nil).
    ? malformed list

If some list constructor doesn't have two children, an error occurs.

    | main = $:reverse(list(a, list(b, list(nil))), nil).
    ? malformed list

The constructor tag can be anything.

    | main = $:reverse(foo(a, foo(b, foo(c, nil))), nil).
    = foo(c, foo(b, foo(a, nil)))

But if there is a different constructor somewhere in the list, well,

    | main = $:reverse(foo(a, fooz(b, foo(c, nil))), nil).
    ? malformed list

You can reverse an empty list.

    | main = $:reverse(nil, nil).
    = nil

But of course,

    | main = $:reverse(nil, zilch).
    ? malformed list

This is a shallow reverse.  Embedded lists are not reversed.

    | main = $:reverse(list(a, list(list(1, list(2, nil)), list(c, nil))), nil).
    = list(c, list(list(1, list(2, nil)), list(a, nil)))

Here's `$:gensym`.

    | main = $:gensym('foo').
    = foo1

    | main = $:gensym('foo') → F & $:gensym('foo') → G & $:equal(F, G).
    ? 'foo1' does not equal 'foo2'

Here's `$:hexbyte`.

    | main = $:hexbyte('5', '0').
    = P

    | main = $:hexbyte('f', 'f') → C & $:repr(C).
    = '\xff'

Here's `$:format_octal`, which makes me feel ill.

    | main = $:format_octal('P').
    = 120

    | main = $:format_octal('\xff').
    = 377

There are never any leading zeroes.

    | main = $:format_octal('\n').
    = 12

It works on the first byte of the string only.

    | main = $:format_octal('«').
    = 302

Here's `$:length`, which returns an atom representing the length, in bytes,
of the given term (flattened.)  Note that this is an atom, not an integer,
because Tamsin doesn't even have integers.

    | main = $:length(abcde).
    = 5

    | main = $:length('').
    = 0

    | main = $:length('♥').
    = 3

    | main = $:length(a(   b  ,  c  )).
    = 7