Skip to content

Commit

Permalink
Finish binary tree std (#576)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored Jun 1, 2024
1 parent 9ebe8a7 commit 1da9a70
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="build -O3 -d ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O0 -d ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<envs>
<env name="LLVM_ADDITIONAL_FLAGS" value="-lole32 -lws2_32" />
<env name="LLVM_BUILD_INCLUDE_DIR" value="$PROJECT_DIR$/../llvm-project-latest/build/include" />
Expand Down
66 changes: 52 additions & 14 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,19 +1,57 @@
import "std/os/env";
import "std/io/filepath";
import "bootstrap/lexer/lexer";
import "std/data/binary-tree";

f<int> main() {
String filePathString = getEnv("SPICE_STD_DIR") + "/../test/test-files/bootstrap-compiler/standalone-lexer-test/test-file.spice";
FilePath filePath = FilePath(filePathString);
Lexer lexer = Lexer(filePath);
unsigned long tokenCount = 0l;
while (!lexer.isEOF()) {
Token token = lexer.getToken();
token.print();
lexer.advance();
tokenCount++;
}
printf("\nLexed tokens: %d\n", tokenCount);
BinaryTree<int> tree;
tree.insert(5);
tree.insert(3);
tree.insert(7);
tree.insert(2);
assert tree.contains(5);
assert tree.contains(3);
assert tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(3);
assert tree.contains(5);
assert !tree.contains(3);
assert tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(5);
assert !tree.contains(5);
assert !tree.contains(3);
assert tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(7);
assert !tree.contains(5);
assert !tree.contains(3);
assert !tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(2);
assert !tree.contains(5);
assert !tree.contains(3);
assert !tree.contains(7);
assert !tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);

printf("All assertions passed!\n");
}

/*import "std/os/env";
Expand Down
9 changes: 7 additions & 2 deletions src/typechecker/FunctionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,13 @@ Function *FunctionManager::matchFunction(Scope *matchScope, const std::string &r
return nullptr;

// Check if more than one function matches the requirements
if (matches.size() > 1)
throw SemanticError(callNode, FUNCTION_AMBIGUITY, "Multiple functions match the requested signature");
if (matches.size() > 1) {
std::stringstream errorMessage;
errorMessage << "The function/procedure '" << reqName << "' is ambiguous. All of the following match the requested criteria:";
for (const Function *match : matches)
errorMessage << "\n " << match->getSignature();
throw SemanticError(callNode, FUNCTION_AMBIGUITY, errorMessage.str());
}

// Insert into cache
lookupCache[cacheKey] = matches.front();
Expand Down
155 changes: 146 additions & 9 deletions std/data/binary-tree.spice
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
// Link external functions
ext f<heap byte*> malloc(long);
ext p free(heap byte*);

// Add generic type definitions
type T dyn;

/**
* Node of a BinaryTree
*/
public type Node<T> struct {
T value
heap Node<T>* childLeft = nil<heap Node<T>*>
heap Node<T>* childRight = nil<heap Node<T>*>
T value
}

/**
Expand All @@ -28,7 +24,148 @@ public type BinaryTree<T> struct {
bool isBalanced = false
}

public p BinaryTree.insert<T>(T newValue, heap Node<T>* baseNode = nil<heap Node<T>*>) {
// Search position where to insert
// ToDo
}
/**
* Insert a new value into the binary tree
*
* @param value The value to insert
*/
public p BinaryTree.insert<T>(const T& value) {
// Create the new node
heap Node<T>* newNode = sNew<Node<T>>(Node<T>{value, nil<heap Node<T>*>, nil<heap Node<T>*>});

// Insert the new node
if this.rootNode == nil<heap Node<T>*> {
this.rootNode = newNode;
} else {
this.insertNode(this.rootNode, newNode);
}
}

/**
* Search for a value in the binary tree
*
* @param value The value to search for
* @return True if the value was found, false otherwise
*/
public f<bool> BinaryTree.contains<T>(const T& value) {
return this.containsNode(this.rootNode, value);
}

/**
* Delete a value from the binary tree
*
* @param value The value to delete
*/
public p BinaryTree.delete<T>(const T& value) {
this.rootNode = this.deleteNode(this.rootNode, value);
}

