diff --git a/runtests.sh b/runtests.sh index fa76b3c1..884c94b2 100755 --- a/runtests.sh +++ b/runtests.sh @@ -202,10 +202,13 @@ function run_test() # jou flags start with space when non-empty command="$command$jou_flags" - if [[ "$joufile" =~ ^examples/aoc ]]; then + if [[ "$joufile" =~ ^examples/aoc ]] || [[ $joufile == *double_dotdot_import* ]]; then # AoC files use fopen("sampleinput.txt", "r"). # We don't do this for all files, because I like relative paths in error messages. # jou_flags starts with a space whenever it isn't empty. + # + # Also, double_dotdot_import test had a bug that was reproducible only with + # relative path. command="cd $(dirname $joufile) && $command $(basename $joufile)" else command="$command $joufile" @@ -236,7 +239,7 @@ function run_test() counter=0 skipped=0 -for joufile in examples/*.jou examples/aoc*/day*/part*.jou tests/*/*.jou; do +for joufile in examples/*.jou examples/aoc*/day*/part*.jou tests/*/*.jou tests/should_succeed/double_dotdot_import/*/*.jou; do if ! [[ $joufile == *"$file_filter"* ]]; then # Skip silently, without showing that this is skipped. # This produces less noisy output when you select only a few tests. diff --git a/src/util.c b/src/util.c index e965aa52..42790707 100644 --- a/src/util.c +++ b/src/util.c @@ -35,6 +35,39 @@ void trim_whitespace(char *s) delete_slice(s, start); } +/* +In paths, "foo/../" is usually unnecessary, because it goes to a folder "foo" and then +immediately back up. However, it makes a difference in a few cases: + +1. folder "foo" doesn't exist +2. folder "foo" is a symlink to a different place +3. we are actually looking at "../../" (so "foo" is "..") + +Special cases 1 and 2 are not relevant in the Jou compiler, but special case 3 is relevant +when importing from "../../file.jou" (bad style, but should work). + +This function deletes one unnecessary "foo/../", and may be called recursively to delete +all of them. +*/ +static bool simplify_dotdot_once(char *path) +{ + assert(!strstr(path, "\\")); // should be already taken care of when calling this + + for (char *p = strstr(path, "/../"); p != NULL; p = strstr(p+1, "/../")) { + char *end = p+4; + char *start = p; + while (start > path && start[-1] != '/') + start--; + + if (strncmp(start, "../", 3)) { + delete_slice(start, end); + return true; + } + } + + return false; +} + void simplify_path(char *path) { #ifdef _WIN32 @@ -52,12 +85,7 @@ void simplify_path(char *path) delete_slice(p, p+2); // Delete unnecessary ".." components. - while ((p = strstr(path, "/../"))) { - char *delstart = p; - while (delstart > path && delstart[-1] != '/') - delstart--; - delete_slice(delstart, p+4); - } + while (simplify_dotdot_once(path)) {} } diff --git a/tests/should_succeed/deep_import.jou b/tests/should_succeed/deep_import.jou new file mode 100644 index 00000000..1ea464c7 --- /dev/null +++ b/tests/should_succeed/deep_import.jou @@ -0,0 +1,5 @@ +import "./imported/level1/level2/deep.jou" + +def main() -> int: + do_deep_stuff() # Output: Deep stuff... Bar Bar 123 456 + return 0 diff --git a/tests/should_succeed/double_dotdot_import/more_nesting/double_dotdot_import.jou b/tests/should_succeed/double_dotdot_import/more_nesting/double_dotdot_import.jou new file mode 100644 index 00000000..2baf656e --- /dev/null +++ b/tests/should_succeed/double_dotdot_import/more_nesting/double_dotdot_import.jou @@ -0,0 +1,9 @@ +# This file tests "../../" imports, which were previously broken. + +import "stdlib/io.jou" +import "../../imported/bar.jou" + +def main() -> int: + printf("It runs\n") # Output: It runs + bar(Point{x = 123, y = 456}) # Output: Bar Bar 123 456 + return 0 diff --git a/tests/should_succeed/imported/level1/level2/deep.jou b/tests/should_succeed/imported/level1/level2/deep.jou new file mode 100644 index 00000000..9f0faf7c --- /dev/null +++ b/tests/should_succeed/imported/level1/level2/deep.jou @@ -0,0 +1,8 @@ +# This file tests "../../" imports, which were previously broken. + +import "stdlib/io.jou" +import "../../bar.jou" + +def do_deep_stuff() -> None: + printf("Deep stuff... ") + bar(Point{x = 123, y = 456})