How to unit test a rule in a grammar - unit-testing

I have a grammar with a rule such as:
item_list returns [EnumSet<Item> value]
: item { $value = EnumSet.of($item.value); }
| item_list ',' item { $value = $item_list.value; $value.add($item.value); }
This is just one rule within the grammar: an item_list on its own is not a valid expression. But I would like to unit test the individual rules as well as the whole grammar. I have tried a method that looks something like:
#Test
void testItemList() {
assertThat(parse("dog,car").item_list().value).containsOnly(Item.DOG, Item.CAR);
}
Unfortunately the parser fails on this text because it is looking for EOF before it recognises the rule to use. I can artificially add a new rule:
item_list_test returns [EnumSet<Item> value]
: item_list EOF { $value = $item_list.value; }
Which then allows the test to pass (using .item_list_test()).
This is obviously kludgy and requires adding useless rules purely for the purpose of testing. Is there a way to force the parser to parse a rule as though it was terminated?

Related

Why can't anything go in the body of a Perl 6 grammar proto?

When declaring a proto, it's possible to surround the multimethod/sub code with additional code. For a silly example:
proto sub foo(|) { 'Camelia says “' ~ {*} ~ '!”' }
multi sub foo(1) { "hi" }
multi sub foo($) { "bye" }
say foo(1) # Camelia says “hi!”
I haven't come across any times (yet) where I've felt that's hugely useful, but on the flipside, I have come across some where in regex/Grammar world where I occasionally find myself repeating myself throughout all of the proto tokens — it's not that I can't shift into a separate token, but that adds an extra layer of hierarchy and actions. Compare a hypothetical
grammar Bar { 
token TOP { <meta>* }
token metastart { '#' }
proto token meta { <metastart> {*} }
token meta:name { ( \w* ) }
token meta:date { (\d**6) }
}
Where they only action methods necessary besides TOP would be meta:nameand meta:date to
grammar Bar { 
token TOP { <meta>* }
token metastart { '#' }
token meta { <metastart> <metacontent> }
proto token metacontent { * }
token metacontent:name { \w* }
token metacontent:date { \d**6 }
}
This now requires three methods: metacontent:name, metacontent:date and then a fairly superfluous meta whose entire body would just be make $<metacontent>.made.
Although I've seen documentation / comments floating around saying you can toss in code in the protos inside of a grammar, if anything is placed in the body of a proto token/regex/rule other than a single *, then the compiler complains: Proto regex body must be {*} (or <*> or <...>, which are deprecated)
Is this an as-yet unimplemented features or is the plan to no longer allow anything in the proto? And if it's the latter, why should the proto designator be required? (I'm guessing it's because there's something special about how proto token/regex/rule dispatches, since removing proto inside of a grammar results in runtime failures unlike in the sub/method world.
As a matter of fact, proto regexes are little more than a grouping device for several tokens. The documentation says:
the name of a group of values we'll create
They don't really declare a routine multi, and in fact, tokens that follow that proto are not declared as multis, they're simply tokens (which are regexes, which are methods) with funny names.
In your case, you can simply avoid the additional proto token by using alternation, which is actually what protos in grammars stand for:
grammar Bar {
token TOP { <meta>* }
token metastart { '#' }
token meta { <metastart> [ <name> | <date> ] }
token name { \w* }
token date { \d**6 }
}
say Bar.parse( "#Hey" );
say Bar.parse( "#3333" );

Regex as associative array key?

I'm working on a very performance dependent portion of my code in D. For this, I want to have an associative array mapping my data to a Regex so that I can use it later.
When I try to do this, it gives me the error, index is not a type or expression. How can I use this regex as my array key?
Edit: For code, here's what I'm trying to define in my class:
View[Regex] m_routes;
I want that so that I can add the routes like below:
void add(string route, View view)
{
auto regex = regex(route.key, [ 'g', 'i' ]);
if (regex in m_routes)
throw new Exception(format(`Route with path, "%s", is already assigned!`, route));
m_routes[regex] = view;
}
This would then allow me to check the regex against a route, without having to rebuild each one, shown in this method:
View check(string resource)
{
foreach (route; m_routes.byKeyValue())
{
auto match = matchAll(resource, route.key);
// If this regex is a match
// return the view
if (!match.empty)
{
return route.value;
}
}
return null;
}
Any help would be appreciated, thank you!
It seems std.regex.Regex is an alias that takes a type parameter:
(from std.regex.package, line 289 in release 2.071.0)
public alias Regex(Char) = std.regex.internal.ir.Regex!(Char);
In other words, you'll need to specify the char type for the regex. For string, that'd be char:
View[Regex!char] m_routes;

SpEL expressions - identify fields declared in an expression?

