Skip to content

Commit

Permalink
Fix importing from "../../" (#526)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 8, 2024
1 parent cef2604 commit 2ba2fdd
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 8 deletions.
7 changes: 5 additions & 2 deletions runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.
Expand Down
40 changes: 34 additions & 6 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)) {}
}


Expand Down
5 changes: 5 additions & 0 deletions tests/should_succeed/deep_import.jou
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions tests/should_succeed/imported/level1/level2/deep.jou
Original file line number Diff line number Diff line change
@@ -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})

0 comments on commit 2ba2fdd

Please sign in to comment.