Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReferenceError: head is not defined #275

Closed
cressie176 opened this issue Jun 2, 2022 · 8 comments
Closed

ReferenceError: head is not defined #275

cressie176 opened this issue Jun 2, 2022 · 8 comments

Comments

@cressie176
Copy link

Hello & thank you for your work on peggy and for picking up where pegjs left off.

I'm one of the maintainers of amqplib and investigating amqp-node/amqplib#453. amqplib uses pegjs via bitsyntax to generate a parser from the grammar specified here.

bitsyntax's last working parser was generated using [email protected] and upgrading to [email protected], peggy@^1.0.0 or peggy@latest results in a broken parser.

/Users/steve/Development/squaremo/bitsyntax-js/lib/parser.js:256
  var peg$f17 = function() { return head + tail.join(''); };
                             ^

ReferenceError: head is not defined

I'm completely new to pegjs/peggy and was hoping it's an easy fix. Can you give me any pointers please?

Thanks

@hildjj
Copy link
Contributor

hildjj commented Jun 2, 2022

I grabbed the grammar, ran it through peggy's CLI with the default options, then called parse('"foo", "bar"'), and got [ { string: 'foo' }, { string: 'bar' } ]. I suspect the issue may be here. Try making that like be:

	 $(PEGJS) $(GRAMMAR) -o $@

(add -o to direct the output to a file). My suspicion is that you're getting an error instead of generating the new implementation. Assuming it's not that, can you tell us how you're calling peggy, and an example input that's failing for you?

I agree that the line you've highlighted looks wrong. Here's what I get:

var peg$f0 = function(head, tail) { tail.unshift(head); return tail; };

@cressie176
Copy link
Author

Hi @hildjj,

Thanks for the quick response. I also noticed that the Makefile is out of date. I've generated the parser by hand as follows

rm lib/parser.js 
./node_modules/.bin/peggy -o lib/parser.js lib/grammar.pegjs

@hildjj
Copy link
Contributor

hildjj commented Jun 2, 2022

Example input, please? And can you check that you're using Peggy 2.0.1, which was just released yesterday?

@cressie176
Copy link
Author

Peggy Version

// Generated by Peggy 2.0.1.
//
// https://peggyjs.org/

Input Grammar

start
    = ws head:segment tail:segmentTail* { tail.unshift(head); return tail; }

segmentTail
    = ws ',' ws seg:segment { return seg; }

segment
    = str:string { return {string: str}; }
    / v:identifier size:size ? specs:specifierList ?
      { return {name: v, size: size, specifiers: specs}; }
    / v:number size:size ? specs:specifierList ?
      { return {value: v, size: size, specifiers: specs}; }

string
  = '"' '"'             { return "";    }
  / '"' chars:chars '"' { return chars; }

/* From JSON example
https://github.com/dmajda/pegjs/blob/master/examples/json.pegjs */

chars
  = chars:char+ { return chars.join(""); }

char
  = [^"\\\0-\x1F\x7f]
  / '\\"'  { return '"';  }
  / "\\\\" { return "\\"; }
  / "\\/"  { return "/";  }
  / "\\b"  { return "\b"; }
  / "\\f"  { return "\f"; }
  / "\\n"  { return "\n"; }
  / "\\r"  { return "\r"; }
  / "\\t"  { return "\t"; }
  / "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit {
      return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
    }

hexDigit
  = [0-9a-fA-F]

identifier
    = (head:[_a-zA-Z] tail:[_a-zA-Z0-9]*) { return head + tail.join(''); }

number
    = '0' { return 0; }
    / head:[1-9] tail:[0-9]* { return parseInt(head + tail.join('')); }

size
    = ':' num:number { return num; }
    / ':' id:identifier { return id; }

specifierList
    = '/' head:specifier tail:specifierTail* { tail.unshift(head); return tail; }

specifierTail
    = '-' spec:specifier { return spec; }

specifier
    = 'little' / 'big' / 'signed' / 'unsigned'
    / 'integer' / 'binary' / 'float'
    / unit

unit
    = 'unit:' num:number { return 'unit:' + num; }

ws = [ \t\n]*

@hildjj
Copy link
Contributor

hildjj commented Jun 2, 2022

OK, it has nothing to do with the build process. Remove the parens on line 43:

identifier
    = head:[_a-zA-Z] tail:[_a-zA-Z0-9]* { return head + tail.join(''); }

which ends up being "a" + ["b", "c"] which is a roundabout way of getting the string that matched. You could just use:

identifier
    = [_a-zA-Z] [_a-zA-Z0-9]* { return text(); }

Some old version of peg.js must have changed how parens are handled. In today's world, they hide labels from the containing rule. Once I got that working, there are a bunch of other test errors, but that's a separate issue.

@cressie176
Copy link
Author

Thanks @hildjj. I'll close this, and try to work out why the tests are failing.

@hildjj
Copy link
Contributor

hildjj commented Jun 2, 2022

Let us know if you'd like more help with the grammar. Happy to pitch in as needed.

@Mingun
Copy link
Member

Mingun commented Jun 3, 2022

Actually, your original grammar worked because of a bug, fixed in [email protected]:

Fixed label scoping so that labels in expressions like (a:"a") or (a:"a" b:"b" c:"c") aren’t visible from the outside.

Also, you could simplify your grammar much more using a new @ operator, for example, here:

segmentTail
    = ws ',' ws @segment

and using a $ operator instead of return text():

identifier
    = $([_a-zA-Z] [_a-zA-Z0-9]*)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants