diff --git a/examples/.idea/ant.xml b/examples/.idea/ant.xml new file mode 100644 index 00000000000..2581ca3fe84 --- /dev/null +++ b/examples/.idea/ant.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/.idea/compiler.xml b/examples/.idea/compiler.xml new file mode 100644 index 00000000000..97c9ca5c8b0 --- /dev/null +++ b/examples/.idea/compiler.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/examples/.idea/copyright/profiles_settings.xml b/examples/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000000..3572571ad83 --- /dev/null +++ b/examples/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/examples/.idea/encodings.xml b/examples/.idea/encodings.xml new file mode 100644 index 00000000000..e206d70d859 --- /dev/null +++ b/examples/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/examples/.idea/misc.xml b/examples/.idea/misc.xml new file mode 100644 index 00000000000..778bf31bc07 --- /dev/null +++ b/examples/.idea/misc.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/examples/.idea/modules.xml b/examples/.idea/modules.xml new file mode 100644 index 00000000000..4b3b58ae48d --- /dev/null +++ b/examples/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/examples/.idea/projectCodeStyle.xml b/examples/.idea/projectCodeStyle.xml new file mode 100644 index 00000000000..8b60e241aaf --- /dev/null +++ b/examples/.idea/projectCodeStyle.xml @@ -0,0 +1,37 @@ + + + + + + + diff --git a/examples/.idea/uiDesigner.xml b/examples/.idea/uiDesigner.xml new file mode 100644 index 00000000000..3b000203088 --- /dev/null +++ b/examples/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/.idea/vcs.xml b/examples/.idea/vcs.xml new file mode 100644 index 00000000000..275077f8255 --- /dev/null +++ b/examples/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/examples.iml b/examples/examples.iml new file mode 100644 index 00000000000..26a958a9c8a --- /dev/null +++ b/examples/examples.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/examples/src/BinaryTree.jetl b/examples/src/BinaryTree.jetl new file mode 100644 index 00000000000..8327a968db0 --- /dev/null +++ b/examples/src/BinaryTree.jetl @@ -0,0 +1,195 @@ +class BinaryTree : IMutableSet { + private class TreeNode( + var value : T, var parent : TreeNode + ) { + var left : TreeNode + var right : TreeNode + + } + + private val compare : MatchableComparison + private var root : TreeNode + private var version = 0 + + override var size : Int { get; private set; } + + this(compare : Comparison) { + this.compare = asMatchableComparison(comparison) + } + + this() : this(naturalOrder) { + } + + private extension [operator] fun T.compareTo(other : T) : Int = compare(this, other) + + override fun contains(item : T) : Boolean { + return contains(root, item) + + fun contains(node : TreeNode, item : T) : Boolean { + if (node == null) return false + compare(item, node.value) match { + case EQ => true + case LS => contains(node.left, item) + case GT => contains(node.right, item) + } + } + } + + override fun add(item : T) : Boolean { + if (add(ref root, null)) { + size++ + version++ + return true + } + return false + + // In principle, this has access to item anyway, but then it's unreachable code + // BAD: the naive implementation of ref will create H(T) ref objects, but can be optimized to create only one + fun add(ref node : TreeNode, parent : TreeNode) : Boolean { + if (node == null) { + node = TreeNode(item, parent) + return true + } + compare(item, node.value) match { + case EQ => false + case LS => add(ref node.left, node) + case GT => add(ref node.right, node) + } + } + + // In principle, this has access to item anyway + fun addNoRef(node : TreeNode) : Boolean { + if (node == null) { + root = TreeNode(item, null) + return true + } + compare(item, node.value) match { + case EQ => return false + case LS => + if (node.left == null) { + node.left = TreeNode(item, node) + return true + } else return add(node.left) + case GT => + if (node.right == null) { + node.right = TreeNode(item, node) + return true + } else return add(node.right) + } + } + } + + override fun remove(item : T) : Boolean { + val toRemove = find(root, item) + if (toRemove == null) return false + remove(toRemove) + size-- + version++ + return true + + fun find(node : TreeNode) : TreeNode { + if (node == null) return null + compare(item, node.value) match { + case EQ => node + case LS => find(node.left) + case GT => find(node.right) + } + } + } + + private fun remove(node : TreeNode) { + node match { + case TreeNode(null, null) => replace(node, null) + case TreeNode(null, right) => replace(node, right) + case TreeNode(left, null) => replace(node, left) + case TreeNode(left, right) => { + val min = min(node.right) + node.value = min.value + remove(min) + } + } + + fun replace(node : TreeNode, replace : TreeNode) { + if (node == root) { + root = replace + return + } + if (node.parent.left == node) { + node.parent.left = replace + } else if (node.parent.right == node) { + node.parent.right = replace + } else Assert(false) + } + } + + // Relies on tail-recursion optimization + private fun min(node : TreeNode) { + if (node.left == null) node else min(node.left) + } + + override fun iterator() : IIterator = mutableIterator() + + override fun mutableIterator() : IMutableIterator = new IMutableIterator() { + val version = BinaryTree.this.version + val down = Stack() + val up = Stack() + var lastNode : TreeNode + + this() { + if (root != null) + down.push(root) + } + + override fun next() : T { + if (!hasNext) + throw NoMoreElementsException() + checkVersion() + + lastNode = nextNode() + return lastNode.value + } + + private fun nextNode() : TreeNode { + while (true) { + if (!down.isEmpty) { + val curNode = down.pop() + if (curNode.left != null) { + up.push(curNode) + down.push(curNode.left) + } else { + if (curNode.right != null) { + down.push(curNode.right) + } + return curNode; + } + } else { + val curNode = up.pop() + if (curNode.right != null) { + down.push(curNode.right) + } + return curNode + } + } + } + + override val hasNext : Boolean { + get() = !down.isEmpty || !up.isEmpty + } + + override fun remove() { + checkVersion() + if (lastNode == null) + throw IterationException("Nothing to remove") + remove(lastNode) + version++ + BinaryTree.this.version = version + } + + private fun checkVersion() { + if (version != BinaryTree.this.version) { + throw ConcurrentModificationException() + } + } + } + +} \ No newline at end of file diff --git a/examples/src/Color.jetl b/examples/src/Color.jetl new file mode 100644 index 00000000000..2c2c4278ff1 --- /dev/null +++ b/examples/src/Color.jetl @@ -0,0 +1,5 @@ +enum class Color(val r, g, b : Int) { + RED : Color(255, 0, 0) + GREEN : Color(0, 255, 0) + BLUE : Color(0, 0, 255) +} \ No newline at end of file diff --git a/examples/src/Graph.jetl b/examples/src/Graph.jetl new file mode 100644 index 00000000000..4ed01564310 --- /dev/null +++ b/examples/src/Graph.jetl @@ -0,0 +1,60 @@ +sealed class Vertex(val data : V) + +sealed class Edge(val from : V, val data : E, val to : V) + +class Graph { + + private val mutableEdges = new ArrayList>() // type is ArrayList, but I want IMutableList +/* options: + private val edges : IMutableList> = new ArrayList>() + private val edges : IMutableList> = new ArrayList() // not an erasure, but a request to infer parameters +*/ + + private val mutableVertices = new HashSet>() + + val edges : IList> = mutableEdges; + val vertices : ISet> = mutableVertices; + + fun addEdge(from : V, data : E, to : V) { + mutableEdges.add(new Edge(from, data, to)) // constructor parameters are inferred + } + fun addVertex(v : V) { + mutableEdges.add(new Edge(from, data, to)) // constructor parameters are inferred + } + + fun neighbours(v : Vertex) = edges.filter{it.from == v}.map{it.to} // type is IIterable> + + fun dfs(handler : {V => ()}) { + val visited = new HashSet>() + vertices.foreach{dfs(it, visited, handler)} + + fun dfs(current : Vertex, visited : ISet>, handler : {V => ()}) { + if (!visited.add(current)) + return + handler(current) + neighbours(current).foreach{dfs(it, visited, handler)} + } + } + + public fun traverse(pending : IPushPop>, visited : ISet>, handler : {V => ()}) { + vertices.foreach { + if (!visited.add(it)) + continue + pending.push(it) + while (!pending.isEmpty) { + val current = pending.pop() + handler(current); + neighbours(current).foreach { n => + if (visited.add(n)) { + pending.push(n) + } + } + /* alternative + pending->push(neighbours(current).filter{n => !visited[n])}) + // -> means that if push(x : T) and actual parameter y is IIterable, this compiles into + y.foreach{ n => push(n) } + */ + } + } + } +} diff --git a/examples/src/IPushPop.jetl b/examples/src/IPushPop.jetl new file mode 100644 index 00000000000..9065c1e0d10 --- /dev/null +++ b/examples/src/IPushPop.jetl @@ -0,0 +1,5 @@ +interface class IPushPop { + val isEmpty : Boolean + fun push(item : T) + fun pop() : T +} \ No newline at end of file diff --git a/examples/src/Queue.jetl b/examples/src/Queue.jetl new file mode 100644 index 00000000000..bbbbe1dc8c2 --- /dev/null +++ b/examples/src/Queue.jetl @@ -0,0 +1,33 @@ +sealed class Queue : IPushPop { + private class Item(val data : T, var next : Item) + + private var head : Item = null + private var tail : Item = null + + override fun push(item : T) { + val i = new Item(item) + if (tail == null) { + head = i + tail = head + } else { + tail.next = i + tail = i + } + } + + override fun pop() = + if (head == null) + throw new UnderflowException() + else { + val result = head.data + head = head.next + if (head == null) + tail = null + result + } + + override val isEmpty { + get() = head == null + } + +} \ No newline at end of file diff --git a/examples/src/Stack.jetl b/examples/src/Stack.jetl new file mode 100644 index 00000000000..2e0803f543a --- /dev/null +++ b/examples/src/Stack.jetl @@ -0,0 +1,13 @@ +sealed class Stack : IPushPop { + private val data = new ArrayList(); + + override fun push(item : T) { + data.add(item) // Problem: I would like to write push(...) = data.add(...), but the types do not match + } + + override fun pop() = data.removeLast() + + override val isEmpty { // TODO: This is UGLY :( + get() = data.isEmpty + } +} \ No newline at end of file diff --git a/examples/src/UnionFind.jetl b/examples/src/UnionFind.jetl new file mode 100644 index 00000000000..a817d3383fe --- /dev/null +++ b/examples/src/UnionFind.jetl @@ -0,0 +1,34 @@ +class UnionFind { + private val data = IMutableList() + + fun add() : Int { + val size = data.size + data.add(size) + size + } + + private fun parent(x : Int) : Int { + val p = data[x]; + if (p == x) { + return x; + } + val result = parent(p); + data[x] = result; + } + + fun union(a : Int, b : Int) { + val pa = parent(a) + val pb = parent(b) + if (pa != pb) { + if (Random.nextInt().isOdd) { + data[pb] = pa + } else { + data[pa] = pb + } + } + } +} + +extension val Int.isOdd : Boolean { + get() = this % 2 != 0 +} \ No newline at end of file diff --git a/examples/src/collections/ArrayList.jetl b/examples/src/collections/ArrayList.jetl new file mode 100644 index 00000000000..ef3575ecba9 --- /dev/null +++ b/examples/src/collections/ArrayList.jetl @@ -0,0 +1,77 @@ +class ArrayList : IMutableList { + private var data = MutableArray(10) + private var used = 0 + private var version = 0 + + override fun iterator() : IIterator = mutableIterator() + + override fun mutableIterator() : IMutableIterator = new IMutableIterator() { // T is inferred + private val index = 0 + private var myVersion = version + + private fun checkVersion() { + if (version != myVersion) + throw new ConcurrentModificationException() + } + + override fun next() { + checkVersion() + if (hasNext) + throw new NoMoreElementsException() + data[index++] + } + + override val hasNext { + get() = index < used + } + + override fun remove() { + checkVersion() + val result = ArrayList.this.remove(index - 1) + myVersion = version + result + } + } + + override fun get(index : Int) { + checkIndex(index) + data[index] + } + + private fun checkIndex(index : Int) { + if (index > used) + throw new IndexOutOfBoundsException(index) + } + + override val isEmpty { + get() = used == 0 + } + + override val size { + get() = used + } + + override fun set(index : Int, value : T) { + checkIndex(index) + var result = data[index] + data[index] = value + result + } + + override fun add(index : Int, value : T) { + ensureSize(used + 1) + if (index == used) { + data[used++] = value + } else if (index < used) { + for (i in used-1..index) // backwards, special operator... Need to optimize this to be a real indexed loop + data[i + 1] = data[i] + data[index] = value + used++ + } else throw IndexOutOfBoundsException(index) + } + + override fun remove(index : Int) { + for (i in index..used-1) + data[i] = data[i + 1] + } +} \ No newline at end of file diff --git a/examples/src/collections/IIterable.jetl b/examples/src/collections/IIterable.jetl new file mode 100644 index 00000000000..2ef19c0caed --- /dev/null +++ b/examples/src/collections/IIterable.jetl @@ -0,0 +1,3 @@ +interface class IIterable { + fun iterator() : IIterator +} diff --git a/examples/src/collections/IIterator.jetl b/examples/src/collections/IIterator.jetl new file mode 100644 index 00000000000..7717e94062f --- /dev/null +++ b/examples/src/collections/IIterator.jetl @@ -0,0 +1,4 @@ +interface class IIterator { + fun next() : T + val hasNext : Boolean +} diff --git a/examples/src/collections/IList.jetl b/examples/src/collections/IList.jetl new file mode 100644 index 00000000000..9e03010ae58 --- /dev/null +++ b/examples/src/collections/IList.jetl @@ -0,0 +1,4 @@ +interface class IList : IIterable, ISizable { + [operator] fun get(index : Int) : T + val isEmpty : Boolean +} \ No newline at end of file diff --git a/examples/src/collections/IMutableIterable.jetl b/examples/src/collections/IMutableIterable.jetl new file mode 100644 index 00000000000..a60bf71c95c --- /dev/null +++ b/examples/src/collections/IMutableIterable.jetl @@ -0,0 +1,3 @@ +interface class IMutableIterable : IIterable { + fun mutableIterator() : IMutableIterator +} \ No newline at end of file diff --git a/examples/src/collections/IMutableIterator.jetl b/examples/src/collections/IMutableIterator.jetl new file mode 100644 index 00000000000..c00e01c3eaa --- /dev/null +++ b/examples/src/collections/IMutableIterator.jetl @@ -0,0 +1,3 @@ +interface class IMutableIterator : IIterator { + fun remove() : T +} \ No newline at end of file diff --git a/examples/src/collections/IMutableList.jetl b/examples/src/collections/IMutableList.jetl new file mode 100644 index 00000000000..2b308d8ca86 --- /dev/null +++ b/examples/src/collections/IMutableList.jetl @@ -0,0 +1,6 @@ +interface class IMutableList : IList, IMutableIterable { + fun set(index : Int, value : T) : T + fun add(index : Int, value : T) + fun remove(index : Int) : T + fun mutableIterator() : IMutableIterator +} \ No newline at end of file diff --git a/examples/src/collections/IMutableSet.jetl b/examples/src/collections/IMutableSet.jetl new file mode 100644 index 00000000000..aa4edbee412 --- /dev/null +++ b/examples/src/collections/IMutableSet.jetl @@ -0,0 +1,4 @@ +interface class IMutableSet : ISet, IMutableIterable { + fun add(item : T) : Boolean + fun remove(item : T) : Boolean +} \ No newline at end of file diff --git a/examples/src/collections/ISet.jetl b/examples/src/collections/ISet.jetl new file mode 100644 index 00000000000..8c32364dcf9 --- /dev/null +++ b/examples/src/collections/ISet.jetl @@ -0,0 +1,3 @@ +interface class ISet : IIterable, ISized { + fun contains(item : T) : Boolean +} diff --git a/examples/src/collections/ISized.jetl b/examples/src/collections/ISized.jetl new file mode 100644 index 00000000000..0b724f702d5 --- /dev/null +++ b/examples/src/collections/ISized.jetl @@ -0,0 +1,3 @@ +interface class ISized { + val size : Int +} \ No newline at end of file diff --git a/examples/src/collections/LinkedList.jetl b/examples/src/collections/LinkedList.jetl new file mode 100644 index 00000000000..ca16db4d89a --- /dev/null +++ b/examples/src/collections/LinkedList.jetl @@ -0,0 +1,73 @@ +class LinkedList : IMutableList { + private class Item(var value : Item) { + var next : Item + var previous : Item + } + + private var head : Item = null + private var tail : Item = null + override var size { get; private set; } + + override fun add(index : Int, value : T) { + size++ + checkIndex(index) + val newItem = Item(value) + if (index == 0) { + newItem.next = head + head = newItem + if (tail == null) { + tail = head + } + } else { + var insertAfter = itemAt(index) + newItem.next = insertAfter.next + insertAfter.next = newItem + if (tail == insertAfter) { + tail = newItem + } + } + } + + private fun checkIndex(index : Int) { + if (!index in [0..size-1]) { + throw IndexOutOfBoundsException(index) + } + } + + override fun remove(index : Int) : T { + checkIndex(index) + val item = itemAt(index) + if (item == head) { + head = item.next + if (head == null) + tail= null + } else { + item.previous.next = item.next + if (item.next == null) { + item.next.previous = item.previous + } else { + tail = tail.previous + } + } + size-- + return item.value + } + + override fun set(index : Int, value : T) : T { + checkIndex(index) + val item = itemAt(index) + val result = item.value + item.value = value + return result + } + + private fun itemAt(index : Int) { + var result = head + for (i in [1..index]) { + result = result.next + } + return result + } + + override fun mutableIterator() : IMutableIterator +} \ No newline at end of file diff --git a/examples/src/collections/List.jetl b/examples/src/collections/List.jetl new file mode 100644 index 00000000000..14cd75594d3 --- /dev/null +++ b/examples/src/collections/List.jetl @@ -0,0 +1,27 @@ +enum class List(theSize : Int) : IList { + Nil : List(0) + + Cons(val value : T, val tail : List) : List(1 + tail.size) + + override val size : Int { + get() = theSize + } + + override val isEmpty : Boolean { + get() = this == Nil + } + + override fun iterator() = new IIterator() { + private var current = List.this + + override val hasNext { + get() = current == Nil + } + + override fun next() { + val result = current.value + current = current.tail + return result + } + } +} \ No newline at end of file diff --git a/examples/src/map/IMap.jetl b/examples/src/map/IMap.jetl new file mode 100644 index 00000000000..4f91bd5e996 --- /dev/null +++ b/examples/src/map/IMap.jetl @@ -0,0 +1,4 @@ +interface class IMap { + + +} \ No newline at end of file diff --git a/examples/src/priorityqueues/BinaryHeap.jetl b/examples/src/priorityqueues/BinaryHeap.jetl new file mode 100644 index 00000000000..1d54ca15cae --- /dev/null +++ b/examples/src/priorityqueues/BinaryHeap.jetl @@ -0,0 +1,104 @@ +class BinaryHeap : IPriorityQueue { + private val data : IMutableList + private val compare : Comparison + + fun this(data : IIterable, compare : Comparison = naturalOrder) { + this.compare = compare + this.data = ArrayList(data) + siftDown(* this.data.size / 2 .. 0) +/* + for (val i in data.size / 2 .. 0) { + siftDown(i) + } +*/ + } + + fun this(compare : Comparison) { + this.compare = compare + this.data = ArrayList() + } + + fun this() { + this.data = ArrayList() + Assert(T is IComparable) + this.comparator = naturalOrder + } + + override fun extract() : T { + if (this.isEmpty) + throw UnderflowException() + data.swap(0, data.lastIndex) + data.remove(data.lastIndex) + siftDown(0) + } + + override fun add(item : T) { + data.add(item) + siftUp(data.lastItem) + } + + private fun siftDown(index : Int) { + var current = index + while (current.left.exists) { + var min = current + if (current.left.value < min.value) { + min = current.left + } + if (current.right.exists && current.right.value < min.value) { + min = current.right + } + if (min == current) break + data.swap(min, current) + current = min + } + } + + private fun siftUp(index : Int) { + if (!current.exists) return + var current = index + while (current.parent.exists) { + if (current.value < current.parent.value) { + data.swap(current, current.parent) + current = current.parent + } + } + } + + private extension HeapIndex for Int { + val parent : Int { + get() = (this - 1) / 2 + } + + val left : Int { + get() = this * 2 + 1 + } + + val right : Int { + get() = this * 2 + 2 + } + + val value : T { + get() = data[this] + } + + val exists : Boolean { + get() = (this < data.size) && (this >= 0) + } + } + + private extension for T { + [operator] fun compareTo(other : T) : Int = compare(this, other) + } + +} + +extension fun IMutableList.swap(a : Int, b : Int) { + val t = this[a] + this[a] = this[b] + this[b] = t +} + +extension val IList.lastIndex : Int { + get() = this.size - 1 +} + diff --git a/examples/src/priorityqueues/IPriorityQueue.jetl b/examples/src/priorityqueues/IPriorityQueue.jetl new file mode 100644 index 00000000000..01e5f357eaf --- /dev/null +++ b/examples/src/priorityqueues/IPriorityQueue.jetl @@ -0,0 +1,5 @@ +interface class IPriorityQueue { + fun extract() : T + fun add(item : T) + val isEmpty : Boolean +} diff --git a/examples/src/priorityqueues/PriorityQueueAsPushPop.jetl b/examples/src/priorityqueues/PriorityQueueAsPushPop.jetl new file mode 100644 index 00000000000..0bbc006f7e1 --- /dev/null +++ b/examples/src/priorityqueues/PriorityQueueAsPushPop.jetl @@ -0,0 +1,7 @@ +class PriorityQueueAsPushPop wraps(wrapped : IPriorityQueue) : IPushPop { + override fun pop() = wrapped.extract() + override fun push(item : T) = wrapped.add(item) + override val isEmpty { + get() = wrapped.isEmpty + } +} \ No newline at end of file diff --git a/examples/src/util/Comparison.jetl b/examples/src/util/Comparison.jetl new file mode 100644 index 00000000000..1318b496d54 --- /dev/null +++ b/examples/src/util/Comparison.jetl @@ -0,0 +1,19 @@ +type Comparison = {T, T => Int} + +fun naturalOrder>(a : T, b : T) : Int = a.compareTo(b) + +fun castingNaturalOrder(a : Object, b : Object) : Int = a.as>.compareTo(b.as>) + +enum class ComparisonResult { + LS,EQ, GR +} + +type MatchableComparison = {T, T, => ComparisonResult} + +fun asMatchableComparison(cmp : Comparison) : MatchableComparison = {a, b => + val res = cmp(a, b) + if (res == 0) return ComparisonResult.EQ + if (res < 0) return ComparisonResult.LS + return ComparisonResult.GR +} + diff --git a/examples/src/util/IComparable.jetl b/examples/src/util/IComparable.jetl new file mode 100644 index 00000000000..79d19a364e6 --- /dev/null +++ b/examples/src/util/IComparable.jetl @@ -0,0 +1,3 @@ +interface class IComparable { + fun compareTo(other : T) : Int +} \ No newline at end of file