|
27 | 27 | :- use_module(library(os), [argv/1, setenv/2, shell/1, unsetenv/1, getenv/2]). |
28 | 28 | :- use_module(library(files), [ |
29 | 29 | directory_exists/1, make_directory_path/1, directory_files/2, file_exists/1, |
30 | | - delete_file/1, delete_directory/1 |
| 30 | + delete_file/1, delete_directory/1, working_directory/2 |
31 | 31 | ]). |
32 | 32 | :- use_module(library(dcgs), [phrase/2, phrase/3, ... //0]). % 13211-3 |
33 | 33 | :- use_module(library(charsio), [write_term_to_chars/3]). |
|
356 | 356 | define_script_arg(Arg-Value) :- setenv(Arg, Value). |
357 | 357 | undefine_script_arg(Arg-_) :- unsetenv(Arg). |
358 | 358 |
|
| 359 | +% join_sep_split/3: Monotonic join and split by separator. |
| 360 | +% Implementation by @bakaq from https://github.com/mthom/scryer-prolog/discussions/3121 |
| 361 | +% |
| 362 | +% True when `Joined` is a list consisting of all the lists in `Segments` |
| 363 | +% separated by `Separator`, and `Separator` doesn't appear in any of the |
| 364 | +% lists in `Segments`. Can be used as both a split and a join depending |
| 365 | +% on the mode. |
| 366 | +join_sep_split(Joined, Separator, Segments) :- |
| 367 | + join_sep_split_(Separator, Joined, Segments). |
| 368 | + |
| 369 | +% The empty separator case is just append/2 |
| 370 | +join_sep_split_([], Joined, Segments) :- |
| 371 | + append(Segments, Joined). |
| 372 | +join_sep_split_([S|Ss], Joined, Segments) :- |
| 373 | + join_sep_split(Joined, [], [S|Ss], Segments, []). |
| 374 | + |
| 375 | +% Stuff like this that needs 2 list differences is hard to encode |
| 376 | +% in a DCG in my experience. |
| 377 | +join_sep_split([], [], _, [], []). |
| 378 | +join_sep_split([L0|LT0], Ls, Sep, [Seg|Segs0], Segs) :- |
| 379 | + Ls0 = [L0|LT0], |
| 380 | + next_segment(Ls0, Seg, Sep, Ls1, Reason), |
| 381 | + join_sep_split_(Ls1, Ls, Sep, Segs0, Segs, Reason). |
| 382 | + |
| 383 | +join_sep_split_([], [], _, Segs0, Segs, Reason) :- |
| 384 | + reason_segs(Reason, Segs0, Segs). |
| 385 | +join_sep_split_([L0|LT0], Ls, Sep, Segs0, Segs, _) :- |
| 386 | + join_sep_split([L0|LT0], Ls, Sep, Segs0, Segs). |
| 387 | + |
| 388 | +reason_segs(sep, [[]|Segs], Segs). |
| 389 | +reason_segs(end, Segs, Segs). |
| 390 | + |
| 391 | +next_segment([], [], _, [], end). |
| 392 | +next_segment([L0|Ls0], Seg, Sep, Ls, Reason) :- |
| 393 | + if_( |
| 394 | + starts_with_t(Sep, [L0|Ls0], Ls1), |
| 395 | + (Ls = Ls1, Seg = [], Reason = sep), |
| 396 | + (Seg = [L0|Seg1], next_segment(Ls0, Seg1, Sep, Ls, Reason)) |
| 397 | + ). |
| 398 | + |
| 399 | +starts_with_t([], Ls, Ls, true). |
| 400 | +starts_with_t([S|Ss], Ls0, Ls, T) :- |
| 401 | + starts_with_t_(Ls0, Ls, S, Ss, T). |
| 402 | + |
| 403 | +starts_with_t_([], _, _, _, false). |
| 404 | +starts_with_t_([L|Ls0], Ls, S, Ss, T) :- |
| 405 | + if_( |
| 406 | + S = L, |
| 407 | + starts_with_t(Ss, Ls0, Ls, T), |
| 408 | + T = false |
| 409 | + ). |
| 410 | + |
| 411 | +find_project_root(Root) :- |
| 412 | + working_directory(CWD, CWD), |
| 413 | + find_project_root_from(CWD, Root). |
| 414 | + |
| 415 | +find_project_root_from(Dir, Root) :- |
| 416 | + append(Dir, "/scryer-manifest.pl", ManifestPath), |
| 417 | + ( file_exists(ManifestPath) -> |
| 418 | + Root = Dir |
| 419 | + ; join_sep_split(Dir, "/", Segments), |
| 420 | + append(ParentSegments, [_LastSegment], Segments), |
| 421 | + ParentSegments \= [], |
| 422 | + join_sep_split(ParentDir, "/", ParentSegments), |
| 423 | + find_project_root_from(ParentDir, Root) |
| 424 | + ). |
| 425 | + |
359 | 426 | scryer_path(ScryerPath) :- |
360 | | - ( getenv("SCRYER_PATH", ScryerPath) -> |
361 | | - true |
362 | | - ; ScryerPath = "scryer_libs" |
| 427 | + ( getenv("SCRYER_PATH", EnvPath) -> |
| 428 | + ScryerPath = EnvPath |
| 429 | + ; find_project_root(RootChars), |
| 430 | + append([RootChars, "/scryer_libs"], ScryerPath) |
363 | 431 | ). |
364 | 432 |
|
365 | 433 | % the message sent to the user when a dependency is malformed |
|
0 commit comments