@whide/tree-lang
v1.5.3
Published
Library module for the Whide editor's tree language
Readme
= Whide Tree Conversion Language Alaric Whitehead [email protected], Supervisor: Dr Bernhard Reus [email protected] 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.
nilmatches the nil valueanymatches any valid tree, and returns it unchangedfalsematches the value 'false' (represented asnil)truematches the value 'true' (represented as<nil.nil>)bool/booleanmatches eithertrueorfalse.intmatches any valid number, and converts it to its numerical representation. E.g: **nilbecomes0**<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 typeAor 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:
nilnodes are shown asnil- Trees are shown as
<A.B.C...>whereA,B, andCare 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, andCare the stringified lsit elements. - Numbers are shown as numbers (i.e. 1 is
1etc) - Booleans are shown as
trueorfalse - 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 nth 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 nils 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)
