112 lines
3.1 KiB
Prolog
112 lines
3.1 KiB
Prolog
% Tested with SWI-Prolog version 7.1.37
|
|
:- initialization(main).
|
|
|
|
before(Lines) :- Lines = [
|
|
"% Tested with SWI-Prolog version 7.1.37",
|
|
":- initialization(main).",
|
|
"",
|
|
"before(Lines) :- Lines = ["
|
|
].
|
|
|
|
after(Lines) :- Lines = [
|
|
"].",
|
|
"",
|
|
"% replaces quotes by harmless ats",
|
|
"% replaces backslashes by harmless slashes",
|
|
"% replaces linebreaks by harmless sharps",
|
|
"maskCode(34, 64).",
|
|
"maskCode(92, 47).",
|
|
"maskCode(10, 35).",
|
|
"maskCode(X, X).",
|
|
"",
|
|
"% Encodes dangerous characters in a string",
|
|
"encode(D, S) :- ",
|
|
" string_codes(D, DC),",
|
|
" maplist(maskCode, DC, SC),",
|
|
" string_codes(S, SC).",
|
|
"",
|
|
"decode(S, D) :- ",
|
|
" string_codes(S, SC),",
|
|
" maplist(maskCode, DC, SC),",
|
|
" string_codes(D, DC).",
|
|
"",
|
|
"% writes each entry indented by two spaces,",
|
|
"% enclosed in quotes and separated by commas,",
|
|
"% with a newline between the list entries.",
|
|
"mkStringList([],@@).",
|
|
"mkStringList([Single],Out) :-",
|
|
" atomics_to_string([@ /@@, Single, @/@@], Out).",
|
|
"",
|
|
"mkStringList([H|T], Res) :-",
|
|
" mkStringList(T, TailRes),",
|
|
" atomics_to_string([@ /@@, H, @/@,/n@, TailRes], Res).",
|
|
"",
|
|
"quine(Q) :- ",
|
|
" before(BeforeEncoded),",
|
|
" after(AfterEncoded),",
|
|
" maplist(decode, BeforeEncoded, BeforeDecoded),",
|
|
" maplist(decode, AfterEncoded, AfterDecoded),",
|
|
" atomic_list_concat(BeforeDecoded, @/n@, B),",
|
|
" atomic_list_concat(AfterDecoded, @/n@, A),",
|
|
" mkStringList(BeforeEncoded, BeforeData),",
|
|
" mkStringList(AfterEncoded, AfterData),",
|
|
" Center = @/n]./n/nafter(Lines) :- Lines = [/n@,",
|
|
" atomic_list_concat([",
|
|
" B, @/n@, BeforeData, ",
|
|
" Center, ",
|
|
" AfterData, @/n@, A, @/n@",
|
|
" ], Q).",
|
|
"",
|
|
"main :- (quine(Q), write(Q);true),halt.",
|
|
"% line break in the end of file is important"
|
|
].
|
|
|
|
% replaces quotes by harmless ats
|
|
% replaces backslashes by harmless slashes
|
|
% replaces linebreaks by harmless sharps
|
|
maskCode(34, 64).
|
|
maskCode(92, 47).
|
|
maskCode(10, 35).
|
|
maskCode(X, X).
|
|
|
|
% Encodes dangerous characters in a string
|
|
encode(D, S) :-
|
|
string_codes(D, DC),
|
|
maplist(maskCode, DC, SC),
|
|
string_codes(S, SC).
|
|
|
|
decode(S, D) :-
|
|
string_codes(S, SC),
|
|
maplist(maskCode, DC, SC),
|
|
string_codes(D, DC).
|
|
|
|
% writes each entry indented by two spaces,
|
|
% enclosed in quotes and separated by commas,
|
|
% with a newline between the list entries.
|
|
mkStringList([],"").
|
|
mkStringList([Single],Out) :-
|
|
atomics_to_string([" \"", Single, "\""], Out).
|
|
|
|
mkStringList([H|T], Res) :-
|
|
mkStringList(T, TailRes),
|
|
atomics_to_string([" \"", H, "\",\n", TailRes], Res).
|
|
|
|
quine(Q) :-
|
|
before(BeforeEncoded),
|
|
after(AfterEncoded),
|
|
maplist(decode, BeforeEncoded, BeforeDecoded),
|
|
maplist(decode, AfterEncoded, AfterDecoded),
|
|
atomic_list_concat(BeforeDecoded, "\n", B),
|
|
atomic_list_concat(AfterDecoded, "\n", A),
|
|
mkStringList(BeforeEncoded, BeforeData),
|
|
mkStringList(AfterEncoded, AfterData),
|
|
Center = "\n].\n\nafter(Lines) :- Lines = [\n",
|
|
atomic_list_concat([
|
|
B, "\n", BeforeData,
|
|
Center,
|
|
AfterData, "\n", A, "\n"
|
|
], Q).
|
|
|
|
main :- (quine(Q), write(Q);true),halt.
|
|
% line break in the end of file is important
|