Line Numbers

12 views
Skip to first unread message

Robottaway

unread,
May 6, 2011, 2:53:07 AM5/6/11
to lepl
I couldn't find anything searching the documentation or this group. I
am wondering if there is an easy way to be able to get at line numbers
(or ranges of them) for a match?

Say I have:

class Greeting(Node): pass
newline = ~Literal('\n')
space = ~Space()
padding = (space | newline)[:]
line = padding & 'howdy:' & padding > Greeting

ast = line.parse(' \n \n \n howdy: \n \n\n ')

Can I get the line number somehow from the Greeting that is created? I
want to be able to report the line number at a time after I have
created an AST and once I exercise values withing it.

Regards,
Rob

andrew cooke

unread,
May 6, 2011, 8:06:23 AM5/6/11
to le...@googlegroups.com

Hi,

I don't know if this is opaque or not, but it does what you want (I'll explain
more below):

from lepl import *

def with_line(node):
def wrapper(results, stream_out, **kargs):
return node(results, ('lineno', s_delta(stream_out)[1]))
return wrapper

class Greeting(Node): pass
newline = ~Literal('\n')
space = ~Space()
padding = (space | newline)[:]

line = padding & (Literal('howdy:') ** with_line(Greeting)) & padding

ast = line.parse(' \n \n \n howdy: \n \n\n ')

print(ast[0])

The output is:

Greeting
+- ['howdy:']
`- lineno 4

This is for the latest version of Lepl btw (5).

The reason that works is:

1 - I'm creating the node exactly where we match the greeting (in your
original code you were creating the node after discaring more padding, so the
line number would have been wrong).

2 - I'm using "**" rather than ">" which calls a function with various named
arguments (see
http://www.acooke.org/lepl/operators.html#operators-that-apply-functions-to-results)
- in this case the important arguments are "results" (the string matched) and
"stream_out) which is the input stream after matching.

3 - With that information, we can get the location from the stream after
matching. That's done with s_delta which returns (offset, lineno and char)
see
http://www.acooke.org/lepl/api/lepl.stream.core-pysrc.html#StreamHelper.delta

4 - Finally, we stick that in the node, along with the result.

Cheers,
Andrew

> --
> You received this message because you are subscribed to the Google Groups "lepl" group.
> To post to this group, send email to le...@googlegroups.com.
> To unsubscribe from this group, send email to lepl+uns...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/lepl?hl=en.
>

andrew cooke

unread,
May 6, 2011, 8:19:02 AM5/6/11
to le...@googlegroups.com
The indentation is a little on on Google groups.  That should be:

def with_line(node):
....def wrapper(results, stream_out, **kargs):
........return node(results, ('lineno', s_delta(stream_out)[1]))
....return wrapper

where I am adding "...." instead of spaces to be sure it's not mangled.

Andrew

Robottaway

unread,
May 9, 2011, 7:47:58 PM5/9/11
to lepl
Andrew, thank you very much! I've been away, think I will try and
update my parser tonight to get line numbers. Thanks! One question, in
the case that a match crosses a number of lines will this approach
return a range of line numbers?

andrew cooke

unread,
May 9, 2011, 8:46:16 PM5/9/11
to le...@googlegroups.com

you'll get the last line number because you're using the output stream (the
stream after matching). there's also the input stream available (the stream
before matching) which will give you the start line. it's one of the
arguments that i ignored by adding "**kargs" to the function.

i can't remember the exact names off the top of my head, but hopefully that's
obvious...?

cheers,
andrew

Reply all
Reply to author
Forward
0 new messages