{"action":"opened","issue":{"url":"https://api.github.com/repos/nikomatsakis/lalrpop/issues/15","labels_url":"https://api.github.com/repos/nikomatsakis/lalrpop/issues/15/labels{/name}","comments_url":"https://api.github.com/repos/nikomatsakis/lalrpop/issues/15/comments","events_url":"https://api.github.com/repos/nikomatsakis/lalrpop/issues/15/events","html_url":"https://github.com/nikomatsakis/lalrpop/issues/15","id":106311952,"number":15,"title":"Inlined nonterminals","user":{"login":"nikomatsakis","id":155238,"avatar_url":"https://avatars.githubusercontent.com/u/155238?v=3","gravatar_id":"","url":"https://api.github.com/users/nikomatsakis","html_url":"https://github.com/nikomatsakis","followers_url":"https://api.github.com/users/nikomatsakis/followers","following_url":"https://api.github.com/users/nikomatsakis/following{/other_user}","gists_url":"https://api.github.com/users/nikomatsakis/gists{/gist_id}","starred_url":"https://api.github.com/users/nikomatsakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikomatsakis/subscriptions","organizations_url":"https://api.github.com/users/nikomatsakis/orgs","repos_url":"https://api.github.com/users/nikomatsakis/repos","events_url":"https://api.github.com/users/nikomatsakis/events{/privacy}","received_events_url":"https://api.github.com/users/nikomatsakis/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/nikomatsakis/lalrpop/labels/wishlist","name":"wishlist","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-09-14T10:15:37Z","updated_at":"2015-09-14T10:15:37Z","closed_at":null,"body":"One of the features I've wanted to have for a long time is inlined nonterminals. The idea is that if you declare a terminal as `#[inline]`:\r\n\r\n ```rust\r\n#[inline]\r\nA = B | C | ();\r\n```\r\n\r\nthen every use of `A` will be expanded out to its various alternatives. In other words, a reference like:\r\n\r\n```rust\r\nX = A \"foo\";\r\n```\r\n\r\nwould become:\r\n\r\n```rust\r\nX = B \"foo\" | C \"foo\" | \"foo\";\r\n```\r\n\r\nIt has been my experience that inlining nonterminals is very helpful for removing shift-reduce conflicts, particularly around optional content. Accordingly, the `X*` and `X?` shorthands would expand to inlined nonterminals.\r\n\r\nThis should solve shift-reduce conflicts like:\r\n\r\n```rust\r\nT = \"L\" | \"&\" \"L\"? T\r\n```\r\n\r\nHere we get a conflict in the state `& (*) L`, where it's unclear whether the `L` is the optional `L` or part of the `T`. In the latter case, we'd have to reduce `() => \"L\"?`. But if we inlined the `\"L\"?` expansion, we'd have:\r\n\r\n```rust\r\nT = \"L\" | \"&\" T | \"&\" \"L\" T\r\n```\r\n\r\nIn which case, we could just shift the `\"L\"` and wait until see the next token to decide what to do.\r\n\r\nUser annotation is needed here because inlining affects the visible order of execution.\r\n\r\nNote though that inlining is only really useful in an `LR(1)` setting. If we chose to adopt some kind of universal algorithm by default this would become less important."}}