[Dropping automake; at this point, m4-discuss is the best place to
discuss how m4p is progressing]

On Sat, May 10, 2025 at 04:45:26PM -0400, Nikolaos Chatzikonstantinou wrote:
> > Try this in the source dir (one time only):
> >
> > python3 -m venv .venv
> > source .venv/bin/activate
> > pip install -U pip setuptools wheel
> > pip install -e .[tests]
> >
> > Then anytime you want to try the software navigate to the source directory
> > and do:
> >
> > source .venv/bin/activate
> >
> > To activate the environment and use "m4p" directly as a command. Any
> > changes you make to the source code should be reflected in that m4p script.
> >
> 
> And I forgot that you can run the tests with
> 
> pytest
> 
> And select a particular test with
> 
> pytest -k define
> 
> E.g. picks tests/resources/define.txt

Thanks; I now have an 'm4p' binary to play with.

Without $* and $@ support, tail recursion is not plausible, so I will
wait until you have that implemented.

An obvious easy difference - you still don't have short-circuiting
working in eval:

$ echo 'eval(1 || 1/0)' | m4
1
$ echo 'eval(1 || 1/0)' | m4p
m4:stdin:1: divide by zero in eval: 1 || 1/0
1

and a bit less obvious is the difference between 1.4.19 and 1.4.20 on
when short-circuiting actually works (if you are aiming for a true
1.4.19 experience, you need bug-for-bug compatibility; if you are
instead aiming for latest release compatibility, you should favor the
fixed eval):

$ echo 'eval(1 || (1/0))' | m4-1.4.19
m4:stdin:1: bad expression in eval (excess input): 1 || (1/0)

$ echo 'eval(1 || (1/0))' | m4-1.4.20
1
$ echo 'eval(1 || (1/0))' | m4p
m4:stdin:1: divide by zero in eval: 1 || (1/0)
1

Another obvious difference that I depend on (and POSIX says it should
work):

$ echo foo | m4 -Dfoo=bar
bar
$ echo foo | m4p -Dfoo=bar
usage: m4p [-h] [-P] [-v] [-I DIRECTORY] [--debugfile [FILE]] [FILE ...]
m4p: error: unrecognized arguments: -Dfoo=bar

And then there's this stress test that's worth handling gracefully
(you can't prevent stack overflow, because that's computationally
equivalent to solving the Halting Problem, so the best you can do is
gracefully handle it rather than spewing thousands of lines of errors
at the user when they write a script with poor recursion):

$ echo 'define(a,a(a))a' | m4; echo $?
m4: stack overflow
1
$ echo 'define(a,a(a))a' | m4p; echo $?
m4: stack overflow
Traceback (most recent call last):
  File "/home/eblake/m4p/.venv/bin/m4p", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/eblake/m4p/m4p/main.py", line 27, in main
    _main()
  File "/home/eblake/m4p/m4p/main.py", line 102, in _main
    parser.parse()
  File "/home/eblake/m4p/m4p/parser.py", line 511, in parse
    args = self.consume_arguments()
           ^^^^^^^^^^^^^^^^^^^^^^^^
... ~2500 lines later...
RecursionError: maximum recursion depth exceeded
120

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization:  qemu.org | libguestfs.org


Reply via email to