#!/usr/bin/env swipl % vim: ft=prolog textwidth=80 tabstop=4 softtabstop=4 shiftwidth=4 expandtab %% :- use_module(library(pure_input)). %%% :- use_module(library(dcg/basics)). :- initialization main. :- multifile prolog:message//1. query_name([H|T]) --> [H], { code_type(H, csymf) }, query_name_next(T). query_name_next([H|T]) --> [H], { H = 0'.; code_type(H, csym) }, !, query_name_next(T). query_name_next([]) --> []. query_default_text([H|T]) --> [H], {\+memberchk(H,`'<>`)}, !, query_default_text(T). query_default_text([]) --> []. query_content([name(Name)|T]) --> query_name(Name), query_content(T). query_content([expr(Expr)|T]) --> `'`, query_awk(Expr), `'`, query_content(T). query_content([query(Query, Filters, Default)|T]) --> query_exp(Query, Filters, Default), query_content(T). query_content([]) --> []. query_default([string(String)|T]) --> awk_string(String), query_default(T). query_default([expr(Expr)|T]) --> `'`, query_awk(Expr), `'`, query_default(T). % query_default([query(Query)|T]) --> query_exp(Query), query_default(T). query_default([query(Query, Filters, Default)|T]) --> query_exp(Query, Filters, Default), query_default(T). query_default([]) --> []. query_exp(Content, Filters, Default) --> `<`, query_content(Content), query_exp_filters(Filters), query_exp_default(Default), `>`. query_exp_filters([H|T]) --> `|`, query_name(H), query_exp_filters(T). query_exp_filters([]) --> []. query_exp_default(none) --> []. query_exp_default(Default) --> `:`, query_default(Default). awk_string(String) --> `"`, awk_string_content(String), `"`. awk_string_content([0'\\,H|T],R) --> [0'\\,H], !, awk_string_content(T,R). awk_string_content([H|T],R) --> [H], { H\=0'\\, H\=0'" }, !, awk_string_content(T,R). awk_string_content(R,R) --> []. awk_string_content(L) --> awk_string_content(L,[]). awk_regex_content([0'\\,H|T],R) --> [0'\\,H], !, awk_regex_content(T,R). awk_regex_content([H|T],R) --> [H], { H\=0'\\, H\=0'/ }, !, awk_regex_content(T,R). awk_regex_content(R,R) --> []. awk_regex_content(L) --> awk_regex_content(L,[]). awk_comment([0'\n|R],R) --> `\n`, !. awk_comment([H|T],R) --> [H], {assertion(H \= 0'\n)}, !, awk_comment(T,R). % awk_comment(L) --> awk_comment(L,[]). awk_code([0'"|T0],R,_,F) --> `"`, !, awk_string_content(T0,T1), `"`, { T1=[0'"|T2] }, awk_code(T2,R,expr,F). awk_code([0'/|T0],R,Prev,F) --> { memberchk(Prev, [delim, op]) }, `/`, !, awk_regex_content(T0,T1), `/`, { T1=[0'/|T2] }, awk_code(T2,R,expr,F). awk_code([0'#|T],R,_,F) --> `#`, !, awk_comment(T,T1), awk_code(T1,R,op,F). awk_code([H|T],R,Prev,F) --> [H], { code_type(H, white) }, !, awk_code(T,R,Prev,F). awk_code([H|T],R,_,F) --> [H], { memberchk(H, `\n,;([{=`) }, !, awk_code(T,R,delim,F). awk_code([H|T],R,_,F) --> [H], { memberchk(H, `!+-*/%^&|?:>~`) }, !, awk_code(T,R,op,F). % awk_code([0'<|T],R,Prev,F) --> % `<`, !, { Prev \= delim }, awk_code(T,R,op,F). awk_code([H|T],R,Prev,F) --> [H], { H \= 0'', H \= 0'@, (H \= 0'< ; Prev \= delim ) }, !, awk_code(T,R,expr,F). awk_code(R,R,L,L) --> []. % awk_code(L) --> awk_code(L,[],delim,_). query_awk([query(Query, Filters, Default)|T],delim) --> query_exp(Query, Filters, Default), query_awk(T, expr). query_awk([code(Code)|T], Last) --> awk_code(Code, [], Last, Next), { Code \= [] }, query_awk(T, Next). query_awk([], _) --> []. query_awk(L) --> query_awk(L,delim). %%% out_awk([code(Code)|T]) --> Code, out_awk(T). out_awk([query(Query, Filters, Default)|T]) --> out_query(Query, Filters, Default), out_awk(T). out_awk([]) --> []. out_query(Query, Filters, none) --> out_filters(Filters, out_f_get(Query)). out_query(Query, Filters, Default) --> `(find(`, out_query_content(Query), `)?`, out_filters(Filters, out_f_found), `:`, out_default(Default), `)`. out_f_get(Query) --> `get(`, out_query_content(Query), `)`. out_f_found --> `found`. out_filters([H|T], Pred) --> H, `(`, out_filters(T, Pred), `)`. out_filters([], Pred) --> call(Pred). out_query_content([name(Name)|T]) --> `"`, Name, `"`, out_query_content(T). out_query_content([expr(Expr)|T]) --> `(`, out_awk(Expr), `)`, out_query_content(T). out_query_content([query(Query, Filters, Default)|T]) --> out_query(Query, Filters, Default), out_query_content(T). out_query_content([]) --> []. out_default([]) --> `""`. out_default([H|T]) --> out_default_aux([H|T]). out_default_aux([string(String)|T]) --> awk_string(String), out_default_aux(T). out_default_aux([expr(Expr)|T]) --> `(`, out_awk(Expr), `)`, out_default_aux(T). out_default_aux([query(Query, Filters, Default)|T]) --> out_query(Query, Filters, Default), out_default_aux(T). out_default_aux([]) --> []. %%% parse_file(InFile) :- ( open(InFile, read, Fd, [encoding(utf8)]), read_stream_to_codes(Fd, Codes) -> true ; throw(read_error(InFile)) ), ( % phrase_from_file(query_awk(Awk), InFile) phrase(query_awk(Awk), Codes) -> true ; throw(parsing_failed(InFile)) ), ( phrase(out_awk(Awk), Out) -> true ; throw(formatting_failed(InFile,Awk)) ), current_stream(1, write, OutStream), set_stream(OutStream, encoding(utf8)), format('~s', [Out]). main :- current_prolog_flag(argv, Argv), main(Argv). main(Args) :- set_prolog_flag(verbose, false), ( (Args=[] -> InFile='/dev/stdin' ; Args=[InFile]) -> catch(parse_file(InFile), E, (print_message(error, E), halt(1))) ; write('usage: query.pl: [filename]\n'), halt(2) ), halt. % current_input(In), set_stream(In, tty(false)), % (phrase_from_stream(query_awk(Awk), In) -> true ; throw(parsing_failed)), % (phrase(out_awk(Awk), Out) -> true ; throw(formatting_failed(Awk))), % format('~s', [Out]). prolog:message(read_error(File)) --> ['Unable to read file: ~w'-[File]]. prolog:message(parsing_failed(File)) --> ['Unable to parse AWK/query file: ~w'-[File]]. prolog:message(formatting_failed(File,_)) --> ['Failed generating AWK code from file: ~w'-[File]].