Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more string methods #214

Merged
merged 4 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions media/test-project/os-test.spice
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
f<int> main() {
int test = "string";
}

/*f<int> main() {
int v1 = 10;
int v2 = v1;
printf("v1: %d, v2: %d\n", v1, v2);
v2++;
printf("v1: %d, v2: %d\n", v1, v2);

unsigned long startIndex = 10l;
for unsigned long charIndex = startIndex; charIndex < 20l; charIndex++ {
printf("Char index: %d, start index: %d\n", charIndex, startIndex);
}
}*/
}

/*import "std/net/http" as http;

Expand Down
16 changes: 8 additions & 8 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ std::any AnalyzerVisitor::visitFctDef(FctDefNode *node) {
auto returnType = any_cast<SymbolType>(visit(node->returnType()));
if (returnType.is(TY_DYN))
throw SemanticError(node, UNEXPECTED_DYN_TYPE_SA, "Dyn return types are not allowed");
if (returnType.isPointer())
/*if (returnType.isPointer())
throw SemanticError(node, COMING_SOON_SA,
"Spice currently not supports pointer return types due to not handling pointer escaping.");
"Spice currently not supports pointer return types due to not handling pointer escaping.");*/
node->fctScope->insert(RETURN_VARIABLE_NAME, returnType, SymbolSpecifiers(returnType), DECLARED, node);