I have the following code which evaluates a SpEL expression using data values defined in a Map object.
// data map
Map dataMap = new HashMap();
dataMap.put("abc",1);
dataMap.put("def",2);
dataMap.put("xyz",1);
dataMap.put("qwerty",2);
// spel rule expression
String ruleExpression = "#abc+#def";
// Set evaluation context
StandardEvaluationContext stdContext = new StandardEvaluationContext();
stdContext.setVariables(map);
// Evaluate the SpEL expression
ExpressionParser parser = new SpelExpressionParser();
Object returnValue = parser.parseExpression(ruleExpression).getValue(stdContext);
// returnValue = 3 :-)
In the real world our map is populated based in a DB query result set and the 'ruleExpression' is only known at runtime. I have a new requirement to log the values defined in the 'ruleExpression' such that a string like this is generated
abc=1,def=2
A brute force approach might see us parsing the 'ruleExpression' string to identify fieldnames that start with '#' using regex but i could see how this could get messy as the complexity of the ruleExpression increases.
I'm wondering since the SpEl engine must identify the fields declared in the 'ruleExpression' during the parseExpress() phase is there a way for us to reuse this logic?
EDIT - I did come across the VariableScope private inner class on the org.springframework.expression.spel.ExpressionState class which seems to do what i want but alas the it's not accessible.
You can try overriding lookupVariable in StandardExpressionContext and adding your logging in there. Replacing your stdContext with the following will catch each variable as it is used:
StandardEvaluationContext stdContext = new StandardEvaluationContext() {
#Override
public Object lookupVariable(String name) {
Object value = super.lookupVariable(name);
//do logging here
System.out.println(name + "=" + value);
return value;
}
};
This outputs:
abc=1
def=2
This will only catch the values which are used from variables. Anything that comes from a bean or other object etc. will not go through lookupVariable. Neither will variable values which are never used (due to a conditional for instance).

Backbone Underscore Template not working dash in variable name

My backbone underscore template is not working. I got one variable return from the server with has a name
month-total. The template engine is treating as arithmetic operation of two variables.
How to treat this as single variable.
Thanks
Underscore templates work by converting your template to a JavaScript function. Things like <%= x %> go straight into that function untouched; then the function uses JavaScript's with to make keys in an object behave like local variables. From the fine manual:
By default, template places the values from your data in the local scope via the with statement.
You can use the source attribute of the compiled template function to see the JavaScript and if we do that with a simple template like <%= a-b %>, you'll see why it is treated as a subtraction:
// Reformatted for readability
function(obj) {
var __t,
__p = '',
__j = Array.prototype.join,
print = function() { __p += __j.call(arguments, ''); };
with(obj || {}) {
__p += '\n ' + ((__t = ( a-b )) == null ? '' : __t ) + '\n';
}
return __p;
}
Demo: http://jsfiddle.net/ambiguous/6rPnB/
There you can see the with and the raw a-b subtraction expression.
Now that you know what's going wrong, how do you fix it? Three possibilities immediately present themselves:
Fix the server to return nicer things like "a_b": 6 instead of "a-b": 6 in the JSON.
Map the incoming JSON to something friendlier when you load it or before you hand your data to the template.
Bypass the with statement using the (documented) variable setting.
For the last one, you'd modify the template to look more like this:
<%= data['a-b'] %>
compile the template with something like this:
var t = _.template(template_text, undefined, { variable: 'data' });
and then call compiled template function as usual. You don't have to use data as your name, you just have to make sure the template and variable setting agree.
Demo: http://jsfiddle.net/ambiguous/eYn9m/

ExpressionEngine templates: pass a plugin/module's output as parameter to another plugin/module

Here's basically what I want to accomplish:
{exp:plugin1:method arg="{exp:plugin2:method}"}
I’ve tried a number of different approaches.
Approach 1:
{exp:plugin1:method arg="{exp:plugin2:method}"}
Result: Plugin1->method’s arg parameter value is the string, {exp:plugin2:method}, and it’s never parsed.
Approach 2:
My understanding of the parsing order suggests that this might have different results, but apparently it does not.
{preload_replace:replaced="{exp:plugin2:method}"}
{exp:plugin1:method arg="{replaced}"}
Result: The arg parameter has the same value as approach 1.
Approach 3:
First I define a snippet (snip), whose content is:
{exp:plugin2:method}
Then in the template:
{exp:plugin1:method arg="{snip}"}
Result: Same as approaches 1 and 2.
Approach 4:
Noting that plugins are processed in the order they appear, I have even tested simply placing an instance of {exp:plugin2:method} before the {exp:plugin1:method} call. My thinking is that I could wrap this first call in a regex replacement plugin in order to suppress output, but that it would trigger Plugin2’s parsing first.
{exp:plugin2:method}
{exp:plugin1:method arg="{exp:plugin2:method}"}
Result: Plugin1->method’s arg parameter value is the temporary hash placeholder for Plugin2->method’s output (MD5 I believe) that the Template class reserves until later.
Interesting approach. However, this can be achieved more simply like this:
{exp:plugin1:method arg="{exp:plugin2:method}" parse="inward"}
I have a workaround, but I'll wait a while to see if a better solution comes up before I accept my own answer. The workaround is to wrap plugin1 with plugin2 and replace template tags referring to its methods within the tagdata. Note that this requires a parse="inward" parameter on the plugin2 call.
In the template:
{exp:plugin2 parse="inward"}
{exp:plugin1:method arg="{someplugin2method}"}
{/exp:plugin2}
In the plugin class:
static $public_methods;
function __construct() {
// Actual construction code omitted...
if(($tagdata = $this->EE->TMPL->tagdata) !== false && trim($tagdata) !== '') {
if(!isset(self::$public_methods)) {
self::$public_methods = array();
$methods = get_class_methods($this);
foreach($methods as $method) {
if($method == get_class($this) || $method == '__construct') {
continue;
}
$reflection = new ReflectionMethod(get_class($this), $method);
if($reflection->isPublic()) {
self::$public_methods[] = $method;
}
}
self::$public_methods = implode('|', self::$public_methods);
}
$tagdata = preg_replace_callback('/\{(' . self::$public_methods . ')\}/',
array($this, 'tagdata_callback'), $tagdata);
$this->return_data = $tagdata;
}
}
private function tagdata_callback($matches) {
$method = $matches[1];
return $this->$method();
}
Caveats:
This can make for messier templates.
Maintaining a list of public methods apparently requires Reflection which is not available in PHP 4. You can, of course, maintain a list of expected methods manually.