nodejs/llparse

switch on span?

drom opened this issue · 16 comments

drom commented

Very cool project.

I am trying to build Verilog preprocessor using llparse here: https://github.com/drom/vpreproc
I have encounter one difficulty that I don't know how to solve.

  1. preprocessor looking for ``` character in the stream. https://github.com/drom/vpreproc/blob/master/bin/build.js#L27
  2. Then it should chop a string (span) of characters (identifier) terminated by non-identifier.
  3. By looking at the span if should classify it as:
  • one of the known directives and continue accordingly.
  • unknown string (defined value) and jump to a different state.

The difficulty I have is to how to implement, span Lookup without select or match API?

Thanks!

I think combination of span and select should do it. Why do you want to avoid select?

drom commented

I am fine with select. But I have not found a good example of doing multiple selects and a span in parallel.

Here's how I do it in llhttp: https://github.com/nodejs/llhttp/blob/d8d480a57df82203fa2f8733178696073451fd7d/src/llhttp/http.ts#L348-L370 . It just starts a span and then does whatever it wants, and ends the span when needed.

drom commented

How do you do select that ends with one of non-identifier symbols like \s \t \n \r .... ?

Could you write a couple of examples of the possible inputs? I'm not sure I fully understand the use-case yet.

drom commented
some text
`include "something.vh"
some text
`define FOO 5
more text
text with `FOO in the middle
more text
`undef FOO
text again
`undefineall
even more text

There are multiple standard defined directives: like \define, `undef, `undefineall, `includewith a different number of standard arguments. And there are defined values like`FOO` that can also appear in the text.

http://ecee.colorado.edu/~mathys/ecen2350/IntelSoftware/pdf/IEEE_Std1800-2017_8299595.pdf
Chapter 22

Okay... Perhaps:

const directive = p.node('directive');

span.start(directive);
directive.select({ include: 1, define: 2, undef: 3, undefineall: 4 }, directiveParamStart);

directiveParamsStart.match([ '\s', '\t', '\n', '\r' ], directiveParams)

// Do something in directiveParams

directiveParamsEnd.otherwise(span.end(afterDirective))

Oh wait, this is not what you asked about.

Second attempt:

const directive = p.node('directive');
const knownDirective = p.invoke(p.code.store('directive'));
const directiveEnd = span.end(afterDirective);

span.start(directive);

directive.select({ include: 1, define: 2, undef: 3, undefinedall: 4 }, knownDirective);
directive.otherwise(unknownDirective);

unknownDirective
  .match([ '\s', '\t', '\n', '\r' ], p.invoke(p.code.update('directive', -1).otherwise(directiveEnd))
  .skipTo(unknownDirective);
drom commented

Will undef and undefineall conflict?

Oh, that's a good one. They will. Perhaps, you'll have to use .match('undef') as well with further branch to either \s\t\n\r or ineall.

I think this conflicting matching should be supported. Created an issue to track progress on it: #28 . It might be wise to move on with a solution above at the moment, though.

drom commented

Can I do multiple select groups?

  • group1: resetall, undefineall, endif ... has no arguments
  • group2: ifdef, ifndef, elsif, undef has single argument
  • group3: include ...

I think it should work. Give it a try 😉

drom commented

Thank you. I will try.

drom commented

Yes, thank you. All works fine!