From d63f5334ce50f1956e4229ff7dd305b2dbe6d437 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Fri, 3 Jan 2025 13:36:50 -0500 Subject: [PATCH 1/8] feat: add ExtraMojo --- recipes/ExtraMojo/recipe.yaml | 53 ++++++ recipes/ExtraMojo/tests/test_bstr.mojo | 217 ++++++++++++++++++++++++ recipes/ExtraMojo/tests/test_file.mojo | 95 +++++++++++ recipes/ExtraMojo/tests/test_regex.mojo | 61 +++++++ 4 files changed, 426 insertions(+) create mode 100644 recipes/ExtraMojo/recipe.yaml create mode 100644 recipes/ExtraMojo/tests/test_bstr.mojo create mode 100644 recipes/ExtraMojo/tests/test_file.mojo create mode 100644 recipes/ExtraMojo/tests/test_regex.mojo diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml new file mode 100644 index 0000000..840d60a --- /dev/null +++ b/recipes/ExtraMojo/recipe.yaml @@ -0,0 +1,53 @@ +context: + version: "0.3.1" + +package: + name: "hue" + version: ${{ version }} + +source: + - git: https://github.com/ExtraMojo/ExtraMojo.git + rev: 42c0b81ba3cf2bde90fb5fa559089a10e129202e + +build: + number: 0 + script: + - mojo package ExtraMojo -o ${{ PREFIX }}/lib/mojo/ExtraMojo.mojopkg +requirements: + host: + - max + run: + - ${{ pin_compatible('max') }} + +tests: + - script: + - if: unix + then: + - mojo run tests/test_file.mojo + - mojo test tests/test_regex.mojo + - mojo test tests/test_bstr.mojo + files: + recipe: + - tests/test_file.mojo + - tests/test_regex.mojo + - tests/test_bstr.mojo + +about: + homepage: https://github.com/ExtraMojo/ExtraMojo + # Remember to specify the license variants for BSD, Apache, GPL, and LGPL. + # Use the SPDX identifier, e.g: GPL-2.0-only instead of GNU General Public License version 2.0 + # See https://spdx.org/licenses/ + license: "Unlicense OR MIT" + # It is strongly encouraged to include a license file in the package, + # (even if the license doesn't require it) using the license_file entry. + # See https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#license-file + license_file: + - LICENSE-MIT + - UNLICENSE + summary: Extra functionality not yet in the standard library, mostly focused on strings and file IO. + repository: https://github.com/ExtraMojo/ExtraMojo + +extra: + maintainers: + - sstadick + project_name: ExtraMojo diff --git a/recipes/ExtraMojo/tests/test_bstr.mojo b/recipes/ExtraMojo/tests/test_bstr.mojo new file mode 100644 index 0000000..0fc0eda --- /dev/null +++ b/recipes/ExtraMojo/tests/test_bstr.mojo @@ -0,0 +1,217 @@ +from ExtraMojo.bstr.bstr import ( + SplitIterator, + find, + to_ascii_lowercase, + to_ascii_uppercase, +) +from memory import Span +from testing import * + + +fn s(bytes: Span[UInt8]) -> String: + """Convert bytes to a String.""" + var buffer = String() + buffer.write_bytes(bytes) + return buffer + + +fn test_lowercase_short() raises: + var example = List("ABCdefgHIjklmnOPQRSTUVWXYZ".as_bytes()) + var answer = "abcdefghijklmnopqrstuvwxyz" + to_ascii_lowercase(example) + assert_equal(s(example), s(answer.as_bytes())) + + +fn test_uppercase_short() raises: + var example = List("ABCdefgHIjklmnOPQRSTUVWXYZ".as_bytes()) + var answer = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + to_ascii_uppercase(example) + assert_equal(s(example), s(answer.as_bytes())) + + +fn test_lowercase() raises: + var example = List( + "ABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZ" + .as_bytes() + ) + var answer = "abcdefghijklmnopqrstuvwxyz;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;abcdefghijklmnopqrstuvwxyz" + to_ascii_lowercase(example) + assert_equal(s(example), s(answer.as_bytes())) + + +fn test_uppercase() raises: + var example = List( + "ABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZ" + .as_bytes() + ) + var answer = "ABCDEFGHIJKLMNOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZ" + to_ascii_uppercase(example) + assert_equal(s(example), s(answer.as_bytes())) + + +fn test_lowercase_long() raises: + var example = List( + "ABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZ" + .as_bytes() + ) + var answer = "abcdefghijklmnopqrstuvwxyz;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;abcdefghijklmnopqrstuvwxyz" + to_ascii_lowercase(example) + assert_equal(s(example), s(answer.as_bytes())) + + +fn test_uppercase_long() raises: + var example = List( + "ABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZABCdefgHIjklmnOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCdefgHIjklmnOPQRSTUVWXYZ" + .as_bytes() + ) + var answer = "ABCDEFGHIJKLMNOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ABCDEFGHIJKLMNOPQRSTUVWXYZ" + to_ascii_uppercase(example) + assert_equal(s(example), s(answer.as_bytes())) + + +fn test_find_short() raises: + var haystack = "ABCDEFGhijklmnop".as_bytes() + var expected = 4 + var answer = find(haystack, "EFG".as_bytes()).value() + assert_equal(answer, expected) + + +fn test_find_medium() raises: + var haystack = "ABCDEFGhijklmnop0123456789TheKindIguana\nJumpedOver the angry weird fense as it ran away from the seething moon that was swooping down to scoop it up and bring it to outer space.".as_bytes() + var expected = 171 + var answer = find(haystack, "space".as_bytes()).value() + assert_equal(answer, expected) + + +fn test_find_long() raises: + var haystack = "ABCDEFGhijklmnop0123456789TheKindIguana\nJumpedOver the angry weird fense as it ran away from the seething moon that was swooping down to scoop it up and bring it to outer space.\nThen a really weird thing happened and suddenly 64 moons were swooping down at the Iguana. It tried to turn and tell them it was scalar, but they didn't care all tried to scoop it at once, which resulted in a massive Iguana lock contention.".as_bytes() + var expected = 373 + var answer = find(haystack, "result".as_bytes()).value() + assert_equal(answer, expected) + + +fn test_spilt_iterator() raises: + var input = "ABCD\tEFGH\tIJKL\nMNOP".as_bytes() + var expected = List( + "ABCD".as_bytes(), "EFGH".as_bytes(), "IJKL\nMNOP".as_bytes() + ) + var output = List[Span[UInt8, StaticConstantOrigin]]() + for value in SplitIterator(input, ord("\t")): + output.append(value) + for i in range(len(expected)): + assert_equal(s(output[i]), s(expected[i]), "Not equal") + + +fn test_spilt_iterator_peek() raises: + var input = "ABCD\tEFGH\tIJKL\nMNOP".as_bytes() + var expected = List( + "ABCD".as_bytes(), "EFGH".as_bytes(), "IJKL\nMNOP".as_bytes() + ) + var iter = SplitIterator(input, ord("\t")) + var first = iter.__next__() + var peek = iter.peek() + var second = iter.__next__() + assert_equal(s(peek.value()), s(second)) + assert_equal(s(first), s(expected[0])) + assert_equal(s(second), s(expected[1])) + + +fn test_spilt_iterator_long() raises: + var input = "ABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ\tABCD\tEFGH\tIJKL\nMNOP\tQRST\tUVWXYZ".as_bytes() + var expected = List( + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + "ABCD".as_bytes(), + "EFGH".as_bytes(), + "IJKL\nMNOP".as_bytes(), + "QRST".as_bytes(), + "UVWXYZ".as_bytes(), + ) + var output = List[Span[UInt8, StaticConstantOrigin]]() + for value in SplitIterator(input, ord("\t")): + output.append(value) + for i in range(len(expected)): + assert_equal(s(output[i]), s(expected[i]), "Not equal") diff --git a/recipes/ExtraMojo/tests/test_file.mojo b/recipes/ExtraMojo/tests/test_file.mojo new file mode 100644 index 0000000..d30326b --- /dev/null +++ b/recipes/ExtraMojo/tests/test_file.mojo @@ -0,0 +1,95 @@ +from memory import Span +from pathlib import Path +from python import Python +from tensor import Tensor +from testing import * + +from ExtraMojo.fs.file import FileReader, read_lines, for_each_line + + +fn s(bytes: Span[UInt8]) -> String: + """Convert bytes to a String.""" + var buffer = String() + buffer.write_bytes(bytes) + return buffer + + +fn create_file(path: String, lines: List[String]) raises: + with open(path, "w") as fh: + for i in range(len(lines)): + fh.write(lines[i]) + fh.write(str("\n")) + + +fn strings_for_writing(size: Int) -> List[String]: + var result = List[String]() + for i in range(size): + result.append("Line: " + str(i) + "X") + return result + + +fn test_read_until(file: Path, expected_lines: List[String]) raises: + var fh = open(file, "r") + var reader = FileReader(fh^, buffer_size=100) + var buffer = List[UInt8]() + var counter = 0 + while reader.read_until(buffer) != 0: + assert_equal(List(expected_lines[counter].as_bytes()), buffer) + counter += 1 + assert_equal(counter, len(expected_lines)) + print("Successful read_until") + + +fn test_read_lines(file: Path, expected_lines: List[String]) raises: + var lines = read_lines(str(file)) + assert_equal(len(lines), len(expected_lines)) + for i in range(0, len(lines)): + assert_equal(lines[i], List(expected_lines[i].as_bytes())) + print("Successful read_lines") + + +fn test_for_each_line(file: Path, expected_lines: List[String]) raises: + var counter = 0 + var found_bad = False + + @parameter + fn inner(buffer: Span[UInt8], start: Int, end: Int) capturing -> None: + if s(buffer[start:end]) != expected_lines[counter]: + found_bad = True + counter += 1 + + for_each_line[inner](str(file)) + assert_false(found_bad) + print("Successful for_each_line") + + +# https://github.com/modularml/mojo/issues/1753 +# fn test_stringify() raises: +# var example = List[Int8]() +# example.append(ord("e")) +# example.append(ord("x")) + +# var container = List[Int8]() +# for i in range(len(example)): +# container.append(example[i]) +# var stringifed = String(container) +# assert_equal("ex", stringifed) +# # Unhandled exception caught during execution: AssertionError: ex is not equal to e + + +fn main() raises: + # TODO: use python to create a tempdir + var tempfile = Python.import_module("tempfile") + var tempdir = tempfile.TemporaryDirectory() + var file = Path(str(tempdir.name)) / "lines.txt" + var strings = strings_for_writing(10000) + create_file(str(file), strings) + + # Tests + test_read_until(str(file), strings) + test_read_lines(str(file), strings) + test_for_each_line(str(file), strings) + + print("SUCCESS") + + _ = tempdir.cleanup() diff --git a/recipes/ExtraMojo/tests/test_regex.mojo b/recipes/ExtraMojo/tests/test_regex.mojo new file mode 100644 index 0000000..d909187 --- /dev/null +++ b/recipes/ExtraMojo/tests/test_regex.mojo @@ -0,0 +1,61 @@ +from ExtraMojo.regex.simple_re import * +from testing import * + + +fn main() raises: + test_start_anchor() + test_end_anchor() + test_dot() + test_star() + test_literal() + test_dot_star() + test_all() + print("SUCCESS") + + +fn test_start_anchor() raises: + var re = "^cat" + assert_true(is_match(re, "cats of a feather")) + assert_false(is_match(re, "bird cats of a cat")) + + +fn test_end_anchor() raises: + var re = "what$" + assert_true(is_match(re, "It is what")) + assert_false(is_match(re, "what is in the box")) + + +fn test_dot() raises: + var re = "w.t" + assert_true(is_match(re, "Is that a witty remark?")) + assert_false(is_match(re, "wt is that what thing there")) + + +fn test_star() raises: + var re = "wha*" + assert_true(is_match(re, "what am I doing here")) + assert_true(is_match(re, "whaaaaaaat am I doing here")) + assert_true(is_match(re, "wht am I doing here")) + assert_false(is_match(re, "wt am I doing here")) + + +fn test_literal() raises: + var re = "ACTG" + assert_true(is_match(re, "TGGGACTGCCCACTG")) + assert_true(is_match(re, "CTGGGACGCCCACTG")) + assert_false(is_match(re, "CTGGGACGCCCACG")) + + +fn test_dot_star() raises: + var re = "STAR.*" + assert_true(is_match(re, "STAR")) + assert_true(is_match(re, "I'M A STAR")) + assert_true(is_match(re, "I'M A STARXXXXXXX")) + assert_true(is_match(re, "I'M A STARS")) + assert_true(is_match(re, "I'M A STAR!!!!!")) + assert_false(is_match(re, "I'm not a STArsss")) + + +fn test_all() raises: + assert_true(is_match("^cat.*$", "catsssssss")) + assert_false(is_match("^cat.*$", "many catsssssss")) From aa2a4e0672fcd263a77005c731857d298c29d683 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Mon, 6 Jan 2025 14:47:31 -0500 Subject: [PATCH 2/8] fix: update name and latest version --- recipes/ExtraMojo/recipe.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml index 840d60a..26df958 100644 --- a/recipes/ExtraMojo/recipe.yaml +++ b/recipes/ExtraMojo/recipe.yaml @@ -1,13 +1,13 @@ context: - version: "0.3.1" + version: "0.6.0" package: - name: "hue" + name: "ExtraMojo" version: ${{ version }} source: - git: https://github.com/ExtraMojo/ExtraMojo.git - rev: 42c0b81ba3cf2bde90fb5fa559089a10e129202e + rev: eaebcaa98c14f840f441dab434d522011d7d4500 build: number: 0 From 411e6b5cac41ef590c012e5c749a1f622c6019a2 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Mon, 6 Jan 2025 14:49:41 -0500 Subject: [PATCH 3/8] fix: update tests --- recipes/ExtraMojo/tests/test_bstr.mojo | 75 ++++++++++++++++++++++++++ recipes/ExtraMojo/tests/test_file.mojo | 15 +++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/recipes/ExtraMojo/tests/test_bstr.mojo b/recipes/ExtraMojo/tests/test_bstr.mojo index 0fc0eda..efb4dac 100644 --- a/recipes/ExtraMojo/tests/test_bstr.mojo +++ b/recipes/ExtraMojo/tests/test_bstr.mojo @@ -4,6 +4,7 @@ from ExtraMojo.bstr.bstr import ( to_ascii_lowercase, to_ascii_uppercase, ) +from ExtraMojo.bstr.memchr import memchr, memchr_wide from memory import Span from testing import * @@ -15,6 +16,69 @@ fn s(bytes: Span[UInt8]) -> String: return buffer +# Sometimes useful for digging into the memchr function +# from ir_utils.dump import dump_ir +# fn main() raises: +# var static_str = "hi" +# dump_ir[ +# find_chr_next_occurrence[__origin_of(static_str)], +# "find_chr_next_occurrence", +# ]() +# test_find_chr_next_occurance() + + +fn test_memchr() raises: + var cases = List[(StringLiteral, Int)]( + ( + "enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy", + 49, + ), + ( + "enlivened,unleavened,Arnulfo's,Unilever's,unloved,Anouilh,analogue,analogy,enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy", + 124, + ), + ) + + for kase in cases: + var index = memchr(kase[][0].as_bytes(), ord("|")) + assert_equal( + index, + kase[][1], + "Expected " + + str(kase[][1]) + + " Found " + + str(index) + + " in " + + kase[][0], + ) + + +fn test_memchr_wide() raises: + var cases = List[(StringLiteral, Int)]( + ( + "enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy", + 49, + ), + ( + "enlivened,unleavened,Arnulfo's,Unilever's,unloved,Anouilh,analogue,analogy,enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy", + 124, + ), + ) + + for kase in cases: + var index = memchr_wide(kase[][0].as_bytes(), ord("|")) + assert_equal( + index, + kase[][1], + "Expected " + + str(kase[][1]) + + " Found " + + str(index) + + " in " + + kase[][0], + ) + + fn test_lowercase_short() raises: var example = List("ABCdefgHIjklmnOPQRSTUVWXYZ".as_bytes()) var answer = "abcdefghijklmnopqrstuvwxyz" @@ -90,6 +154,17 @@ fn test_find_long() raises: assert_equal(answer, expected) +fn test_find_long_variable_start() raises: + var haystack = "ABCDEFGhijklmnop0123456789TheKindIguana\nJumpedOver the angry weird fense as it ran away from the seething moon that was swooping down to scoop it up and bring it to outer space.\nThen a really weird thing happened and suddenly 64 moons were swooping down at the Iguana. It tried to turn and tell them it was scalar, but they didn't care all tried to scoop it at once, which resulted in a massive IguanaZ lock contention.".as_bytes() + for i in range(0, len(haystack)): + var answer = memchr(haystack, ord("Z"), i) + if i <= 401: + assert_equal(401, answer) + else: + assert_equal(-1, answer) + # assert_equal(answer, expected) + + fn test_spilt_iterator() raises: var input = "ABCD\tEFGH\tIJKL\nMNOP".as_bytes() var expected = List( diff --git a/recipes/ExtraMojo/tests/test_file.mojo b/recipes/ExtraMojo/tests/test_file.mojo index d30326b..e8a0608 100644 --- a/recipes/ExtraMojo/tests/test_file.mojo +++ b/recipes/ExtraMojo/tests/test_file.mojo @@ -24,13 +24,13 @@ fn create_file(path: String, lines: List[String]) raises: fn strings_for_writing(size: Int) -> List[String]: var result = List[String]() for i in range(size): - result.append("Line: " + str(i) + "X") + result.append("Line: " + str(i) + "X" + ("-" * 64)) # make lines long return result fn test_read_until(file: Path, expected_lines: List[String]) raises: var fh = open(file, "r") - var reader = FileReader(fh^, buffer_size=100) + var reader = FileReader(fh^, buffer_size=200) var buffer = List[UInt8]() var counter = 0 while reader.read_until(buffer) != 0: @@ -40,6 +40,17 @@ fn test_read_until(file: Path, expected_lines: List[String]) raises: print("Successful read_until") +fn test_context_manager_simple(file: Path, expected_lines: List[String]) raises: + var buffer = List[UInt8]() + var counter = 0 + with FileReader(open(file, "r"), buffer_size=200) as reader: + while reader.read_until(buffer) != 0: + assert_equal(List(expected_lines[counter].as_bytes()), buffer) + counter += 1 + assert_equal(counter, len(expected_lines)) + print("Successful read_until") + + fn test_read_lines(file: Path, expected_lines: List[String]) raises: var lines = read_lines(str(file)) assert_equal(len(lines), len(expected_lines)) From 96ce060ebe7f605c81f4f42920a4b98a28611986 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Thu, 9 Jan 2025 15:15:08 -0500 Subject: [PATCH 4/8] fix: pin max host version --- recipes/ExtraMojo/recipe.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml index 26df958..cf33fdd 100644 --- a/recipes/ExtraMojo/recipe.yaml +++ b/recipes/ExtraMojo/recipe.yaml @@ -15,7 +15,7 @@ build: - mojo package ExtraMojo -o ${{ PREFIX }}/lib/mojo/ExtraMojo.mojopkg requirements: host: - - max + - max ==24.6 run: - ${{ pin_compatible('max') }} From 49148fab13ebacc68cf45265514a1a7a88f869e8 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Sat, 11 Jan 2025 06:46:56 -0500 Subject: [PATCH 5/8] fix: pin max version to 24.6 This also updates ExtraMojo to 0.7.0 which also pins the max version. --- recipes/ExtraMojo/recipe.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml index cf33fdd..5750914 100644 --- a/recipes/ExtraMojo/recipe.yaml +++ b/recipes/ExtraMojo/recipe.yaml @@ -1,5 +1,5 @@ context: - version: "0.6.0" + version: "0.7.0" package: name: "ExtraMojo" @@ -7,7 +7,7 @@ package: source: - git: https://github.com/ExtraMojo/ExtraMojo.git - rev: eaebcaa98c14f840f441dab434d522011d7d4500 + rev: c509406a4951f83b63a2ff09be1f53a67c9ea45e build: number: 0 @@ -17,6 +17,7 @@ requirements: host: - max ==24.6 run: + - max ==24.6 - ${{ pin_compatible('max') }} tests: From 72278f577c33ea60cd12d9f9853ca7c7fe198b1b Mon Sep 17 00:00:00 2001 From: Seth Date: Wed, 15 Jan 2025 16:41:49 -0500 Subject: [PATCH 6/8] fix: max pin version --- recipes/ExtraMojo/recipe.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml index 5750914..c568b34 100644 --- a/recipes/ExtraMojo/recipe.yaml +++ b/recipes/ExtraMojo/recipe.yaml @@ -15,9 +15,9 @@ build: - mojo package ExtraMojo -o ${{ PREFIX }}/lib/mojo/ExtraMojo.mojopkg requirements: host: - - max ==24.6 + - max =24.6 run: - - max ==24.6 + - max =24.6 - ${{ pin_compatible('max') }} tests: @@ -27,6 +27,9 @@ tests: - mojo run tests/test_file.mojo - mojo test tests/test_regex.mojo - mojo test tests/test_bstr.mojo + requirements: + run: + - max =24.6 files: recipe: - tests/test_file.mojo From 1ba850890b93a2c29981649bb1fbbd45823c8f01 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Fri, 17 Jan 2025 14:40:06 -0500 Subject: [PATCH 7/8] fix: update to v0.8.0 and lowercase project name --- recipes/ExtraMojo/recipe.yaml | 14 +++++------ recipes/ExtraMojo/tests/test_file.mojo | 32 +++++++++++++++++++------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml index c568b34..d0663ad 100644 --- a/recipes/ExtraMojo/recipe.yaml +++ b/recipes/ExtraMojo/recipe.yaml @@ -1,13 +1,13 @@ context: - version: "0.7.0" + version: "0.8.0" package: - name: "ExtraMojo" + name: "extramojo" version: ${{ version }} source: - git: https://github.com/ExtraMojo/ExtraMojo.git - rev: c509406a4951f83b63a2ff09be1f53a67c9ea45e + rev: 263006acc60d64a2f21958e9bb6298cc5a0da8c2 build: number: 0 @@ -24,9 +24,9 @@ tests: - script: - if: unix then: - - mojo run tests/test_file.mojo - - mojo test tests/test_regex.mojo - - mojo test tests/test_bstr.mojo + - mojo run -I ${{ PREFIX }}/lib/mojo/ExtraMojo.mojopkg tests/test_file.mojo + - mojo test -I ${{ PREFIX }}/lib/mojo/ExtraMojo.mojopkg tests/test_regex.mojo + - mojo test -I ${{ PREFIX }}/lib/mojo/ExtraMojo.mojopkg tests/test_bstr.mojo requirements: run: - max =24.6 @@ -54,4 +54,4 @@ about: extra: maintainers: - sstadick - project_name: ExtraMojo + project_name: extramojo diff --git a/recipes/ExtraMojo/tests/test_file.mojo b/recipes/ExtraMojo/tests/test_file.mojo index e8a0608..cbce69e 100644 --- a/recipes/ExtraMojo/tests/test_file.mojo +++ b/recipes/ExtraMojo/tests/test_file.mojo @@ -4,7 +4,12 @@ from python import Python from tensor import Tensor from testing import * -from ExtraMojo.fs.file import FileReader, read_lines, for_each_line +from ExtraMojo.fs.file import ( + FileReader, + read_lines, + for_each_line, + BufferedWriter, +) fn s(bytes: Span[UInt8]) -> String: @@ -14,13 +19,6 @@ fn s(bytes: Span[UInt8]) -> String: return buffer -fn create_file(path: String, lines: List[String]) raises: - with open(path, "w") as fh: - for i in range(len(lines)): - fh.write(lines[i]) - fh.write(str("\n")) - - fn strings_for_writing(size: Int) -> List[String]: var result = List[String]() for i in range(size): @@ -88,6 +86,23 @@ fn test_for_each_line(file: Path, expected_lines: List[String]) raises: # # Unhandled exception caught during execution: AssertionError: ex is not equal to e +fn test_buffered_writer(file: Path, expected_lines: List[String]) raises: + var fh = BufferedWriter(open(str(file), "w"), buffer_capacity=128) + for i in range(len(expected_lines)): + fh.write_bytes(expected_lines[i].as_bytes()) + fh.write_bytes("\n".as_bytes()) + fh.close() + + test_read_until(str(file), expected_lines) + + +fn create_file(path: String, lines: List[String]) raises: + with open(path, "w") as fh: + for i in range(len(lines)): + fh.write(lines[i]) + fh.write(str("\n")) + + fn main() raises: # TODO: use python to create a tempdir var tempfile = Python.import_module("tempfile") @@ -100,6 +115,7 @@ fn main() raises: test_read_until(str(file), strings) test_read_lines(str(file), strings) test_for_each_line(str(file), strings) + test_buffered_writer(str(file), strings) print("SUCCESS") From b4e76f1da7680448edf692321d708b1f02c54c33 Mon Sep 17 00:00:00 2001 From: Seth Stadick Date: Tue, 21 Jan 2025 10:49:42 -0500 Subject: [PATCH 8/8] fix: remove trailing whitespace --- recipes/ExtraMojo/recipe.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/ExtraMojo/recipe.yaml b/recipes/ExtraMojo/recipe.yaml index d0663ad..de5a243 100644 --- a/recipes/ExtraMojo/recipe.yaml +++ b/recipes/ExtraMojo/recipe.yaml @@ -54,4 +54,4 @@ about: extra: maintainers: - sstadick - project_name: extramojo + project_name: extramojo