// Return to old scope
Expand Down Expand Up @@ -263,9 +263,9 @@ std::any AnalyzerVisitor::visitFctDef(FctDefNode *node) {
SymbolTableEntry *returnVarEntry = currentScope->lookup(RETURN_VARIABLE_NAME);
if (returnVarEntry->type.is(TY_GENERIC)) {
SymbolType returnType = spiceFunc.getReturnType();
if (returnType.isPointer())
/*if (returnType.isPointer())
throw SemanticError(node, COMING_SOON_SA,
"Spice currently not supports pointer return types due to not handling pointer escaping.");
"Spice currently not supports pointer return types due to not handling pointer escaping.");*/
returnVarEntry->updateType(returnType, true);
}

Expand Down Expand Up @@ -1166,7 +1166,7 @@ std::any AnalyzerVisitor::visitPrintfCall(PrintfCallNode *node) {
case 'X': {
if (!assignmentType.isOneOf({TY_INT, TY_SHORT, TY_LONG, TY_BYTE, TY_BOOL}))
throw SemanticError(assignment, PRINTF_TYPE_ERROR,
"Template string expects int, byte or bool, but got " + assignmentType.getName(false));
"Template string expects int, short, long, byte or bool, but got " + assignmentType.getName(false));
placeholderCount++;
break;
}
Expand All @@ -1187,14 +1187,14 @@ std::any AnalyzerVisitor::visitPrintfCall(PrintfCallNode *node) {
case 's': {
if (!assignmentType.is(TY_STRING) && !assignmentType.isPointerOf(TY_CHAR) && !assignmentType.isArrayOf(TY_CHAR))
throw SemanticError(assignment, PRINTF_TYPE_ERROR,
"Template string expects string, but got " + assignmentType.getName(false));
"Template string expects string, char* or char[], but got " + assignmentType.getName(false));
placeholderCount++;
break;
}
case 'p': {
if (!assignmentType.isPointer() && !assignmentType.isArray())
if (!assignmentType.isPointer() && !assignmentType.isArray() && !assignmentType.is(TY_STRING))
throw SemanticError(assignment, PRINTF_TYPE_ERROR,
"Template string expects pointer, but got " + assignmentType.getName(false));
"Template string expects pointer, array or string, but got " + assignmentType.getName(false));
placeholderCount++;
break;
}
Expand Down
14 changes: 6 additions & 8 deletions src/generator/OpRuleConversionsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1511,16 +1511,14 @@ llvm::Value *OpRuleConversionsManager::getCastInst(llvm::Value *rhsV, const Symb
case COMB(TY_CHAR, TY_SHORT): // fallthrough
case COMB(TY_CHAR, TY_LONG):
return builder->CreateIntCast(rhsV, lhsTy, false);
case COMB(TY_CHAR, TY_CHAR): // fallthrough
case COMB(TY_STRING, TY_STRING):
case COMB(TY_CHAR, TY_CHAR): // fallthrough
case COMB(TY_STRING, TY_STRING): // fallthrough
case COMB(TY_STRING, TY_PTR): // fallthrough
case COMB(TY_BOOL, TY_BOOL): // fallthrough
case COMB(TY_PTR, TY_STRING):
return rhsV;
case COMB(TY_STRING, TY_PTR):
return builder->CreatePointerCast(rhsV, lhsTy);
case COMB(TY_BOOL, TY_BOOL):
return rhsV;
case COMB(TY_PTR, TY_STRING): // fallthrough (string corresponds to byte* or char*)
case COMB(TY_PTR, TY_PTR):
return builder->CreatePointerCast(rhsV, lhsTy);
return lhsSTy.getContainedTy() == rhsSTy.getContainedTy() ? rhsV : builder->CreatePointerCast(rhsV, lhsTy);
}
throw std::runtime_error("Internal compiler error: Operator fallthrough: (cast)"); // GCOV_EXCL_LINE
}
Expand Down
2 changes: 1 addition & 1 deletion std/data/doubly-linked-list.spice
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public p DoublyLinkedList.insert<T>(T newValue, Node<T>* prevNode = nil<Node<T>*
// Create new node
Node<T>* newNode;
unsafe {
newNode = (Node<T>*) malloc(sizeof(type Node<T>));
newNode = (Node<T>*) malloc(sizeof(type Node<T>) / 8);
}
newNode.value = newValue;

Expand Down
2 changes: 1 addition & 1 deletion std/data/linked-list.spice
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public p LinkedList.insert<T>(T newValue, Node<T>* prevNode = nil<Node<T>*>) {
// Create new node
Node<T>* newNode;
unsafe {
newNode = (Node<T>*) malloc(sizeof(type Node<T>));
newNode = (Node<T>*) malloc(sizeof(type Node<T>) / 8);
}
newNode.value = newValue;

Expand Down
2 changes: 1 addition & 1 deletion std/data/queue.spice
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public p Queue.ctor(unsigned int initAllocItems) {

public p Queue.ctor(unsigned long initAllocItems = INITIAL_ALLOC_COUNT) {
// Allocate space for the initial number of elements
this.itemSize = sizeof(type T);
this.itemSize = sizeof(type T) / 8;
unsafe {
this.contents = (T*) malloc(this.itemSize * initAllocItems);
}
Expand Down
2 changes: 1 addition & 1 deletion std/data/stack.spice
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public p Stack.ctor(unsigned int initAllocItems) {

public p Stack.ctor(unsigned long initAllocItems = INITIAL_ALLOC_COUNT) {
// Allocate space for the initial number of elements
this.itemSize = sizeof(type T);
this.itemSize = sizeof(type T) / 8;
unsafe {
this.contents = (T*) malloc(this.itemSize * initAllocItems);
}
Expand Down
2 changes: 1 addition & 1 deletion std/data/vector.spice
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public p Vector.ctor(unsigned int initAllocItems) {

public p Vector.ctor(unsigned long initAllocItems = INITIAL_ALLOC_COUNT) {
// Allocate space for the initial number of elements
this.itemSize = sizeof(type T);
this.itemSize = sizeof(type T) / 8;
unsafe {
this.contents = (T*) malloc(this.itemSize * initAllocItems);
}
Expand Down
119 changes: 97 additions & 22 deletions std/runtime/string_rt.spice
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public p String.ctor(const string value = "") {
// Allocate space for the initial number of elements
unsafe {
unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator
this.contents = (char*) malloc(sizeof(type char) * requiredBytes);
this.contents = (char*) malloc(requiredBytes);
}

// Save initial value
Expand All @@ -47,7 +47,7 @@ public p String.ctor(const string value1, const string value2) {
// Allocate space for the initial number of elements
unsafe {
unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator
this.contents = (char*) malloc(sizeof(type char) * requiredBytes);
this.contents = (char*) malloc(requiredBytes);
}

// Save initial value
Expand All @@ -68,7 +68,7 @@ public p String.ctor(const char value) {
// Allocate space for the initial number of elements
unsafe {
unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator
this.contents = (char*) malloc(sizeof(type char) * requiredBytes);
this.contents = (char*) malloc(requiredBytes);
}

// Save initial value
Expand Down Expand Up @@ -257,31 +257,110 @@ public p String.clear() {
}

/**
* Checks if the string contains a substring
* Searches for a substring in a string. Returns -1 if the string was not found.
*
* @param needle Substring to search for
* @return Found or not
* @param startIndex Index where to start the search
* @return Index, where the substring was found / -1
*/
public f<bool> String.contains(string needle) {
public f<long> String.find(string needle, unsigned long startIndex = 0l) {
// Return -1 if the startIndex is out of bounds
if startIndex >= this.length { return -1l; }

unsigned long needleLength = str.getRawLength(needle);
// Return false if the needle is longer than the haystack
if this.length < needleLength { return false; }
if this.length < needleLength { return -1l; }

// Search needle in haystack
for unsigned long startIdx = 0l; startIdx <= this.length - needleLength; startIdx++ {
for unsigned long idx = startIndex; idx <= this.length - needleLength; idx++ {
// Start matching at startIdx
for unsigned long charIdx = 0l; charIdx < needleLength; charIdx++ {
unsafe {
if this.contents[startIdx + charIdx] != needle[charIdx] {
if this.contents[idx + charIdx] != needle[charIdx] {
continue 2;
}
}
}
// Whole string was matched
return true;
return idx;
}
return false;
return -1l;
}

/**
* Searches for a substring in a string. Returns -1 if the string was not found.
*
* @param startIndex Index where to start the search
* @return Index, where the substring was found / -1
*/
public f<long> String.find(string needle, unsigned int startIndex) {
return this.find(needle, (long) startIndex);
}

/**
* Checks if the string contains a substring
*
* @param needle Substring to search for
* @return Found or not
*/
public inline f<bool> String.contains(string needle) {
return this.find(needle) != -1l;
}

/**
* Replace occurrence of substring with the replacement string
*
* @param needle Substring to replace
* @param replacement Replacement for the substring
*/
/*public p String.replace(
string* haystack,
string needle,
string replacement,
unsigned long startIndex = 0l
) {
// Find occurrence
unsigned long startIdx = haystack.find(needle, startIndex);
// Return if not found
if startIdx == -1l { return; }

// Replace
unsigned long needleLength = str.getRawLength(needle);
for unsigned long idx = 0; idx < needleLength; idx++ {
// ToDo: Extend
}
}*/

/**
* Replace occurrence of substring with the replacement string
*
* @param needle Substring to replace
* @param replacement Replacement for the substring
*/
/*public inline p String.replace(
string* haystack,
string needle,
string replacement,
unsigned int startIndex
) {
this.replace(haystack, needle, replacement, (long) startIndex);
}*/

/**
* Replace all occurrences of substring with the replacement string
*
* @param needle Substring to replace
* @param replacement Replacement for the substring
*/
/*public p String.replaceAll(string* haystack, string needle, string replacement) {
unsigned long needleLength = str.getRawLength(needle);
// Return false if the needle is longer than the haystack
if this.length < needleLength { return -1l; }

for unsigned long startIdx = 0; startIdx <= this.length - needle; startIdx++ {
// ToDo: Extend
}
}*/

/**
* Returns the substring of the current string, starting at position `startIndex` with
* the length of `length`.
Expand All @@ -290,12 +369,10 @@ public f<bool> String.contains(string needle) {
* @param length Length of substring
* @return Substring
*/
public f<string> String.substring(unsigned long startIndex, long length = -1l) {
String substring = String("");

public f<String> String.substring(unsigned long startIndex, long length = -1l) {
// Return empty string if the length is 0 or the startIndex is out of bounds
if length == 0l || startIndex >= this.length {
return (string) substring.contents;
return String("");
}

// Get everything after startIndex when length is -1
Expand All @@ -309,12 +386,11 @@ public f<string> String.substring(unsigned long startIndex, long length = -1l) {
}

// Get substring
String substring = String("");
substring.reserve(length);
unsigned long endIndex = startIndex + length;
for unsigned long charIndex = startIndex; charIndex < endIndex; charIndex++ {
unsafe {
//printf("'%c'\n", this.contents[charIndex]);
//printf("%d\n", charIndex - startIndex);
substring.contents[charIndex - startIndex] = this.contents[charIndex];
}
}
Expand All @@ -325,7 +401,7 @@ public f<string> String.substring(unsigned long startIndex, long length = -1l) {
}

// Return raw string
return (string) substring.contents;
return substring;
}

/**
Expand All @@ -336,7 +412,7 @@ public f<string> String.substring(unsigned long startIndex, long length = -1l) {
* @param length Length of substring
* @return Substring
*/
public inline f<string> String.substring(unsigned int startIndex, int length = -1) {
public inline f<String> String.substring(unsigned int startIndex, int length = -1) {
return this.substring((long) startIndex, (long) length);
}

Expand Down Expand Up @@ -370,8 +446,7 @@ p String.resize(unsigned long newLength) {
unsafe {
byte* oldAddress = (byte*) this.contents;
unsigned long requiredBytes = newLength + 1; // +1 because of null terminator
int newSize = (int) (sizeof(type char) * requiredBytes);
char* newMemory = (char*) realloc(oldAddress, newSize);
char* newMemory = (char*) realloc(oldAddress, (int) requiredBytes);
this.contents = newMemory;
}
// Set new capacity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Semantic error in : ./test-files/analyzer/builtins/error-printf-wrong-type1/source.spice:2:18:
Types of printf call not matching: Template string expects int, byte or bool, but got double
Types of printf call not matching: Template string expects int, short, long, byte or bool, but got double

2 printf("%d", 6.23456);
^^^^^^^
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Semantic error in : ./test-files/analyzer/builtins/error-printf-wrong-type3/source.spice:3:18:
Types of printf call not matching: Template string expects string, but got int*
Types of printf call not matching: Template string expects string, char* or char[], but got int*

3 printf("%s", &integer);
^^^^^^^^
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Semantic error in : ./test-files/analyzer/builtins/error-printf-wrong-type4/source.spice:5:18:
Types of printf call not matching: Template string expects pointer, but got NotAPointer
Types of printf call not matching: Template string expects pointer, array or string, but got NotAPointer

5 printf("%p", nonPtr);
^^^^^^
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Semantic error in : ./test-files/analyzer/generics/error-generic-type-check/source.spice:4:18:
Types of printf call not matching: Template string expects int, byte or bool, but got string
Types of printf call not matching: Template string expects int, short, long, byte or bool, but got string

4 printf("%d", g);
^
10 changes: 10 additions & 0 deletions test/test-files/std/runtime/string-basic-methods/cout.out
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
24
1
0
1
-1
0
11
-1
0
1
1
Expand All @@ -17,6 +22,11 @@
12
12
24
1
-1
0
11
-1
0
1
1
Expand Down
Loading