-
Notifications
You must be signed in to change notification settings - Fork 0
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
Generate proper precede requirement based on layout follow restriction #9
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
147e86a
Manually rewrote rascal grammar to get better highlights
DavyLandman a6944f9
Merge branch 'main' into better-rascal-grammar
sungshik 4e0b79b
Add new module to compute first/last/follow/precede sets
sungshik 8ac28e8
Add optional generation of a precede guard for regular expressions
sungshik d01f5d0
Update tests
sungshik 8a29809
Update generated TextMate grammar for Rascal's own grammar
sungshik 5a8597e
Include the beginning of a line as admissible alternative to the prec…
sungshik 654cb88
Update generated TextMate grammar for Rascal's own grammar
sungshik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
rascal-textmate-core/src/main/rascal/lang/rascal/grammar/analyze/Symbols.rsc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
@synopsis{ | ||
Types and functions to analyze symbols | ||
} | ||
|
||
@description{ | ||
Note: Some functions in this module seemingly overlap with those in module | ||
`lang::rascal::grammar::Lookahead` (i.e., computation of first/follow sets). | ||
However, only symbols of the form `\char-class(_)` are considered terminals | ||
in that module, which is too strict for the purpose of this project. | ||
} | ||
|
||
// TODO: The analysis of delimiters in module | ||
// `lang::rascal::grammar::analyze::Delimiters` can probably be rewritten (less | ||
// code) to use functions in this module. | ||
|
||
module lang::rascal::grammar::analyze::Symbols | ||
|
||
import Grammar; | ||
import ParseTree; | ||
import util::Maybe; | ||
|
||
import lang::rascal::grammar::Util; | ||
|
||
@synopsis{ | ||
Representation of a traversal direction along a list of symbols | ||
} | ||
|
||
data Direction // Traverse lists of symbols (in productions)... | ||
= forward() // - ...from left to right; | ||
| backward() // - ...from right to left. | ||
; | ||
|
||
private list[&T] reorder(list[&T] l, forward()) = l; | ||
private list[&T] reorder(list[&T] l, backward()) = reverse(l); | ||
|
||
@synopsis{ | ||
Computes the *last* set of symbol `s` in grammar `g` | ||
} | ||
|
||
set[Symbol] last(Grammar g, Symbol s) | ||
= unmaybe(firstBySymbol(g, isTerminal, backward())[delabel(s)]); | ||
|
||
@synopsis{ | ||
Computes the *first* set of symbol `s` in grammar `g` | ||
} | ||
|
||
set[Symbol] first(Grammar g, Symbol s) | ||
= unmaybe(firstBySymbol(g, isTerminal, forward())[delabel(s)]); | ||
|
||
@memo | ||
private map[Symbol, Maybe[set[Symbol]]] firstBySymbol(Grammar g, bool(Symbol) predicate, Direction dir) { | ||
map[Symbol, Maybe[set[Symbol]]] ret | ||
= (delabel(s): nothing() | s <- g.rules) // Non-terminals | ||
+ (delabel(s): nothing() | /prod(_, [*_, s, *_], _) := g, !isNonTerminalType(s)); // Terminals | ||
|
||
Maybe[set[Symbol]] firstOf([]) | ||
= just({}); | ||
Maybe[set[Symbol]] firstOf([h, *t]) | ||
= \set: just({\empty(), *_}) := ret[delabel(h)] | ||
? union(\set, firstOf(t)) | ||
: ret[delabel(h)]; | ||
|
||
solve (ret) { | ||
for (s <- ret, nothing() == ret[s]) { | ||
if (predicate(s)) { | ||
ret[s] = just({s}); | ||
} else if (list[Production] prods: [_, *_] := lookup(g, s)) { | ||
ret[s] = (just({}) | union(it, firstOf(reorder(p.symbols, dir))) | p <- prods); | ||
} else { | ||
ret[s] = just({\empty()}); | ||
} | ||
} | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
@synopsis{ | ||
Computes the *precede* set of symbol `s` in grammar `g` | ||
} | ||
|
||
set[Symbol] precede(Grammar g, Symbol s) | ||
= unmaybe(followBySymbol(g, isTerminal, backward())[delabel(s)]); | ||
|
||
@synopsis{ | ||
Computes the *follow* set of symbol `s` in grammar `g` | ||
} | ||
|
||
set[Symbol] follow(Grammar g, Symbol s) | ||
= unmaybe(followBySymbol(g, isTerminal, forward())[delabel(s)]); | ||
|
||
@memo | ||
private map[Symbol, Maybe[set[Symbol]]] followBySymbol(Grammar g, bool(Symbol) predicate, Direction dir) { | ||
map[Symbol, Maybe[set[Symbol]]] ret = (delabel(s): nothing() | s <- g.rules); // Non-terminals | ||
|
||
Maybe[set[Symbol]] followOf(Symbol parent, []) | ||
= ret[delabel(parent)]; | ||
Maybe[set[Symbol]] followOf(Symbol parent, [h, *t]) | ||
= just({\empty(), *rest}) := firstBySymbol(g, predicate, dir)[delabel(h)] | ||
? union(just(rest), followOf(parent, t)) | ||
: firstBySymbol(g, predicate, dir)[delabel(h)]; | ||
|
||
solve (ret) { | ||
for (s <- ret, nothing() == ret[s]) { | ||
ret[s] = just({}); | ||
for (/prod(def, symbols, _) := g, [*_, t, *after] := reorder(symbols, dir), s == delabel(t)) { | ||
ret[s] = union(ret[s], followOf(def, after)); | ||
} | ||
} | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
private set[Symbol] unmaybe(just(set[Symbol] \set)) | ||
= \set; | ||
private set[Symbol] unmaybe(nothing()) | ||
= {}; | ||
|
||
private Maybe[set[Symbol]] union(just(set[Symbol] \set1), just(set[Symbol] \set2)) | ||
= just(\set1 + \set2); | ||
private default Maybe[set[Symbol]] union(Maybe[set[Symbol]] _, Maybe[set[Symbol]] _) | ||
= nothing(); | ||
|
||
@synopsis{ | ||
Checks if symbol `s` is a terminal | ||
} | ||
|
||
bool isTerminal(Symbol s) | ||
= !isNonTerminalType(s); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: solve returns the solved value, so this can become:
return solve(ret)...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I played a bit with this just now, but it seems
solve
doesn't always return a value (it doesn't in the cases of this PR). I submitted an issue basically to update the docs (it seems by design instead of a bug).