diff --git a/self_hosted/runs_wrong.txt b/self_hosted/runs_wrong.txt index 61286578..b44b692f 100644 --- a/self_hosted/runs_wrong.txt +++ b/self_hosted/runs_wrong.txt @@ -42,3 +42,4 @@ tests/syntax_error/bad_addressof.jou tests/wrong_type/assert.jou tests/wrong_type/cannot_be_indexed.jou tests/wrong_type/index.jou +stdlib/ascii.jou diff --git a/stdlib/ascii.jou b/stdlib/ascii.jou new file mode 100644 index 00000000..5dedfca1 --- /dev/null +++ b/stdlib/ascii.jou @@ -0,0 +1,40 @@ +import "stdlib/str.jou" +import "stdlib/mem.jou" + +# Test if a string is ASCII only. +# TODO: test +def is_ascii(s: byte*) -> bool: + for p = s; *p != '\0'; p++: + if *p >= 128: + return False + return True + +# Check for '0', '1', ..., '9'. +# TODO: test +def is_ascii_digit(b: byte) -> bool: + return '0' <= b and b <= '9' + +# Checks if the given byte is an ASCII punctuation character, such as '*' or '_' or '"'. +# TODO: test +def is_ascii_punctuation(b: byte) -> bool: + return strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", b) != NULL + +# Checks if the given byte is an ASCII whitespace character, such as ' ' or '\n'. +# TODO: test +def is_ascii_whitespace(b: byte) -> bool: + return strchr("\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f ", b) != NULL + +# Removes ASCII whitespace from both ends of a string in-place. +# Similar to .strip() in Python or .trim() in JavaScript. +def trim_ascii_whitespace(s: byte*) -> void: + start = s + while *start != '\0' and is_ascii_whitespace(*start): + start++ + + len = strlen(start) + while len > 0 and is_ascii_whitespace(start[len-1]): + len-- + + if start != s: + memcpy(s, start, len) + s[len] = '\0' diff --git a/stdlib/io.jou b/stdlib/io.jou index e46fb907..53f35083 100644 --- a/stdlib/io.jou +++ b/stdlib/io.jou @@ -60,6 +60,10 @@ declare fprintf(file: FILE *, pattern: byte*, ...) -> int declare fgetc(file: FILE*) -> int # see getchar() declare fscanf(file: FILE*, pattern: byte*, ...) -> int +# Reads at most n items of data, each of size "itemsize". Returns number of items read. +# Usually this is used with itemsize 1, so return value is number of bytes. +declare fread(destination: byte*, itemsize: long, n: long, file: FILE*) -> long + # Ensure that output is actually written. It may remain buffered # if this function isn't called. declare fflush(file: FILE*) -> int diff --git a/stdlib/str.jou b/stdlib/str.jou index 90970591..17cd3a22 100644 --- a/stdlib/str.jou +++ b/stdlib/str.jou @@ -36,8 +36,13 @@ def ends_with(s: byte*, suffix: byte*) -> bool: return offset >= 0 and strcmp(&s[offset], suffix) == 0 # Return how many bytes at start of s appear in the accept string. +# For example, you can use strspn(s, " \t") to get the amount of indentation. declare strspn(s: byte*, accept: byte*) -> long +# Return how many bytes at start of s do not appear in the reject string. +# For example, you can use strcspn(s, "\n") to get the length of the first line. +declare strcspn(s: byte*, accept: byte*) -> long + # Copy a string. Assumes it fits. Returned value is dest. declare strcpy(dest: byte*, source: byte*) -> byte* @@ -47,3 +52,8 @@ declare strcat(dest: byte*, source: byte*) -> byte* # Return a newly allocated (as in malloc()) copy of the string. declare strdup(s: byte*) -> byte* + +# Convert a string to an int. +# Returns 0 on error, and ignores junk at end: atoi("123foo") == 123 +declare atoi(s: byte*) -> int +declare atoll(s: byte*) -> long