Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Refactor how the <O()> rule works.
Things brings us closer in line with how STD does things, and does away with
the rule taking a string of colonpairs that we then dissect into the
precedence information.
  • Loading branch information
arnsholt committed Mar 31, 2014
1 parent a2bb2db commit 7e96389
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 152 deletions.
92 changes: 7 additions & 85 deletions src/HLL/Grammar.nqp
Expand Up @@ -165,91 +165,13 @@ C< :!pair >, and C<< :pair<strval> >>.

=end

# This lexical holds the hash cache. Right now we have one
# cache for all grammars; eventually we may need a way to
# separate them out by cursor type.
my %ohash;

method O(str $spec, $save?) {
# See if we've already created a Hash for the current
# specification string -- if so, use that.
my %hash := %ohash{$spec};
unless %hash {
# Otherwise, we need to build a new one.
%hash := nqp::hash();
my int $eos := nqp::chars($spec);
my int $pos := 0;
while ($pos := nqp::findnotcclass(nqp::const::CCLASS_WHITESPACE,
$spec, $pos, $eos)) < $eos
{
my int $lpos;
my str $s := nqp::substr($spec, $pos, 1);
if $s eq ',' { # Ignore commas between elements for now.
$pos++;
}
elsif $s eq ':' { # Parse whatever comes next like a pair.
$pos++;

# If the pair is of the form :!name, then reverse the value
# and skip the exclamation mark.
my $value := 1;
if nqp::substr($spec, $pos, 1) eq '!' {
$pos++;
$value := 0;
}

# Get the name of the pair.
$lpos := nqp::findnotcclass(nqp::const::CCLASS_WORD,
$spec, $pos, $eos);
my $name := nqp::substr($spec, $pos, $lpos - $pos);
$pos := $lpos;

# Look for a <...> that follows.
if nqp::substr($spec, $pos, 1) eq '<' {
$pos := $pos + 1;
$lpos := nqp::index($spec, '>', $pos);
$value := nqp::substr($spec, $pos, $lpos - $pos);
$pos := $lpos + 1;
}
# Done processing the pair, store it in the hash.
%hash{$name} := $value;
}
else {
# If whatever we found doesn't start with a colon, treat it
# as a lookup of a previously saved hash to be merged in.
# Find the first whitespace or comma
$lpos := nqp::findcclass(nqp::const::CCLASS_WHITESPACE,
$spec, $pos, $eos);
my $index := nqp::index($spec, ',', $pos);
$lpos := $index unless $index < 0 || $index >= $lpos;
my $lookup := nqp::substr($spec, $pos, $lpos - $pos);
my %lhash := %ohash{$lookup};
self.'panic'('Unknown operator precedence specification "',
$lookup, '"') unless %lhash;
my $lhash_it := nqp::iterator(%lhash);
while $lhash_it {
$s := nqp::shift($lhash_it);
%hash{$s} := %lhash{$s};
}
$pos := $lpos;
}
}
# Done processing the spec string, cache the hash for later.
%ohash{$spec} := %hash;
}

if $save {
%ohash{$save} := %hash;
self;
}
else {
# If we've been called as a subrule, then build a pass-cursor
# to indicate success and set the hash as the subrule's match object.
my $cur := self.'!cursor_start_cur'();
$cur.'!cursor_pass'(nqp::getattr_i($cur, $cursor_class, '$!from'));
nqp::bindattr($cur, $cursor_class, '$!match', %hash);
$cur;
}
method O(*%hash) {
# Build a pass-cursor to indicate success and set the hash as the
# subrule's match object.
my $cur := self.'!cursor_start_cur'();
$cur.'!cursor_pass'(nqp::getattr_i($cur, $cursor_class, '$!from'));
nqp::bindattr($cur, $cursor_class, '$!match', %hash);
$cur;
}


Expand Down
130 changes: 63 additions & 67 deletions src/NQP/Grammar.nqp
@@ -1,4 +1,20 @@
grammar NQP::Grammar is HLL::Grammar {
my %methodop := nqp::hash('prec', 'y=', 'assoc', 'unary');
my %autoincrement := nqp::hash('prec', 'x=', 'assoc', 'unary');
my %exponentiation := nqp::hash('prec', 'w=', 'assoc', 'left');
my %symbolic_unary := nqp::hash('prec', 'v=', 'assoc', 'unary');
my %multiplicative := nqp::hash('prec', 'u=', 'assoc', 'left');
my %additive := nqp::hash('prec', 't=', 'assoc', 'left');
my %concatenation := nqp::hash('prec', 'r=', 'assoc', 'left');
my %relational := nqp::hash('prec', 'm=', 'assoc', 'non');
my %tight_and := nqp::hash('prec', 'l=', 'assoc', 'left');
my %tight_or := nqp::hash('prec', 'k=', 'assoc', 'left');
my %conditional := nqp::hash('prec', 'j=', 'assoc', 'right');
my %assignment := nqp::hash('prec', 'i=', 'assoc', 'right');
my %comma := nqp::hash('prec', 'g=', 'assoc', 'list', 'nextterm', 'nulltermish');
my %list_infix := nqp::hash('prec', 'f=', 'assoc', 'list');
my %list_prefix := nqp::hash('prec', 'e=', 'assoc', 'unary');

method TOP() {
# Language braids.
my %*LANG;
Expand Down Expand Up @@ -696,26 +712,6 @@ grammar NQP::Grammar is HLL::Grammar {
token semilist { <.ws> <statement> <.ws> }

## Operators

INIT {
NQP::Grammar.O(':prec<y=>, :assoc<unary>', '%methodop');
NQP::Grammar.O(':prec<x=>, :assoc<unary>', '%autoincrement');
NQP::Grammar.O(':prec<w=>, :assoc<left>', '%exponentiation');
NQP::Grammar.O(':prec<v=>, :assoc<unary>', '%symbolic_unary');
NQP::Grammar.O(':prec<u=>, :assoc<left>', '%multiplicative');
NQP::Grammar.O(':prec<t=>, :assoc<left>', '%additive');
NQP::Grammar.O(':prec<r=>, :assoc<left>', '%concatenation');
NQP::Grammar.O(':prec<m=>, :assoc<non>', '%relational');
NQP::Grammar.O(':prec<l=>, :assoc<left>', '%tight_and');
NQP::Grammar.O(':prec<k=>, :assoc<left>', '%tight_or');
NQP::Grammar.O(':prec<j=>, :assoc<right>', '%conditional');
NQP::Grammar.O(':prec<i=>, :assoc<right>', '%assignment');
NQP::Grammar.O(':prec<g=>, :assoc<list>, :nextterm<nulltermish>', '%comma');
NQP::Grammar.O(':prec<f=>, :assoc<list>', '%list_infix');
NQP::Grammar.O(':prec<e=>, :assoc<unary>', '%list_prefix');
}


token infixish { <!infixstopper> <OPER=infix> }
token infixstopper {
| <?{ $*IN_REGEX_ASSERTION }> <?[>]>
Expand All @@ -724,90 +720,90 @@ grammar NQP::Grammar is HLL::Grammar {

token postcircumfix:sym<[ ]> {
'[' <.ws> <EXPR> ']'
<O('%methodop')>
<O(|%methodop)>
}

token postcircumfix:sym<{ }> {
'{' <.ws> <EXPR> '}'
<O('%methodop')>
<O(|%methodop)>
}

token postcircumfix:sym<ang> {
<?[<]> <quote_EXPR: ':q'>
<O('%methodop')>
<O(|%methodop)>
}

token postcircumfix:sym<( )> {
'(' <.ws> <arglist> ')'
<O('%methodop')>
<O(|%methodop)>
}

token postfix:sym<.> { <dotty> <O('%methodop')> }
token postfix:sym<.> { <dotty> <O(|%methodop)> }

token prefix:sym<++> { <sym> <O('%autoincrement, :op<preinc>')> }
token prefix:sym<--> { <sym> <O('%autoincrement, :op<predec>')> }
token prefix:sym<++> { <sym> <O(|%autoincrement, :op<preinc>)> }
token prefix:sym<--> { <sym> <O(|%autoincrement, :op<predec>)> }

token postfix:sym<++> { <sym> <O('%autoincrement, :op<postinc>')> }
token postfix:sym<--> { <sym> <O('%autoincrement, :op<postdec>')> }
token postfix:sym<++> { <sym> <O(|%autoincrement, :op<postinc>)> }
token postfix:sym<--> { <sym> <O(|%autoincrement, :op<postdec>)> }

token infix:sym<**> { <sym> <O('%exponentiation, :op<pow_n>')> }
token infix:sym<**> { <sym> <O(|%exponentiation, :op<pow_n>)> }

token prefix:sym<+> { <sym> <O('%symbolic_unary, :op<numify>')> }
token prefix:sym<~> { <sym> <O('%symbolic_unary, :op<stringify>')> }
token prefix:sym<-> { <sym> <![>]> <!number> <O('%symbolic_unary, :op<neg_n>')> }
token prefix:sym<?> { <sym> <O('%symbolic_unary, :op<istrue>')> }
token prefix:sym<!> { <sym> <O('%symbolic_unary, :op<falsey>')> }
token prefix:sym<|> { <sym> <O('%symbolic_unary')> }
token prefix:sym<+> { <sym> <O(|%symbolic_unary, :op<numify>)> }
token prefix:sym<~> { <sym> <O(|%symbolic_unary, :op<stringify>)> }
token prefix:sym<-> { <sym> <![>]> <!number> <O(|%symbolic_unary, :op<neg_n>)> }
token prefix:sym<?> { <sym> <O(|%symbolic_unary, :op<istrue>)> }
token prefix:sym<!> { <sym> <O(|%symbolic_unary, :op<falsey>)> }
token prefix:sym<|> { <sym> <O(|%symbolic_unary)> }

token infix:sym<*> { <sym> <O('%multiplicative, :op<mul_n>')> }
token infix:sym</> { <sym> <O('%multiplicative, :op<div_n>')> }
token infix:sym<%> { <sym> <O('%multiplicative, :op<mod_n>')> }
token infix:sym<+&> { <sym> <O('%multiplicative, :op<bitand_i>')> }
token infix:sym<*> { <sym> <O(|%multiplicative, :op<mul_n>)> }
token infix:sym</> { <sym> <O(|%multiplicative, :op<div_n>)> }
token infix:sym<%> { <sym> <O(|%multiplicative, :op<mod_n>)> }
token infix:sym<+&> { <sym> <O(|%multiplicative, :op<bitand_i>)> }

token infix:sym<+> { <sym> <O('%additive, :op<add_n>')> }
token infix:sym<-> { <sym> <O('%additive, :op<sub_n>')> }
token infix:sym<+|> { <sym> <O('%additive, :op<bitor_i>')> }
token infix:sym<+^> { <sym> <O('%additive, :op<bitxor_i>')> }
token infix:sym<+> { <sym> <O(|%additive, :op<add_n>)> }
token infix:sym<-> { <sym> <O(|%additive, :op<sub_n>)> }
token infix:sym<+|> { <sym> <O(|%additive, :op<bitor_i>)> }
token infix:sym<+^> { <sym> <O(|%additive, :op<bitxor_i>)> }

token infix:sym<~> { <sym> <O('%concatenation , :op<concat>')> }
token infix:sym<~> { <sym> <O(|%concatenation , :op<concat>)> }

token infix:sym«==» { <sym> <O('%relational, :op<iseq_n>')> }
token infix:sym«!=» { <sym> <O('%relational, :op<isne_n>')> }
token infix:sym«<=» { <sym> <O('%relational, :op<isle_n>')> }
token infix:sym«>=» { <sym> <O('%relational, :op<isge_n>')> }
token infix:sym«<» { <sym> <O('%relational, :op<islt_n>')> }
token infix:sym«>» { <sym> <O('%relational, :op<isgt_n>')> }
token infix:sym«eq» { <sym> <O('%relational, :op<iseq_s>')> }
token infix:sym«ne» { <sym> <O('%relational, :op<isne_s>')> }
token infix:sym«le» { <sym> <O('%relational, :op<isle_s>')> }
token infix:sym«ge» { <sym> <O('%relational, :op<isge_s>')> }
token infix:sym«lt» { <sym> <O('%relational, :op<islt_s>')> }
token infix:sym«gt» { <sym> <O('%relational, :op<isgt_s>')> }
token infix:sym«=:=» { <sym> <O('%relational, :op<eqaddr>')> }
token infix:sym<~~> { <sym> <O('%relational, :reducecheck<smartmatch>')> }
token infix:sym«==» { <sym> <O(|%relational, :op<iseq_n>)> }
token infix:sym«!=» { <sym> <O(|%relational, :op<isne_n>)> }
token infix:sym«<=» { <sym> <O(|%relational, :op<isle_n>)> }
token infix:sym«>=» { <sym> <O(|%relational, :op<isge_n>)> }
token infix:sym«<» { <sym> <O(|%relational, :op<islt_n>)> }
token infix:sym«>» { <sym> <O(|%relational, :op<isgt_n>)> }
token infix:sym«eq» { <sym> <O(|%relational, :op<iseq_s>)> }
token infix:sym«ne» { <sym> <O(|%relational, :op<isne_s>)> }
token infix:sym«le» { <sym> <O(|%relational, :op<isle_s>)> }
token infix:sym«ge» { <sym> <O(|%relational, :op<isge_s>)> }
token infix:sym«lt» { <sym> <O(|%relational, :op<islt_s>)> }
token infix:sym«gt» { <sym> <O(|%relational, :op<isgt_s>)> }
token infix:sym«=:=» { <sym> <O(|%relational, :op<eqaddr>)> }
token infix:sym<~~> { <sym> <O(|%relational, :reducecheck<smartmatch>)> }

token infix:sym<&&> { <sym> <O('%tight_and, :op<if>')> }
token infix:sym<&&> { <sym> <O(|%tight_and, :op<if>)> }

token infix:sym<||> { <sym> <O('%tight_or, :op<unless>')> }
token infix:sym<//> { <sym> <O('%tight_or, :op<defor>')> }
token infix:sym<||> { <sym> <O(|%tight_or, :op<unless>)> }
token infix:sym<//> { <sym> <O(|%tight_or, :op<defor>)> }

token infix:sym<?? !!> {
'??'
<.ws>
<EXPR('i=')>
'!!'
<O('%conditional, :reducecheck<ternary>, :op<if>')>
<O(|%conditional, :reducecheck<ternary>, :op<if>)>
}

token infix:sym<=> {
<sym> <.panic: 'Assignment ("=") not supported in NQP, use ":=" instead'>
}
token infix:sym<:=> { <sym> <O('%assignment, :op<bind>')> }
token infix:sym<::=> { <sym> <O('%assignment, :op<bind>')> }
token infix:sym<:=> { <sym> <O(|%assignment, :op<bind>)> }
token infix:sym<::=> { <sym> <O(|%assignment, :op<bind>)> }

token infix:sym<,> { <sym> <O('%comma, :op<list>')> }
token infix:sym<,> { <sym> <O(|%comma, :op<list>)> }

token prefix:sym<make> { <sym> \s <O('%list_prefix')> }
token prefix:sym<make> { <sym> \s <O(|%list_prefix)> }
token term:sym<return> { <sym> [\s <EXPR>]? { $*RETURN_USED := 1 } }

method smartmatch($/) {
Expand Down

0 comments on commit 7e96389

Please sign in to comment.