:- module(source_processor).
:- export meta_predicate_pattern / 1.
:- export source_open / 4.
:- export source_close / 2.
:- export source_read / 4.
:- export source_open / 3.
:- export struct(source_position(stream, file, line, offset, remaining_files, included_from, options, created_modules, oldcwd, module)).
:- export struct(source_term(term, vars)).
:- tool(source_open / 3,source_open / 4).
:- comment(source_open / 4, hidden).
:- comment(summary, "Tools for processing ECLiPSe sources").
:- comment(date, "$Date: 2006/09/23 01:55:34 $").
:- comment(copyright, "Cisco Systems, Inc").
:- comment(author, "Joachim Schimpf, IC-Parc").
:- comment(eg, "\n    % This can be used as a template for source processing code:\n    % a source file is opened,\n    % every term is read and printed,\n    % then the file is closed\n\n    test(File) :-\n\tsource_open(File, [], SP0),\n\t(\n\t    fromto(begin, _, Class, end),\n\t    fromto(SP0, SP1, SP2, SPend)\n\tdo\n\t    source_read(SP1, SP2, Class, SourceTerm),\n\t    SP1 = source_position{file:F,line:L,module:M},\n\t    printf(\"%w %w:%d %w%n\", [M,F,L,Class]),\n\t    arg(term of source_term, SourceTerm, Term),\n\t    writeclause(Term)\n\t),\n\tsource_close(SPend, []).\n    ").
:- comment(struct(source_term), [summary : "A source term with additional information", fields : [term : "A term read from a source file (a clause, fact, etc)", vars : "A list of the term's variables and their names"], see_also : [readvar / 3]]).
:- comment(struct(source_position), [summary : "Current source position", desc : html("This structure describes a particular position that has been\n    \treached during processing of an ECLiPSe source file. It also describes\n\twhat has to be done when this file is finished. The source_read/3\n\tpredicate reads a term from a given source position and returns\n\tthe new source position after the read."), fields : [stream : "the Eclipse stream being read", file : "this file's canonical file name", line : "this position's line number (integer)", offset : "this position's byte offset (integer)", remaining_files : "list of files still to be included", included_from : "the source_position from which this file is included, or [] if not included", options : "structure describing option settings", created_modules : "list of modules created so far", oldcwd : "current directory before opening this file", module : "read-module at this source position"], see_also : [source_open / 3, source_close / 2, source_read / 4]]).
:- comment(meta_predicate_pattern / 1, [summary : "Describes built-in ECLiPSe meta-predicate patterns", amode : meta_predicate_pattern(?), args : ["Pattern" : "Prolog term describing the meta-predicate pattern"], fail_if : no, resat : yes, desc : html("<P>This predicate returns a structure, Pattern, that describes the control flow through the arguments of a meta-predicate.<P>The functor and arity of Pattern correspond to the functor and arity of the meta-predicate. The arguments are each populated with one of the following atomic descriptors:<DL><DT><PRE>u</PRE><DD>A goal that is unconditionally called whenever the predicate is called.<DT><PRE>e</PRE><DD>A goal whose exit leads unconditionally to the predicate exit.<DT><PRE>s</PRE><DD>A goal whose behaviour is the combination of <TT>u</TT> and <TT>e</TT>.<DT><PRE>:</PRE><DD>A goal that is called directly.<DT><PRE>0</PRE><DD>A goal that is not directly called, but is further processed.<DT><P>An integer</P><DD><P>A goal that is constructed by appending the number of specified arguments.</P><DT><PRE>c</PRE><DD>A clause.<DT><PRE>p</PRE><DD>A PredSpec.<DT><PRE>*</PRE><DD>An argument that is not one of the above.</DL>"), see_also : [instrument / 2, instrument / 3, library(instrument), struct(itemplate)]]).
:- comment(source_close / 2, [summary : "Close an open ECLiPSe source file.", args : ["SourcePos" : "Source position handle", "OptionList" : "List of options, possibly empty"], desc : html("This is used to close an ECLiPSe source file that was\n    previously opened with source_open/3.  It is possible to close\n    before the end of the source is reached. Nesting of included\n    files is properly handled.\n    <P>\n    OptionList can contain the following:\n    <DL>\n    <DT>keep_modules</DT>\n    \t<DD>keep the modules that have been created implicitly during\n\tsource processing (by default they are erased to restore the\n\toriginal state)</DD>\n    </DL>\n    "), see_also : [source_open / 3], amode : source_close(+, +)]).
:- comment(source_open / 3, [summary : "Open an ECLiPSe source code file for subsequent processing", args : ["File" : "Name of source file (Atom or string)", "OptionList" : "List of options, possibly empty", "SourcePos" : "Source position handle"], desc : html("This predicates opens an ECLiPSe source file for subsequent\n    reading with source_read/4. Compared to the standard primitives for\n    reading from a file, this takes care of\n    <UL>\n    <LI>nesting of included files\n    <LI>creating and keeping track of modules\n    <LI>syntax settings\n    <LI>comments (optional)\n    <LI>changing the current directory to the opened file's directory\n    </UL>\n    OptionList can contain the following:\n    <DL>\n    <DT>keep_comments</DT>\n\t<DD>treat comments and spacing between source terms as data\n\t\trather than ignoring it</DD>\n    <DT>no_macro_expansion</DT>\n\t<DD>do not expand term macros (e.g. with/2 and of/2)</DD>\n    <DT>no_clause_expansion</DT>\n\t<DD>do not expand clause macros (e.g. DCGs)</DD>\n    <DT>goal_expansion</DT>\n\t<DD>do inline expansion of goals (only works if clause expansion\n\tis not disabled)</DD>\n    <DT>recreate_modules</DT>\n\t<DD>erase and re-create module when encountering a module directive</DD>\n    </DL>\n    source_open/3 and source_read/4 maintain a 'current source position',\n    which is a structure containing (among others) the following fields:\n    <PRE>\n    :- export struct(source_position(\n\tstream,\t\t\t% Eclipse stream\n\tfile,\t\t\t% canonical file name\n\tline,\t\t\t% integer\n\toffset,\t\t\t% integer\n\tincluded_from,\t\t% source_position or []\n\tmodule,\t\t\t% current source module\n\t...\n    )).\n    </PRE>\n    i.e. information about the module context and the precise location\n    of a source term (e.g. for error messages).\n    <P>\n    "), see_also : [source_close / 2, source_read / 4], amode : source_open(+, +, -)]).
:- comment(source_read / 4, [summary : "Read the next term from an open ECLiPSe source file", args : ["SourcePos" : "Source position handle", "NextPos" : "Source position handle", "Kind" : "kind of source term (atom)", "SourceTerm" : "a source_term structure"], desc : html("This reads the next source term from a source file previously\n    opened with source_open/3. The term at the current source position\n    SourcePos is read, and the next source position is returned for use\n    in subsequent source_read/4 invocations (it is not possible to read\n    twice from the same source position!).\n    <P>\n    The term that has been read is classified into one of the following\n    categories (Kind):\n    <DL>\n    <DT>handled_directive</DT>\n    \t<DD>A directive (a term with functor :-/1) which has already\n\tbeen handled (interpreted by source_read/3). Such directives are:\n\tmodule/1,3, local/1, export/1, reexport/1, use_module/1, op/3,\n\tpragma/1, include/1, ./2</DD>\n    <DT>directive</DT>\n    \t<DD>A directive (a term with functor :-/1) which has not\n\tbeen handled (ignored by source_read/3)</DD>\n    <DT>query</DT>\n    \t<DD>A query (a term with functor ?-/1)</DD>\n    <DT>var</DT>\n    \t<DD>A term consisting of only a variable (very likely an error)</DD>\n    <DT>clause</DT>\n    \t<DD>Any other term (a syntactically valid clause)</DD>\n    <DT>comment</DT>\n    \t<DD>Spacing, layout and comments between source terms\n    \t(only when keep_comments option is in effect)</DD>\n    <DT>end</DT>\n    \t<DD>The end of the (top-level) source file</DD>\n    </DL>\n    The information about the source term itself is returned as a structure\n    <PRE>\n    :- export struct(source_term(\n\tterm,\t\t% the read term itself\n\tvars,\t\t% list of [VarName|Var] pairs (as in readvar/3)\n\t...\n    )).\n    </PRE>\n    For category 'comment', the term is a string containing the comment.\n    For category 'end', the term is the atom end_of_file. In both these\n    cases, vars is the empty list.\n    <P>\n    Notes on module handling:  When source_read/3 encounters a\n    module-directive (which is a handled_directive), the corresponding\n    module is implicitly created (unless it exists already, in which\n    case it is either reused or erased and re-created, depending on\n    the setting of the recreate_modules option), and that\n    module becomes the context module for any subsequently read\n    clauses or directives.  By default, source_close/2 removes these\n    modules again in order to restore the original state.\n    "), see_also : [source_open / 3, source_close / 2, readvar / 3], amode : source_read(+, -, -, -)]).
