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