diff --git a/CHANGES.md b/CHANGES.md index bcf936071..a3c8db84e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,9 @@ +# UNRELEASED + +- Command line: + - Deprecate `-test` + - New `-main` to run `main` (with no arguments) + # v1.16.8 (November 2022) Requires Menhir 20211230 and OCaml 4.08 or above. diff --git a/Makefile b/Makefile index e84fe9f4e..1c31fd13f 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,11 @@ help: @echo ' menhir-complete-errormsgs run when updating the grammar' @echo ' menhir-strip-errormsgs remove comments from error message file' @echo + @echo 'Doc and release targets:' + @echo + @echo ' doc-build builds all doc in docs/build/' + @echo ' release calls dune-release and uploads the doc' + @echo INSTALL=_build/install/default BUILD=_build/default diff --git a/docs/base/cmdline.rst b/docs/base/cmdline.rst new file mode 100644 index 000000000..6ca9b87f3 --- /dev/null +++ b/docs/base/cmdline.rst @@ -0,0 +1,49 @@ +Running a program +================= + +The :console:`elpi` command line utility can run a query against a program. +The standard query is :elpi:`main` for which one can use the dedicated +command line option :console:`-main`. + +.. elpi:: cmdline_example.elpi + :nostderr: + +Custom entry point +++++++++++++++++++ + +.. elpi:: cmdline_example.elpi + :cmdline: -exec mypred -- 1 a "hi there" + :nostderr: + :nocode: + +Interactive use ++++++++++++++++ + +.. elpi:: cmdline_interactive.elpi + :cmdline: + +Typing :elpi:`guess X.` followed by enter runs the query. + +.. elpi:: cmdline_interactive.elpi + :stdin: guess X.\ny\n + :nostderr: + :cmdline: + :nocode: + +Command line options +==================== + +.. elpi:: + :cmdline: -h + +Debug parsing ++++++++++++++ + +.. elpi:: + :stdin: a ++-> b **? c + :cmdline: -parse-term + :nocode: + +Tracing options ++++++++++++++++ + diff --git a/docs/base/cmdline_example.elpi b/docs/base/cmdline_example.elpi new file mode 100644 index 000000000..f0effd949 --- /dev/null +++ b/docs/base/cmdline_example.elpi @@ -0,0 +1,4 @@ +pred mypred i:list string. +mypred Args :- print Args. + +main :- print "Hello world!". diff --git a/docs/base/cmdline_interactive.elpi b/docs/base/cmdline_interactive.elpi new file mode 100644 index 000000000..b00b941ab --- /dev/null +++ b/docs/base/cmdline_interactive.elpi @@ -0,0 +1,3 @@ +pred guess o:int. +guess 46. +guess 42. diff --git a/docs/base/index.rst b/docs/base/index.rst index 9d3881d6c..b56dfe89c 100644 --- a/docs/base/index.rst +++ b/docs/base/index.rst @@ -6,12 +6,12 @@ Welcome to Elpi's documentation! ================================ -.. .. toctree: -.. :maxdepth: 2 -.. :caption: Contents: -.. -.. about -.. playground +.. toctree:: + :maxdepth: 2 + :caption: Usage: + + cmdline + trace-browser .. toctree:: :maxdepth: 2 diff --git a/docs/base/playground.rst b/docs/base/playground.rst index 91f67b44a..d23c9214f 100644 --- a/docs/base/playground.rst +++ b/docs/base/playground.rst @@ -79,151 +79,142 @@ Regexp Matching This ``elpi`` directive should pass validation: -.. code-block:: console - - .. elpi:: ./a.elpi - :assert: V = s \(.*\) - .. elpi:: ./a.elpi :assert: V = s \(.*\) + :nostderr: This one should fail validation, only a message stating the regexp matching error will be printed: -.. code-block:: console - - .. elpi:: ./a.elpi - :assert: /(?!)/ - -.. elpi:: ./a.elpi - :assert: /(?!)/ +.. .. elpi:: ./a.elpi +.. :assert: /(?!)/ Test Bed -------- .. elpi:: ../../tests/sources/accumulate_twice1.elpi -.. elpi:: ../../tests/sources/accumulate_twice2.elpi -.. elpi:: ../../tests/sources/accumulated.elpi -.. elpi:: ../../tests/sources/ackermann.elpi -.. elpi:: ../../tests/sources/asclause.elpi -.. elpi:: ../../tests/sources/beta.elpi -.. elpi:: ../../tests/sources/block.elpi -.. elpi:: ../../tests/sources/chr.elpi -.. elpi:: ../../tests/sources/chrGCD.elpi -.. elpi:: ../../tests/sources/chrLEQ.elpi -.. elpi:: ../../tests/sources/chr_nokey.elpi -.. elpi:: ../../tests/sources/chr_nokey2.elpi -.. elpi:: ../../tests/sources/chr_not_clique.elpi -.. elpi:: ../../tests/sources/chr_sem.elpi -.. elpi:: ../../tests/sources/conj2.elpi -.. elpi:: ../../tests/sources/ctx_loading.elpi -.. elpi:: ../../tests/sources/cut.elpi -.. elpi:: ../../tests/sources/cut2.elpi -.. elpi:: ../../tests/sources/cut3.elpi -.. elpi:: ../../tests/sources/cut4.elpi -.. elpi:: ../../tests/sources/cut5.elpi -.. elpi:: ../../tests/sources/cut6.elpi -.. elpi:: ../../tests/sources/deep_indexing.elpi -.. elpi:: ../../tests/sources/discard.elpi -.. elpi:: ../../tests/sources/elpi_only_llam.elpi -.. elpi:: ../../tests/sources/end_comment.elpi -.. elpi:: ../../tests/sources/eta.elpi -.. elpi:: ../../tests/sources/eta_as.elpi -.. elpi:: ../../tests/sources/even-odd.elpi -.. elpi:: ../../tests/sources/findall.elpi -.. elpi:: ../../tests/sources/fragment_exit.elpi -.. elpi:: ../../tests/sources/fragment_exit2.elpi -.. elpi:: ../../tests/sources/fragment_exit3.elpi -.. elpi:: ../../tests/sources/general_case.elpi -.. elpi:: ../../tests/sources/general_case2.elpi -.. elpi:: ../../tests/sources/general_case3.elpi -.. elpi:: ../../tests/sources/hc_interp.elpi -.. elpi:: ../../tests/sources/hdclause.elpi -.. elpi:: ../../tests/sources/heap_discard.elpi -.. elpi:: ../../tests/sources/ho.elpi -.. elpi:: ../../tests/sources/hollight.elpi -.. elpi:: ../../tests/sources/hollight_legacy.elpi -.. elpi:: ../../tests/sources/hyp_uvar.elpi -.. elpi:: ../../tests/sources/impl.elpi -.. elpi:: ../../tests/sources/impl2.elpi -.. elpi:: ../../tests/sources/index2.elpi -.. elpi:: ../../tests/sources/io_colon.elpi -.. elpi:: ../../tests/sources/lambda.elpi -.. elpi:: ../../tests/sources/lambda2.elpi -.. elpi:: ../../tests/sources/lambda3.elpi -.. elpi:: ../../tests/sources/list_as_conj.elpi -.. elpi:: ../../tests/sources/list_comma.elpi -.. elpi:: ../../tests/sources/llam.elpi -.. elpi:: ../../tests/sources/llamchr.elpi -.. elpi:: ../../tests/sources/map.elpi -.. elpi:: ../../tests/sources/map_list.elpi -.. elpi:: ../../tests/sources/map_list_opt.elpi -.. elpi:: ../../tests/sources/name_builtin.elpi -.. elpi:: ../../tests/sources/named_clauses00.elpi -.. elpi:: ../../tests/sources/named_clauses01.elpi -.. elpi:: ../../tests/sources/named_clauses02.elpi -.. elpi:: ../../tests/sources/namespaces00.elpi -.. elpi:: ../../tests/sources/namespaces01.elpi -.. elpi:: ../../tests/sources/namespaces02.elpi -.. elpi:: ../../tests/sources/namespaces03.elpi -.. elpi:: ../../tests/sources/nil_cons.elpi -.. elpi:: ../../tests/sources/notation.elpi -.. elpi:: ../../tests/sources/notation_error.elpi -.. elpi:: ../../tests/sources/notation_legacy.elpi -.. elpi:: ../../tests/sources/patternunif.elpi -.. elpi:: ../../tests/sources/patternunif2.elpi -.. elpi:: ../../tests/sources/pi.elpi -.. elpi:: ../../tests/sources/pi3.elpi -.. elpi:: ../../tests/sources/pi5.elpi -.. elpi:: ../../tests/sources/pnf.elpi -.. elpi:: ../../tests/sources/polymorphic_variants.elpi -.. elpi:: ../../tests/sources/printer.elpi -.. elpi:: ../../tests/sources/queens.elpi -.. elpi:: ../../tests/sources/quote_syntax.elpi -.. elpi:: ../../tests/sources/random.elpi -.. elpi:: ../../tests/sources/reduce_cbn.elpi -.. elpi:: ../../tests/sources/reduce_cbv.elpi -.. elpi:: ../../tests/sources/restriction.elpi -.. elpi:: ../../tests/sources/restriction3.elpi -.. elpi:: ../../tests/sources/restriction4.elpi -.. elpi:: ../../tests/sources/restriction5.elpi -.. elpi:: ../../tests/sources/restriction6.elpi -.. elpi:: ../../tests/sources/rev.elpi -.. elpi:: ../../tests/sources/rev14.elpi -.. elpi:: ../../tests/sources/same_term.elpi -.. elpi:: ../../tests/sources/self_assignment.elpi -.. elpi:: ../../tests/sources/set.elpi -.. elpi:: ../../tests/sources/shorten.elpi -.. elpi:: ../../tests/sources/shorten2.elpi -.. elpi:: ../../tests/sources/shorten_aux.elpi -.. elpi:: ../../tests/sources/shorten_aux2.elpi -.. elpi:: ../../tests/sources/shorten_builtin.elpi -.. elpi:: ../../tests/sources/shorten_trie.elpi -.. elpi:: ../../tests/sources/spill_and.elpi -.. elpi:: ../../tests/sources/spill_impl.elpi -.. elpi:: ../../tests/sources/spill_lam.elpi -.. elpi:: ../../tests/sources/trace.elpi -.. elpi:: ../../tests/sources/trace2.elpi -.. elpi:: ../../tests/sources/trace_chr.elpi -.. elpi:: ../../tests/sources/trace_cut.elpi -.. elpi:: ../../tests/sources/trace_findall.elpi -.. elpi:: ../../tests/sources/trail.elpi -.. elpi:: ../../tests/sources/typeabbrv.elpi -.. elpi:: ../../tests/sources/typeabbrv1.elpi -.. elpi:: ../../tests/sources/typeabbrv10.elpi -.. elpi:: ../../tests/sources/typeabbrv11.elpi -.. elpi:: ../../tests/sources/typeabbrv12.elpi -.. elpi:: ../../tests/sources/typeabbrv2.elpi -.. elpi:: ../../tests/sources/typeabbrv3.elpi -.. elpi:: ../../tests/sources/typeabbrv4.elpi -.. elpi:: ../../tests/sources/typeabbrv5.elpi -.. elpi:: ../../tests/sources/typeabbrv6.elpi -.. elpi:: ../../tests/sources/typeabbrv7.elpi -.. elpi:: ../../tests/sources/typeabbrv8.elpi -.. elpi:: ../../tests/sources/typeabbrv9.elpi -.. elpi:: ../../tests/sources/uminus.elpi -.. elpi:: ../../tests/sources/uvar_chr.elpi -.. elpi:: ../../tests/sources/var.elpi -.. elpi:: ../../tests/sources/variadic_declare_constraints.elpi -.. elpi:: ../../tests/sources/w.elpi -.. elpi:: ../../tests/sources/w_legacy.elpi -.. elpi:: ../../tests/sources/zebra.elpi \ No newline at end of file +.. .. elpi:: ../../tests/sources/accumulate_twice2.elpi +.. .. elpi:: ../../tests/sources/accumulated.elpi +.. .. elpi:: ../../tests/sources/ackermann.elpi +.. .. elpi:: ../../tests/sources/asclause.elpi +.. .. elpi:: ../../tests/sources/beta.elpi +.. .. elpi:: ../../tests/sources/block.elpi +.. .. elpi:: ../../tests/sources/chr.elpi +.. .. elpi:: ../../tests/sources/chrGCD.elpi +.. .. elpi:: ../../tests/sources/chrLEQ.elpi +.. .. elpi:: ../../tests/sources/chr_nokey.elpi +.. .. elpi:: ../../tests/sources/chr_nokey2.elpi +.. .. elpi:: ../../tests/sources/chr_not_clique.elpi +.. .. elpi:: ../../tests/sources/chr_sem.elpi +.. .. elpi:: ../../tests/sources/conj2.elpi +.. .. elpi:: ../../tests/sources/ctx_loading.elpi +.. .. elpi:: ../../tests/sources/cut.elpi +.. .. elpi:: ../../tests/sources/cut2.elpi +.. .. elpi:: ../../tests/sources/cut3.elpi +.. .. elpi:: ../../tests/sources/cut4.elpi +.. .. elpi:: ../../tests/sources/cut5.elpi +.. .. elpi:: ../../tests/sources/cut6.elpi +.. .. elpi:: ../../tests/sources/deep_indexing.elpi +.. .. elpi:: ../../tests/sources/discard.elpi +.. .. elpi:: ../../tests/sources/elpi_only_llam.elpi +.. .. elpi:: ../../tests/sources/end_comment.elpi +.. .. elpi:: ../../tests/sources/eta.elpi +.. .. elpi:: ../../tests/sources/eta_as.elpi +.. .. elpi:: ../../tests/sources/even-odd.elpi +.. .. elpi:: ../../tests/sources/findall.elpi +.. .. elpi:: ../../tests/sources/fragment_exit.elpi +.. .. elpi:: ../../tests/sources/fragment_exit2.elpi +.. .. elpi:: ../../tests/sources/fragment_exit3.elpi +.. .. elpi:: ../../tests/sources/general_case.elpi +.. .. elpi:: ../../tests/sources/general_case2.elpi +.. .. elpi:: ../../tests/sources/general_case3.elpi +.. .. elpi:: ../../tests/sources/hc_interp.elpi +.. .. elpi:: ../../tests/sources/hdclause.elpi +.. .. elpi:: ../../tests/sources/heap_discard.elpi +.. .. elpi:: ../../tests/sources/ho.elpi +.. .. elpi:: ../../tests/sources/hollight.elpi +.. .. elpi:: ../../tests/sources/hollight_legacy.elpi +.. .. elpi:: ../../tests/sources/hyp_uvar.elpi +.. .. elpi:: ../../tests/sources/impl.elpi +.. .. elpi:: ../../tests/sources/impl2.elpi +.. .. elpi:: ../../tests/sources/index2.elpi +.. .. elpi:: ../../tests/sources/io_colon.elpi +.. .. elpi:: ../../tests/sources/lambda.elpi +.. .. elpi:: ../../tests/sources/lambda2.elpi +.. .. elpi:: ../../tests/sources/lambda3.elpi +.. .. elpi:: ../../tests/sources/list_as_conj.elpi +.. .. elpi:: ../../tests/sources/list_comma.elpi +.. .. elpi:: ../../tests/sources/llam.elpi +.. .. elpi:: ../../tests/sources/llamchr.elpi +.. .. elpi:: ../../tests/sources/map.elpi +.. .. elpi:: ../../tests/sources/map_list.elpi +.. .. elpi:: ../../tests/sources/map_list_opt.elpi +.. .. elpi:: ../../tests/sources/name_builtin.elpi +.. .. elpi:: ../../tests/sources/named_clauses00.elpi +.. .. elpi:: ../../tests/sources/named_clauses01.elpi +.. .. elpi:: ../../tests/sources/named_clauses02.elpi +.. .. elpi:: ../../tests/sources/namespaces00.elpi +.. .. elpi:: ../../tests/sources/namespaces01.elpi +.. .. elpi:: ../../tests/sources/namespaces02.elpi +.. .. elpi:: ../../tests/sources/namespaces03.elpi +.. .. elpi:: ../../tests/sources/nil_cons.elpi +.. .. elpi:: ../../tests/sources/notation.elpi +.. .. elpi:: ../../tests/sources/notation_error.elpi +.. .. elpi:: ../../tests/sources/notation_legacy.elpi +.. .. elpi:: ../../tests/sources/patternunif.elpi +.. .. elpi:: ../../tests/sources/patternunif2.elpi +.. .. elpi:: ../../tests/sources/pi.elpi +.. .. elpi:: ../../tests/sources/pi3.elpi +.. .. elpi:: ../../tests/sources/pi5.elpi +.. .. elpi:: ../../tests/sources/pnf.elpi +.. .. elpi:: ../../tests/sources/polymorphic_variants.elpi +.. .. elpi:: ../../tests/sources/printer.elpi +.. .. elpi:: ../../tests/sources/queens.elpi +.. .. elpi:: ../../tests/sources/quote_syntax.elpi +.. .. elpi:: ../../tests/sources/random.elpi +.. .. elpi:: ../../tests/sources/reduce_cbn.elpi +.. .. elpi:: ../../tests/sources/reduce_cbv.elpi +.. .. elpi:: ../../tests/sources/restriction.elpi +.. .. elpi:: ../../tests/sources/restriction3.elpi +.. .. elpi:: ../../tests/sources/restriction4.elpi +.. .. elpi:: ../../tests/sources/restriction5.elpi +.. .. elpi:: ../../tests/sources/restriction6.elpi +.. .. elpi:: ../../tests/sources/rev.elpi +.. .. elpi:: ../../tests/sources/rev14.elpi +.. .. elpi:: ../../tests/sources/same_term.elpi +.. .. elpi:: ../../tests/sources/self_assignment.elpi +.. .. elpi:: ../../tests/sources/set.elpi +.. .. elpi:: ../../tests/sources/shorten.elpi +.. .. elpi:: ../../tests/sources/shorten2.elpi +.. .. elpi:: ../../tests/sources/shorten_aux.elpi +.. .. elpi:: ../../tests/sources/shorten_aux2.elpi +.. .. elpi:: ../../tests/sources/shorten_builtin.elpi +.. .. elpi:: ../../tests/sources/shorten_trie.elpi +.. .. elpi:: ../../tests/sources/spill_and.elpi +.. .. elpi:: ../../tests/sources/spill_impl.elpi +.. .. elpi:: ../../tests/sources/spill_lam.elpi +.. .. elpi:: ../../tests/sources/trace.elpi +.. .. elpi:: ../../tests/sources/trace2.elpi +.. .. elpi:: ../../tests/sources/trace_chr.elpi +.. .. elpi:: ../../tests/sources/trace_cut.elpi +.. .. elpi:: ../../tests/sources/trace_findall.elpi +.. .. elpi:: ../../tests/sources/trail.elpi +.. .. elpi:: ../../tests/sources/typeabbrv.elpi +.. .. elpi:: ../../tests/sources/typeabbrv1.elpi +.. .. elpi:: ../../tests/sources/typeabbrv10.elpi +.. .. elpi:: ../../tests/sources/typeabbrv11.elpi +.. .. elpi:: ../../tests/sources/typeabbrv12.elpi +.. .. elpi:: ../../tests/sources/typeabbrv2.elpi +.. .. elpi:: ../../tests/sources/typeabbrv3.elpi +.. .. elpi:: ../../tests/sources/typeabbrv4.elpi +.. .. elpi:: ../../tests/sources/typeabbrv5.elpi +.. .. elpi:: ../../tests/sources/typeabbrv6.elpi +.. .. elpi:: ../../tests/sources/typeabbrv7.elpi +.. .. elpi:: ../../tests/sources/typeabbrv8.elpi +.. .. elpi:: ../../tests/sources/typeabbrv9.elpi +.. .. elpi:: ../../tests/sources/uminus.elpi +.. .. elpi:: ../../tests/sources/uvar_chr.elpi +.. .. elpi:: ../../tests/sources/var.elpi +.. .. elpi:: ../../tests/sources/variadic_declare_constraints.elpi +.. .. elpi:: ../../tests/sources/w.elpi +.. .. elpi:: ../../tests/sources/w_legacy.elpi +.. .. elpi:: ../../tests/sources/zebra.elpi \ No newline at end of file diff --git a/docs/base/trace-browser.gif b/docs/base/trace-browser.gif new file mode 100644 index 000000000..079912858 Binary files /dev/null and b/docs/base/trace-browser.gif differ diff --git a/docs/base/trace-browser.rst b/docs/base/trace-browser.rst new file mode 100644 index 000000000..ca738ccc8 --- /dev/null +++ b/docs/base/trace-browser.rst @@ -0,0 +1,6 @@ +Trace Browser +============= + +.. image:: trace-browser.gif + :width: 800 + :alt: Trace browsing in action diff --git a/docs/base/trace-browser_example.elpi b/docs/base/trace-browser_example.elpi new file mode 100644 index 000000000..454e36d23 --- /dev/null +++ b/docs/base/trace-browser_example.elpi @@ -0,0 +1,5 @@ +pred p i:int. +p X :- X > 2. +p 1. + +main :- p 1. \ No newline at end of file diff --git a/docs/engine/engine.py b/docs/engine/engine.py index 5424b0338..a4b6975e6 100644 --- a/docs/engine/engine.py +++ b/docs/engine/engine.py @@ -1,23 +1,65 @@ #!/usr/bin/env python3 -import os, sys, in_place, pathlib, subprocess, re +# Available options ######################################################### + +atext = ':assert:' # regexp - fail if not matched +noerrtext = ':nostderr:' # - omit stderr, by default show +stdintext = ':stdin:' # - specify stdin +nocodetext = ':nocode:' # - omit code, by default show +cmdlinetext = ':cmdline:' # arguments to elpi - override default which is -main + +options = [atext , noerrtext, nocodetext, cmdlinetext, stdintext ] +initial_option_status = ('' , False, False, ['-main'] , '' ) + +############################################################################# + +import os, sys, in_place, pathlib, subprocess, re, shlex, copy def check(input, expression): - pattern = re.compile(expression, re.IGNORECASE) - return pattern.match(input) - -def exec(path, base_path): - file = base_path / path - print(' - Executing elpi on', file.as_posix().rstrip()) - elpi = subprocess.Popen(['dune', 'exec', 'elpi', '--', '-test', file.as_posix()[:-1]], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - output, errors = elpi.communicate() + if expression == '': + return True + pattern = re.compile('.*' + expression, re.IGNORECASE | re.MULTILINE | re.DOTALL) + rc = pattern.match(input) + return rc + +def run(o, path, base_path): + _, _, _, cmd, s = o + + if len(path) > 0: + file = [(base_path / path).as_posix()] + else: + file = [] + + exec = ['dune', 'exec', 'elpi', '--'] + file + cmd + print(' - Executing: echo \''+s+'\' | '+' '.join(exec)) + elpi = subprocess.Popen(exec, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, text=True) + output, errors = elpi.communicate(input=(s.replace('\\n','\n') + '\n')) elpi.wait() return output, errors +def parse_option(o, line): + a,e,x,c,i = o + if line.startswith(atext): + a = line[len(atext):].strip() + return (a,e,x,c,i) + elif line.startswith(noerrtext): + e = True + return (a,e,x,c,i) + elif line.startswith(nocodetext): + x = True + return (a,e,x,c,i) + elif line.startswith(cmdlinetext): + c = shlex.split(line[len(cmdlinetext):].strip()) + return (a,e,x,c,i) + elif line.startswith(stdintext): + i = line[len(stdintext):].lstrip() + return (a,e,x,c,i) + else: + print ('Error parsing options:',line) + exit(1) + def process(source, base_path): - atext = ' :assert:' stext = '.. elpi::' - rtext = '.. literalinclude::' file_ = open(source, 'r') lines = file_.readlines() @@ -25,72 +67,87 @@ def process(source, base_path): with in_place.InPlace(source) as file: index = 0 - + + file.write('.. role:: console(code)\n') + file.write(' :language: shell\n\n') + file.write('.. role:: elpi(code)\n') + file.write(' :language: elpi\n\n') for line in file: path = '' - output = '' errors = '' - matchr = '' + option_status = copy.deepcopy(initial_option_status) - if line.startswith(atext): - index += 1 + # ship options, already handled + if any(line.strip().startswith(x) for x in options): #file.write('') continue - if line.startswith(stext): - path = line[10:] + elif line.strip().startswith(stext): + indentation = ' ' + indentation *= line.index(':') - 7 + + path = line[line.index(':')+2:].strip() + + stop = False + while not stop and index < len(lines)-1: + next = lines[index+1].strip() + if any(next.startswith(x) for x in options): + index += 1 + option_status = parse_option(option_status,next) + else: + stop = True - output, errors = exec(path, base_path) + output, errors = run(option_status, path, base_path) - if index < len(lines)-1: - next = lines[index+1] + assert_expression, skip_stderr, skip_code, command_line, input_text = option_status + + if check(output, assert_expression) is None: + print('Failed to match',assert_expression,'on:\n') + print(output) + print(errors) + exit(1) + + if len(path) > 0 and not skip_code: + block = '' + block += indentation + '.. literalinclude:: ' + path + '\n' + block += indentation + ' :caption: ' + path + '\n' + block += indentation + ' :linenos:' + '\n' + block += indentation + ' :language: elpi' + '\n' + file.write(block) + + if len(path) > 0: + elpi_args = shlex.join([path] + command_line) + else: + elpi_args = shlex.join( command_line) + + if len(input_text) > 0: + elpi_input = "echo -e '" + input_text + "' | " + else: + elpi_input = "" + + file.write('\n' + indentation + 'Output of :console:`' + elpi_input + 'elpi ' + elpi_args + '`\n') + + if len(output) > 0: + block = indentation + '\n' + block += indentation + '.. code-block:: console' + '\n' + block += indentation + '\n ' + block += indentation + output.replace('\n', '\n'+indentation+' ') + block += indentation + '\n' + file.write(block) - if next.startswith(atext): - - expression = next[12:].rstrip() - - if check(output, expression) is None: - output = '' - errors = '' - matchr = 'Injection failure: result did not pass regexp check (' + expression + ')' - - if line.startswith(stext): - block = '**' + path + ':' + '**' + '\n' + '\n' - block += line.replace(stext, rtext) - block += ' :linenos:' + '\n' - block += ' :language: elpi' + '\n' - file.write(block) + if len(errors) > 0 and not skip_stderr: + block = indentation + '\n' + block += indentation + '.. code-block:: console' + '\n' + block += indentation + '\n ' + block += indentation + errors.replace('\n', '\n'+indentation+' ') + block += indentation + '\n' + file.write(block) + else: file.write(line) - if len(output) > 0: - block = '\n' - block += '.. code-block:: console' + '\n' - block += '\n ' - block += output.replace('\n', '\n ') - block += '\n' - file.write(block) - - if len(errors) > 0: - block = '\n' - block += '.. code-block:: console' + '\n' - block += '\n ' - block += errors.replace('\n', '\n ') - block += '\n' - file.write(block) - - if len(matchr) > 0: - block = '\n' - block += '.. raw:: html' + '\n' - block += '\n ' - block += '
'
-                block += matchr
-                block += '
' - block += '\n' - file.write(block) - index += 1 def find(path): diff --git a/elpi_REPL.ml b/elpi_REPL.ml index 60f5371fb..b6844acbb 100644 --- a/elpi_REPL.ml +++ b/elpi_REPL.ml @@ -16,25 +16,30 @@ open Elpi module Str = Re.Str -let print_solution time = function +let print_solution print_time time = function | API.Execute.NoMoreSteps -> - Format.eprintf "Interrupted (no more steps)@\n%!" -| API.Execute.Failure -> Format.eprintf "Failure@\n%!" + Format.printf "Interrupted (no more steps)@\n%!" +| API.Execute.Failure -> Format.printf "Failure@\n%!" | API.Execute.Success { API.Data.assignments; constraints; state; pp_ctx; _ } -> - Format.eprintf "@\nSuccess:@\n%!" ; - API.Data.StrMap.iter (fun name v -> - Format.eprintf " @[%s = %a@]@\n%!" name - (API.Pp.term pp_ctx) v) assignments; - Format.eprintf "@\nTime: %5.3f@\n%!" time; - Format.eprintf "@\nConstraints:@\n%a@\n%!" - (API.Pp.constraints pp_ctx) constraints; - Format.eprintf "@\nState:@\n%a@\n%!" - API.Pp.state state; + if not (API.Data.StrMap.is_empty assignments) then begin + Format.printf "@\nSuccess:@\n%!" ; + API.Data.StrMap.iter (fun name v -> + Format.printf " @[%s = %a@]@\n%!" name + (API.Pp.term pp_ctx) v) assignments; + end; + if print_time then + Format.eprintf "@\nTime: %5.3f@\n%!" time; + if API.RawData.constraints constraints != [] then + Format.printf "@\nConstraints:@\n%a@\n%!" + (API.Pp.constraints pp_ctx) constraints; + if not(API.State.is_empty state) then + Format.printf "@\nState:@\n%a@\n%!" + API.Pp.state state; ;; let more () = - prerr_endline "\nMore? (Y/n)"; + print_endline "\nMore? (Y/n)"; read_line() <> "n" ;; @@ -54,7 +59,8 @@ let set_terminal_width ?(max_w= let usage = "\nUsage: elpi [OPTION].. [FILE].. [-- ARGS..] \n" ^ "\nMain options:\n" ^ - "\t-test runs the query \"main\"\n" ^ + "\t-main runs the query \"main\"\n" ^ + "\t-test runs the query \"main\" (deprecated)\n" ^ "\t-exec pred runs the query \"pred ARGS\"\n" ^ "\t-D var Define variable (conditional compilation)\n" ^ "\t-document-builtins Print documentation for built-in predicates\n" ^ @@ -72,7 +78,8 @@ let usage = "\t-print-ast prints files as parsed, then exit\n" ^ "\t-print prints files after most compilation passes, then exit\n" ^ "\t-print-passes prints intermediate data during compilation, then exit\n" ^ - "\t-print-units prints compilation units data, then exit\n" + "\t-print-units prints compilation units data, then exit\n" ^ + "\t-print-time prints parsing, compilation, checking and esecution time\n" ;; (* For testing purposes we declare an identity quotation *) @@ -81,7 +88,7 @@ let _ = API.Quotation.lp let _ = - let test = ref false in + let main = ref false in let exec = ref "" in let print_lprolog = ref false in let print_ast = ref false in @@ -89,6 +96,7 @@ let _ = let batch = ref false in let doc_builtins = ref false in let delay_outside_fragment = ref false in + let print_time = ref false in let print_passes = ref false in let print_units = ref false in let extra_paths = ref [] in @@ -102,9 +110,11 @@ let _ = | "-legacy-parser" :: rest -> legacy_parser := true; eat_options rest | "-legacy-parser-available" :: _ -> if API.Setup.legacy_parser_available then exit 0 else exit 1 - | "-test" :: rest -> batch := true; test := true; eat_options rest + | "-main" :: rest -> batch := true; main := true; eat_options rest + | "-test" :: rest -> batch := true; main := true; eat_options rest | "-exec" :: goal :: rest -> batch := true; exec := goal; eat_options rest | "-print" :: rest -> print_lprolog := true; eat_options rest + | "-print-time" :: rest -> print_time := true; eat_options rest | "-print-ast" :: rest -> print_ast := true; eat_options rest | "-print-passes" :: rest -> print_passes := true; eat_options rest | "-print-units" :: rest -> print_units := true; eat_options rest @@ -176,8 +186,8 @@ let _ = exit 1; in let g = - if !test then - API.Parse.goal ~elpi ~loc:(API.Ast.Loc.initial "(-test)") ~text:"main." + if !main then + API.Parse.goal ~elpi ~loc:(API.Ast.Loc.initial "(-main)") ~text:"main." else if !exec <> "" then begin API.Parse.goal ~elpi ~loc:(API.Ast.Loc.initial "(-exec)") @@ -186,8 +196,9 @@ let _ = end else begin Printf.printf "goal> %!"; - let buff = Lexing.from_channel stdin in - try API.Parse.goal_from ~elpi ~loc:(API.Ast.Loc.initial "(stdin)") buff + let buff = Lexing.from_function (fun b n -> try let c = input_char stdin in Bytes.set b 0 c; 1 with End_of_file -> 0) in + try + API.Parse.goal_from ~elpi ~loc:(API.Ast.Loc.initial "(stdin)") buff with API.Parse.ParseError(loc,err) -> Printf.eprintf "%s:\n%s\n" (API.Ast.Loc.show loc) err; exit 1; @@ -198,14 +209,17 @@ let _ = exit 0; end; - Format.eprintf "@\nParsing time: %5.3f@\n%!" (Unix.gettimeofday () -. t0_parsing); + if !print_time then + Format.eprintf "@\nParsing time: %5.3f@\n%!" (Unix.gettimeofday () -. t0_parsing); + let query, exec = let t0_compilation = Unix.gettimeofday () in try let prog = API.Compile.program ~flags ~elpi [p] in let query = API.Compile.query prog g in let exec = API.Compile.optimize query in - Format.eprintf "@\nCompilation time: %5.3f@\n%!" (Unix.gettimeofday () -. t0_compilation); + if !print_time then + Format.eprintf "@\nCompilation time: %5.3f@\n%!" (Unix.gettimeofday () -. t0_compilation); query, exec with API.Compile.CompileError(loc,msg) -> API.Utils.error ?loc msg @@ -213,7 +227,8 @@ let _ = if !typecheck then begin let t0 = Unix.gettimeofday () in let b = API.Compile.static_check ~checker:(Builtin.default_checker ()) query in - Format.eprintf "@\nTypechecking time: %5.3f@\n%!" (Unix.gettimeofday () -. t0); + if !print_time then + Format.eprintf "@\nTypechecking time: %5.3f@\n%!" (Unix.gettimeofday () -. t0); if not b then begin Format.eprintf "Type error. To ignore it, pass -no-tc.\n"; exit 1 @@ -230,7 +245,7 @@ let _ = end; if not !batch then API.Execute.loop - ~delay_outside_fragment:!delay_outside_fragment ~more ~pp:print_solution + ~delay_outside_fragment:!delay_outside_fragment ~more ~pp:(print_solution !print_time) exec else begin Gc.compact (); @@ -240,7 +255,7 @@ let _ = ~delay_outside_fragment:!delay_outside_fragment exec in let t1 = Unix.gettimeofday () in match b with - | API.Execute.Success _ -> print_solution (t1 -. t0) b; true + | API.Execute.Success _ -> print_solution !print_time (t1 -. t0) b; true | (API.Execute.Failure | API.Execute.NoMoreSteps) -> false then exit 0 else exit 1 diff --git a/src/API.mli b/src/API.mli index bad958cd3..a15ef0e01 100644 --- a/src/API.mli +++ b/src/API.mli @@ -750,6 +750,8 @@ module State : sig val update : 'a component -> t -> ('a -> 'a) -> t val update_return : 'a component -> t -> ('a -> 'a * 'b) -> t * 'b + val is_empty : t -> bool + end (** Flexible data is for unification variables. One can use Elpi's unification diff --git a/src/data.ml b/src/data.ml index 1b69964c1..85cc78116 100644 --- a/src/data.ml +++ b/src/data.ml @@ -266,6 +266,7 @@ module State : sig val update : 'a component -> t -> ('a -> 'a) -> t val update_return : 'a component -> t -> ('a -> 'a * 'b) -> t * 'b val pp : Format.formatter -> t -> unit + val is_empty : t -> bool end = struct @@ -360,6 +361,18 @@ end = struct with Not_found -> ()) !extensions + let is_empty (t,s) = + let reserved_prefix = "elpi:" in + let len_reserved = String.length reserved_prefix in + StrMap.fold (fun name { pp } acc -> + if String.length name > len_reserved && String.sub name 0 len_reserved = reserved_prefix then + acc + else + try acc && (ignore(StrMap.find name t);Printf.eprintf "%s\n%!" name; false) + with Not_found -> acc) + !extensions true + + end (* This module contains the symbols reserved by Elpi and the ones diff --git a/tests/suite/suite.ml b/tests/suite/suite.ml index e9c9d798f..ad42dfa5f 100644 --- a/tests/suite/suite.ml +++ b/tests/suite/suite.ml @@ -388,7 +388,7 @@ let () = Runner.declare let { Test.expectation; input; outside_llam ; typecheck; trace; legacy_parser; _ } = test in let input = Util.option_map (fun x -> sources^x) input in - let args = ["-test";"-I";executable_stuff;"-I";sources;source] @ trace in + let args = ["-print-time";"-main";"-I";executable_stuff;"-I";sources;source] @ trace in let args = if typecheck then args else "-no-tc" :: args in