/**
* Recursion helper to insert a new node into the binary tree
*
* @param currentNode The current node to check
* @param newNode The new node to insert
*/
p BinaryTree.insertNode<T>(heap Node<T>* currentNode, heap Node<T>* newNode) {
if newNode.value < currentNode.value {
if currentNode.childLeft == nil<heap Node<T>*> {
currentNode.childLeft = newNode;
} else {
this.insertNode(currentNode.childLeft, newNode);
}
} else {
if currentNode.childRight == nil<heap Node<T>*> {
currentNode.childRight = newNode;
} else {
this.insertNode(currentNode.childRight, newNode);
}
}
}

/**
* Recursion helper to find the smallest node in the binary tree
*
* @param currentNode The current node to check
* @return The smallest node
*/
f<bool> BinaryTree.containsNode<T>(heap Node<T>* currentNode, const T& value) {
// We reached the end of the tree
if currentNode == nil<heap Node<T>*> {
return false;
}

// We found the value
if currentNode.value == value {
return true;
}

// Search in the left or right child
if value < currentNode.value {
return this.containsNode(currentNode.childLeft, value);
} else {
return this.containsNode(currentNode.childRight, value);
}
}

/**
* Recursion helper to find the smallest node in the binary tree
*
* @param currentNode The current node to check
* @return The smallest node
*/
f<heap Node<T>*> BinaryTree.deleteNode<T>(heap Node<T>* currentNode, const T& value) {
// We reached the end of the tree
if currentNode == nil<heap Node<T>*> {
return currentNode;
}

// Check the value
if value < currentNode.value {
currentNode.childLeft = this.deleteNode(currentNode.childLeft, value);
} else if value > currentNode.value {
currentNode.childRight = this.deleteNode(currentNode.childRight, value);
} else {
// Node with only one child or no child
if currentNode.childLeft == nil<heap Node<T>*> {
heap Node<T>* tempNode = currentNode.childRight;
// Use dealloc, because we don't want to call the destructor.
// The destructor would delete children and parent.
unsafe {
sDealloc((byte*) currentNode);
}
return tempNode;
} else if currentNode.childRight == nil<heap Node<T>*> {
heap Node<T>* tempNode = currentNode.childLeft;
// Use dealloc, because we don't want to call the destructor.
// The destructor would delete children and parent.
unsafe {
sDealloc((byte*) currentNode);
}
return tempNode;
}

// Node with two children: Get the smallest node in the right subtree
heap Node<T>* tempNode = this.findSmallestNode(currentNode.childRight);

// Copy the smallest node's value to this node
currentNode.value = tempNode.value;

// Delete the smallest node
currentNode.childRight = this.deleteNode(currentNode.childRight, tempNode.value);
}
return currentNode;
}

/**
* Recursion helper to find the smallest node in the binary tree
*
* @param currentNode The current node to check
* @return The smallest node
*/
f<heap Node<T>*> BinaryTree.findSmallestNode<T>(heap Node<T>* currentNode) {
heap Node<T>* smallestNode = currentNode;
while smallestNode.childLeft != nil<heap Node<T>*> {
smallestNode = smallestNode.childLeft;
}
return smallestNode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
All assertions passed!
55 changes: 55 additions & 0 deletions test/test-files/std/data/binary-tree-normal-usecase/source.spice
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import "std/data/binary-tree";

f<int> main() {
BinaryTree<int> tree;
tree.insert(5);
tree.insert(3);
tree.insert(7);
tree.insert(2);
assert tree.contains(5);
assert tree.contains(3);
assert tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(3);
assert tree.contains(5);
assert !tree.contains(3);
assert tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(5);
assert !tree.contains(5);
assert !tree.contains(3);
assert tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(7);
assert !tree.contains(5);
assert !tree.contains(3);
assert !tree.contains(7);
assert tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);
tree.delete(2);
assert !tree.contains(5);
assert !tree.contains(3);
assert !tree.contains(7);
assert !tree.contains(2);
assert !tree.contains(1);
assert !tree.contains(4);
assert !tree.contains(6);
assert !tree.contains(8);

printf("All assertions passed!\n");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Error|Semantic] ./source.spice:8:5:
Function ambiguity: The function/procedure 'foo' is ambiguous. All of the following match the requested criteria:
foo(byte*&)
foo<byte>(byte*&)

8 foo(ptr);
^^^^^^^^
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type T dyn;

p foo(byte*& ptr) {}
p foo<T>(T*& ptr) {}

f<int> main() {
byte* ptr = nil<byte*>;
foo(ptr);
}

0 comments on commit 1da9a70

Please sign in to comment.