Skip to content
6 changes: 6 additions & 0 deletions examples/add_atom_fun_space.metta
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@


(= (space) my_space_name)

!(add-atom (space) (my test atom))
!(test (match (space) $a $a) (my test atom))
1 change: 1 addition & 0 deletions python/helper.pl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
maybe_enable_silent(false) :- assertz(silent(true)).

set_working_dir(load_metta_file, File) :-
clear_imported_files,
file_directory_name(File, Dir),
retractall(working_dir(_)),
assertz(working_dir(Dir)),
Expand Down
28 changes: 28 additions & 0 deletions python/tests/test_petta.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,31 @@ def test_var_out(petta_instance):
assert (
var == '$b' or (var.startswith('$_') and var[2:].isdigit())
), f"Unexpected variable name '{var}' in result '{result}'"

def test_duplicate_import_is_ignored(petta_instance, tmp_path):
imported_file = tmp_path / "imported_lib.metta"
root_file = tmp_path / "root.metta"

imported_file.write_text("")
root_file.write_text("!(import! &self imported_lib)\n!(import! &self imported_lib)\n")

results = petta_instance.load_metta_file(str(root_file))

assert isinstance(results, list)

def test_nested_relative_imports_use_importer_directory(petta_instance, tmp_path):
main_dir = tmp_path / "main"
libs_dir = tmp_path / "libs"
main_dir.mkdir()
libs_dir.mkdir()

root_file = main_dir / "root.metta"
parent_file = libs_dir / "parent.metta"
sibling_file = libs_dir / "sibling.metta"

root_file.write_text("!(import! &self ../libs/parent)\n!(from-sibling)\n")
parent_file.write_text("!(import! &self sibling)\n")
sibling_file.write_text("(= (from-sibling) 42)\n")

results = petta_instance.load_metta_file(str(root_file))
assert any(result == "42" for result in results), f"Expected sibling import to resolve; got {results}"
16 changes: 14 additions & 2 deletions src/filereader.pl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@
:- use_module(library(pcre)). % re_replace/4
:- current_prolog_flag(argv, Args), ( (memberchk(silent, Args) ; memberchk('--silent', Args) ; memberchk('-s', Args))
-> assertz(silent(true)) ; assertz(silent(false)) ).
:- dynamic working_dir/1.

push_working_dir(Filename) :- file_directory_name(Filename, Dir0),
( absolute_file_name(Dir0, Dir, [file_type(directory), file_errors(fail)])
-> true
; Dir = Dir0 ),
asserta(working_dir(Dir)).

pop_working_dir :- retract(working_dir(_)), !.
pop_working_dir.

%Read Filename into string S and process it (S holds MeTTa code):
load_metta_file(Filename, Results) :- load_metta_file(Filename, Results, '&self').
load_metta_file(Filename, Results, Space) :- read_file_to_string(Filename, S, []),
process_metta_string(S, Results, Space).
load_metta_file(Filename, Results, Space) :- setup_call_cleanup(push_working_dir(Filename),
( read_file_to_string(Filename, S, []),
process_metta_string(S, Results, Space) ),
pop_working_dir).

%Extract function definitions, call invocations, and S-expressions part of &self space:
process_metta_string(S, Results) :- process_metta_string(S, Results, '&self').
Expand Down
1 change: 1 addition & 0 deletions src/main.pl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
mork_test
; Args = [File|_] -> file_directory_name(File, Dir),
assertz(working_dir(Dir)),
clear_imported_files,
load_metta_file(File,Results),
maplist(swrite,Results,ResultsR),
maplist(format("~w~n"), ResultsR)
Expand Down
50 changes: 37 additions & 13 deletions src/metta.pl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
:- use_module(library(apply_macros)).
:- use_module(library(process)).
:- use_module(library(filesex)).
:- multifile prolog:message//1.
:- current_prolog_flag(argv, Argv),
( member(mork, Argv) -> ensure_loaded([parser, translator, specializer, filereader, '../mork_ffi/morkspaces', spaces])
; ensure_loaded([parser, translator, specializer, filereader, spaces])).
Expand Down Expand Up @@ -276,19 +277,42 @@
ensure_metta_ext(Path, Path) :- file_name_extension(_, metta, Path), !.
ensure_metta_ext(Path, PathWithExt) :- file_name_extension(Path, metta, PathWithExt).

'import!'(Space, File, true) :- catch(importer_helper(Space, File), _, fail).
importer_helper(Space, File) :- atom_string(File, SFile),
working_dir(Base),
( file_name_extension(ModPath, 'py', SFile)
-> absolute_file_name(SFile, Path, [relative_to(Base)]),
file_directory_name(Path, Dir),
file_base_name(ModPath, ModuleName),
py_call(sys:path:append(Dir), _),
py_call(builtins:'__import__'(ModuleName), _)
; ( Path = SFile ; atomic_list_concat([Base, '/', SFile], Path) ),
ensure_metta_ext(Path, PathWithExt),
exists_file(PathWithExt), !,
load_metta_file(PathWithExt, _, Space) ).
:- dynamic imported_file/1.

clear_imported_files :-
retractall(imported_file(_)).

resolve_import_path(Base, File, AbsPath) :-
absolute_file_name(File, AbsPath, [relative_to(Base), access(read), file_errors(fail)]),
!.
resolve_import_path(_, File, AbsPath) :-
absolute_file_name(File, AbsPath, [access(read), file_errors(fail)]).

absolute_import_path(Base, File, AbsPath, python) :-
file_name_extension(_, py, File),
!,
resolve_import_path(Base, File, AbsPath).
absolute_import_path(Base, File, AbsPath, metta) :-
ensure_metta_ext(File, FileWithExt),
resolve_import_path(Base, FileWithExt, AbsPath).

'import!'(Space, File, true) :-
importer_helper(Space, File).
importer_helper(Space, File) :-
atom_string(File, SFile),
working_dir(Base),
absolute_import_path(Base, SFile, AbsPath, ImportType),
( imported_file(AbsPath)
-> true
; ( ImportType = python
-> file_directory_name(AbsPath, Dir),
file_base_name(AbsPath, BaseName),
file_name_extension(ModuleName, _, BaseName),
py_call(sys:path:append(Dir), _),
py_call(builtins:'__import__'(ModuleName), _)
; load_metta_file(AbsPath, _, Space)
),
assertz(imported_file(AbsPath)) ).

:- dynamic translator_rule/1.
'add-translator-rule!'(HV, true) :- ( translator_rule(HV)
Expand Down
7 changes: 4 additions & 3 deletions src/translator.pl
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,10 @@
( FreeVars == [] -> Out = F
; Out = partial(F, FreeVars) )
%--- Spaces ---:
; ( HV == 'add-atom' ; HV == 'remove-atom' ), T = [_,_] -> append(T, [Out], RawArgs),
Goal =.. [HV|RawArgs],
append(GsH, [Goal], Goals)
; ( HV == 'add-atom' ; HV == 'remove-atom' ), T = [Space,Atom] ->
translate_expr(Space, G1, S),
Goal =.. [HV,S,Atom,Out],
append([GsH,G1,[Goal]], Goals)
; HV == match, T = [Space, Pattern, Body] -> translate_expr(Space, G1, S),
translate_expr(Body, GsB, Out),
append(G1, [match(S, Pattern, Out, Out)], G2),
Expand Down
Loading