@whide/tree-lang v1.5.3
= Whide Tree Conversion Language Alaric Whitehead aw548@sussex.ac.uk, Supervisor: Dr Bernhard Reus bernhard@sussex.ac.uk 1.0, 14 November, 2020 :doctype: article :icons: font //URL aliases: :chai: https://www.npmjs.com/package/chai :electron: https://www.electronjs.org/ :hwhile: https://github.com/alexj136/HWhile :mocha: https://www.npmjs.com/package/mocha :whide: https://github.com/sonrad10/Whide :typescript: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html
This repository holds the tree conversion language used by the link:{whide}Whide IDE. The purpose of this language is to validate the formats of link:{hwhile}WHILE binary trees, and to convert them to a more human-friendly representation.
This language was loosely inspired by link:{typescript}TypeScript's type declaration syntax;
namely by its union operator (|
), its any
type, and its support of literal types.
NOTE: The term "type" is used in this document to refer to any valid atom or structure in the expression language.
#language-description == Language description
Formally, the language's syntax can be expressed as the following context-free grammar:
source
ROOT = <ROOT.ROOT> //Binary tree | ROOT[] //List of type ROOT | FIX_INT //List of a fixed structure | (ROOT) //Parentheses | ROOT|ROOT //Accept any of these types | ATOM //Accept atomic values | NAT //Accept all the natural numbers
//Fixed structure list FIX_LST = [] //Empty list | FIX_INT //Populated list
FIX_INT = ROOT,FIX_INT //Comma separated list of types | ROOT //Final list element | ... //Ignore any further elements
//Built-in atomic types
ATOM = any //Accept any type
| bool //Accept either 'true' or 'false'
| boolean //Same as 'bool'
| false //Accept the value 'false' ('nil')
| int //Integer
| nil //The value nil
exactly
| true //Accept the value 'true' ('<nil.nil>')
//The natural numbers
NAT = 0|1|2|...
=== Informal Description
==== Atoms
The language contains several built-in atomic types. See <> for a description of the tree forms of these types.
nil
matches the nil valueany
matches any valid tree, and returns it unchangedfalse
matches the value 'false' (represented asnil
)true
matches the value 'true' (represented as<nil.nil>
)bool
/boolean
matches eithertrue
orfalse
.int
matches any valid number, and converts it to its numerical representation. E.g:nil
becomes0
<nil.nil>
becomes1
**<nil.<nil.nil>>
becomes2
- Number literals (0, 1, 2, ...) match exactly that number
==== Alternative types
Alternative types can be easily specified using the |
operator;
the string A|B
first attempts to use type A
, then type B
.
For example int|any
first attempts to convert the tree to an integer, but returns the tree unchanged if it is invalid.
==== Binary trees
Binary trees are represented in the form <L.R>
where L
is the type of the left-hand node, and R
is the type of the right-hand node.
For example, <int.nil>
matches any tree with an integer as the left child.
==== Lists
There are two supported types of list in the language; generic and fixed lists.
Generic lists (A[]
or (A|B)[]
) represent arbitrary length lists of a fixed type.
For example:
A[]
represents a list where each element is of typeA
(A|B)[]
represents a list where each element is of typeA
or typeB
NOTE: []
binds more tightly than |
so A|B[]
would be equivalent to A|(B[])
.
Fixed structure lists match against lists which have a fixed length and each element has a known type:
[]
represents the empty list.
[A]
represents a list with exactly one element of type A
.
[A,B,C]
represents a list with exactly 3 elements of type A
, B
, and C
respectively.
[A,B,...]
represents a list with 2 or more elements, the first two of types A
and B
respectively, and any further elements of any type.
NOTE: Any type can be turned into a generic list by adding []
to the end; int[][]
would match a list of lists of integers, and <int.int>[]
would match a list of trees of integers.
=== Error handling
If the provided tree does not match the conversion string, the converter returns the original tree in place of the mismatched token, with an error message describing the issue.
For example, the tree <<nil.nil>.nil>
with conversion string int
would return the tree <<nil.nil>.nil>
with the error "not a valid number".
Similarly, conversion string <any.nil>
acting on tree nil
would return nil
with the error message "expected a tree".
If the error is non-recoverable (e.g. a syntax error) the converter throws an exception.
== Examples
cols="25a,~a" !==== |Conversion String | Input tree
| int
| * nil
-> 0
+<nil.nil>+
-> 1+<nil.<nil.nil>>+
-> 2
| any
| * nil
-> nil
+<nil.nil>+
->+<nil.nil>+
+<<nil.nil>.<nil.nil>>+
->+<<nil.nil>.<nil.nil>>+
| <int.any>
| * nil
-> Invalid
+<nil.nil>+
->+<0.nil>+
+<<nil.nil>.<nil.nil>>+
->+<1.<nil.nil>>+
| int[]
| * nil
-> []
+<nil.nil>+
->+[0]+
+<<nil.nil>.<nil.nil>>+
->+[1,0]+
| int[][]
| * nil
-> []
+<nil.nil>+
->+[]+
+<<nil.nil>.<nil.nil>>+
->+[[0],[]]+
| bool
| * nil
-> false
+<nil.nil>+
->+true+
!====
== Stringify
In addition to the conversion language, this module also provides a stringify
method.
This accepts a converted binary tree (the resulting type of the conversion) and converts it to a string representation.
The format used by this method is similar to that used in this documentation:
nil
nodes are shown asnil
- Trees are shown as
<A.B.C...>
whereA
,B
, andC
are the stringified representations of each of the child nodes. In most cases there will be only 2 children. - Lists are shown as
[A,B,C,...]
whereA
,B
, andC
are the stringified lsit elements. - Numbers are shown as numbers (i.e. 1 is
1
etc) - Booleans are shown as
true
orfalse
- Other strings are shown as-is, wrapped in "double quotes"
#data-structures === Data Structures
Data structures are based on the types provided by Dr Bernhard Reus in his textbook link:Limits of Computation.
Lists are represented by a tree of depth N, where each "left" node at depth n
represents the n
th element in the list, and the final right-node is null, acting as a terminator.
//TODO: Represent a list in tree form in the conversion language
Each integer n
is represented as a list of nil
s of depth n
.
//TODO: Represent an integer in tree form in the conversion language
#io-types === Tree Input/Output Types
The language accepts trees represented as objects in the following format.
Nodes can be null
(representing nil
) or point to left and right nodes.
source
type BinaryTree = { left: BinaryTree, right: BinaryTree,
}|null;
The conversion produces a tree of type ConvertedBinaryTree
.
This tree is represented differently to the input type due to having a more flexible format.
Every node may contain the following information:
- A list of children (each a
ConvertedBinaryTree
)
+ There may be more than 2 children to any given node
- A string value describing the node
- A boolean describing whether the node represents a list rather than a tree
- A string containing an error message for the current node
source
export type ConvertedBinaryTree = { children?: ConvertedBinaryTree[], value?: string|number|null, list?: boolean, error?: string,
};
== Future features
- counters
- strict mode (error on invalid nodes)