:-module('transducer',[chars_codes/2,transduce/5,transduce_one/2, read_line/3]).
space(X):-
	char_type(X, space).

let(X):-
	char_type(X, alpha).
dig(X):-
	char_type(X, digit).

orn('$').
orn('+').
orn('-').
orn('?').
orn('@').
orn('^').
orn('~').
orn('`').
orn('_').

nonlet(',').
nonlet(';').
nonlet('|').
nonlet('{').
nonlet('}').
nonlet('(').
nonlet(')').
nonlet(':').
nonlet('[').
nonlet(']').
nonlet('!').
nonlet('/').

ldo(none):-fail.

ldo(X):-
	char_type(X, alnum);
	orn(X).

initial(0).

final(5).
final(4):-
	writef("Error:Unexpected end of file").

eof(4).

arc(0, 1, '#':none).
arc(0, 2, '|':none).
arc(0, 3, '"':'"').
arc(0, 5, end_of_file:none).
arc(0, 5, X:Y):-
	final_char(X, Y).
arc(0, 6, X:X):-
	ldo(X).
arc(0, 7, X:X):-
	nonlet(X).
arc(0, 0, X:none):-
	space(X).
arc(1, 5, end_of_file:none).
arc(1, 0, '\n':none).
arc(1, 1, _:none).
arc(2, 4, end_of_file:none).
arc(2, 0, '|':none).
arc(2, 2, _:none).

%this weird part of the automata is because of the hyphen convention
arc(3, 4, end_of_file:none).
arc(3, 0, '"':'"').
arc(3, 3-e, '\\':'\\').
arc(3, 3-a, '-':'\001\').
arc(3, 3-a, X:X).
arc(3-a, 4, end_of_file:none).
arc(3-a, 0, '"':'"').
arc(3-a, 3-b, '-':none).
arc(3-a, 3-e, '\\':'\\').
arc(3-e, 3-a, X:X).
arc(3-a, 3-a, X:X).
arc(3-b, 3-d, '"':'\001\').
arc(3-b, 3-c, none:'-').
arc(3-c, 4, end_of_file:none).
arc(3-c, 3-a, X:X).
arc(3-d, 0, none:'"').

% arc(3, 4, end_of_file:none).
% arc(3, 3-a, '\\':'\\').
% arc(3, 3, '-':'\001\').
% arc(3, 3, X:X).
% arc(3-a, 4, end_of_file:none).

% arc(3-a, 3, X:X).


arc(6, 0, none:none).
arc(6, 7, X:X):-
	nonlet(X).
arc(6, 6, X:X):-
	ldo(X).
arc(6, 6-a, X:none):-
	space(X), not(final_char(X, _)).

%must have only one none:X transition from one node

arc(6-a, 1, '#':none).
%arc(6-a, 2, '|':none).
arc(6-a, 3, '\"':none).
arc(6-a, 5, X:Y):-
	final_char(X, Y).
arc(6-a, 4, end_of_file:none).
arc(6-a, 6-b, none:' ').
arc(6-a, 7, X:X):-
	nonlet(X).
arc(6-a, 6-a, X:none):-
	space(X).

arc(6-b, 4, end_of_file:none).
arc(6-b, 6, X:X):-
	ldo(X).

arc(7, 0, none:none).
arc(7, 6, X:X):-
	ldo(X).
arc(7, 7, X:X):-
	nonlet(X).


chars_codes([],[]).

chars_codes([X|L1],[Y|R1]):-
	char_code(X,Y),
	chars_codes(L1, R1).


transduce(N, _, _, X, Y):-
	final(N),
	(eof(N)->
	    Y = end_of_file;
	    reverse(X, Y)).

transduce(N1, F, [C|L1], L2, Y):-
	(var(C)->
	    get_char(F, C);
	    true),
	(arc(N1, N2, C:V), L = C:V;
	    arc(N1, N2, none:V),L=none:V),
				%	write(L),writef("--"), write(N1), writef("==>"), write(N2), nl,
	traverse(L, [C|L1],NL1, L2, NL2),!,
				%	writef("Success >"),write(N2),writef("=="),write(L),writef("--"), write(NL1), writef("=="), write(NL2), nl,
	transduce(N2, F, NL1, NL2, Y).

				% traverse(+Label, +String1, -NewString1, +String2, -NewString2)

traverse(none:none, S1, S1, S2, S2).

traverse(none:X, S1, S1, S2, [X|S2]).

traverse(X:none, [X|S1], S1, S2, S2).

traverse(X:Y, [X|S1], S1, S2, [Y|S2]).

% parse_file(Name):-
% 	open(Name, read, F),
% 	transduce_wrap(F).

transduce_one(F, L):-
	initial(N),
	transduce(N, F, _, [], L1),
%	write(L1), nl,
	(L1 \== [] ->
	    chars_codes(L1, L);
	    L = end_of_file),!.


read_line(F, [C|L1], T):-
	get_code(F, C),
	( (C\== 10 , C\== -1) ->
	    read_line(F, L1, T);
	    L1 = [],
	    (C == 10 ->
		T = false;
		T = true)).
	    