#name and ##keyword not working with rule annotations - annotations

I'm trying to use ##keyword and #name in my grammar but tatsu seems to ignore it if rules tagged #name are annotated.
Am I missing something?
To reproduce the behaviour, I provide the following example:
This one works:
import tatsu
GRAMMAR = '''
##grammar::TestGrammar
##keyword :: if var
##whitespace :: /[\t ]+/
start =
var identifier ";" { var identifier ";" }* $
;
if = "if";
var = "var";
#name
identifier =
/[a-z]+/;
'''
if __name__ == '__main__':
import pprint
import json
from tatsu import parse
from tatsu.util import asjson
ast = parse(GRAMMAR, 'var xyz; var if;')
pprint.pprint(ast, indent=2, width=20)
As expected, tatsu will report
tatsu.exceptions.FailedParse: (1:16) "if" is a reserved word :
var xyz; var if;
^
If I annotate the identifier rule by
#name
identifier =
id:
/[a-z]+/;
the same python program will output
( 'var',
{'id': 'xyz'},
';',
[ [ 'var',
{'id': 'if'},
';']])

Basically, you should not define:
#name
identifier =
id:
/[a-z]+/;
TatSu will match the ast resulting from the rule against the names ##keyword, and the output of the above rule will always be {'id': 'something'}, which will not match any keyword.
Perhaps what you want is something like:
identifier = id:_identifier;
#name
_identifier = /[a-z]+/;

Related

How to Import xPath fields of XML to Pimcore DataDirector dataport raw data fields?

Pimcore has powerfull plugin DataDirector for import automation.
It proposes manual configuration of fields to import and their mapping to Pimcore fields https://www.youtube.com/watch?v=nyhKJTzTq-4&list=PL4-QRNfdsdKIfzQIP-c9hRruXf0r48fjt
It works fine if you have 10-50 fields.
How to import that configuration from some csv file whan you have 700+ fields?
There is no ability to import using interface of commandline DataDirector API.
I tried to request such functionality creation from vendor -- it costs.
I tried to edit it in MySQL but it is strictly coupled to other data, see: SELECT sourceconfig FROM plugin_pim_dataport;
Solution:
Each dataport can be exported and imported to JSON. This is our chance.
create sample dataport using your source XML
export it to sample.json
unserialize $json_a['plugin_pim_dataport']['sourceconfig'] and $json_a['plugin_pim_rawitemField'] containers
$string = file_get_contents(
"sample.json"
);
$json_a = json_decode($string, true);
$sourceConfig = $json_a['plugin_pim_dataport']['sourceconfig'];
$sourceConfig = unserialize($sourceConfig, ['allowed_classes' => false]);
$fieldsConfig = $json_a['plugin_pim_rawitemField'];
add new fields to them from any source e.g. CSV
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
$row++;
$id = $max + 1 + $row;
$data = $this->addField($id, $data[0], $data[1]);
$sourceConfig['fields']['field_' . ($id + 1)] = $data['sourceConfig'];
$fieldsConfig[$id] = $data['fieldsConfig'];
}
public function addField(
$id,
$name = 'ObjectBrick/Field',
$xpath = '//*[.//MainContainer = "systeme"]//*[.//Description = "SomeAttribute"]/anyPath/SampleContainer'
) {
$res = [];
$res['fieldsConfig'] = [
"dataportId" => "1",
"fieldNo" => $id + 1,
"name" => $name,
"priority" => $id
];
$res['sourceConfig'] = [
'xpath' => $xpath,
'multiValues' => false,
];
return $res;
}
serialize, save to JSON, import to your dataport.

Yii2 prepared statements fail to evaluate parameters wrapped in quotes

$params = [
':x1' => $locationBox['leftLongitude'],
':y1' => $locationBox['topLatitude'],
':x2' => $locationBox['rightLongitude'],
':y2' => $locationBox['topLatitude'],
':x3' => $locationBox['rightLongitude'],
':y3' => $locationBox['bottomLatitude'],
':x4' => $locationBox['leftLongitude'],
':y4' => $locationBox['bottomLatitude'],
':x5' => $locationBox['leftLongitude'],
':y5' => $locationBox['topLatitude']
];
$sql = "
....
INNER JOIN tag_geo T3 ON (T3.id = T2.tag_id_b AND ST_Covers(ST_GeogFromText('POLYGON((:x1 :y1, :x2 :y2, :x3 :y3, :x4 :y4, :x5 :y5))'), T3.geo_location));
";
$connection = \Yii::$app->getDb();
$command = $connection->createCommand($sql);
$command->bindValues($params);
$result = $command->queryAll();
I get an error:
SQLSTATE[HY093]: Invalid parameter number: :x1 Failed to prepare SQL
Notice single tick ('POLYGON), if I remove the ticks that wrap the POLYGON function the parameters get evaluated but another error occurred, since this POLYGON must be in single quotes.
Because of the single quotes around POLYGON function, the polygon part is recognized by the db engine as it is, e.g. as the string POLYGON((:x1 :y1, :x2 :y2, :x3 :y3, :x4 :y4, :x5 :y5)). So you should implement only one marker (:polygon) in the sql statement istead:
<?php
$sql = "
....
INNER JOIN tag_geo T3 ON (T3.id = T2.tag_id_b AND ST_Covers(ST_GeogFromText(:polygon), T3.geo_location));
";
$params = [
":poligon" => sprintf( // Output: POLYGON((x1-value y1-value, x2-value y2-value, ...))
"POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))"
, $locationBox['leftLongitude']
, $locationBox['topLatitude']
, $locationBox['rightLongitude']
, $locationBox['topLatitude']
, $locationBox['rightLongitude']
, $locationBox['bottomLatitude']
, $locationBox['leftLongitude']
, $locationBox['bottomLatitude']
, $locationBox['leftLongitude']
, $locationBox['topLatitude']
)
];
//...
Of course, if it still doesn't work use question mark markers (?) instead.
This situation is similar with the one where one tries to prepare an sql statement which uses the LIKE keyword. An example here: Syntax of LIKE in PreparedStatement.

Difficulty rendering form inside a loop

I'm new to web.py and am having difficulty with the following:
in app.py
args = ()
for i in range(4):
args = args + (form.Checkbox('followup'+str(i)), )
my_form = form.Form(*args)
in my_template.html
$for i in range(4):
$ name = "followup"+ str(i)
$name $:form.$name.render() <br>
when I run this I get the following error:
'str' object has no attribute 'render'
How should I change my template so that I will have 4 checkboxes?
Any help would be greatly appreciated.
The problem is $:form.$name resolves to a string, prior to the call to render(). You can fix that by replacing it with $:form[name]. You're still in the "python" context with form[name], so you should use name rather than $name.
=== my_template.html ===
$def with(form)
$for i in range(4):
$ name = 'followup' + str(i)
$name $:form[name].render()<br/>
or, even simpler:
=== my_template.html ===
$def with(form)
$for i in form.inputs:
$i.description $:i.render()<br/>

Using Parse::Lex, is there a way to return tokens only in certain states/conditions

Assuming that i need to tokenize and parse only multiline comments, how will i do that using Parse::Lex. When using flex-bison, the default action for any pattern in the rules section of the lex file used to be 'skip'.
%%
.* ;
%%
How to do this here ?
[EDIT] Well, i tried that, i'm still missing something - here is my code - and result. Where have i gone wrong ??
my simplified lex file:
use Parse::Lex;
use Regexp::Common;
use YParser;
my $lexer;
my #token = (
qw|esp:TA abcdefgh|,
qw(esp:REST .|\n),
);
Parse::Lex->trace;
Parse::Lex->exclusive('esp');
$lexer = Parse::Lex->new(#token);
$lexer->from(\*STDIN);
$lexer->skip(qr! [ \t]+ | $RE{balanced}{-begin=>'/*'}{-end=>'*/'} !xms);
$lexer->start('esp');
my $j = YParser->new();
$j->YYParse(yylex => \&lex);
sub lex {
my $token = $lexer->next;
return ('', undef) if $lexer->eoi;
if ($token->name eq 'TA' || $token->name eq 'REST') {
return ($token->name, {LINENO => $lexer->line, TEXT => $token->text});
}
}
my simplified grammar file
% token TA REST
%%
Program: Element
| Program Element
;
Element: TA
| REST
;
%%
Input file:
abcdefgh
/*sdf*/
Result:
perl lexfile.pl < inputfile
Trace is ON in class Parse::Lex
Can't call method "name" on an undefined value at qnlex.pl line 26, <STDIN> line 1.
Use the skip setting, shown here using Regexp::Common to help construct a regexp matching balanced pairs of comment delimiters. I've assumed /* */ as the comment delimiters, but they could be anything.
$lexer->skip(qr! [ \t]+ | $RE{balanced}{-begin=>'/*'}{-end=>'*/'} !xms);
The [ \t]+ alternative is left in place since that's the default.
Well, i figured this out :) Very simple - all i have to do is make the lex get the next token when encountering tokens i want to skip. Below is code to skip passing the token 'REST' to the parser.
sub lex {
my $token;
NEXTTOKEN:
$token = $lexer->next;
return ('', undef) if $lexer->eoi;
if ($token->name eq 'TA') {
return ($token->name, {LINENO => $lexer->line, TEXT => $token->text});
}
elsif ($token->name eq 'REST') {
goto NEXTTOKEN;
}
}

Zend Framework - Issue with delete from database code

In my Application_Model_DbTable_User, I have the following function:
public function deleteUser($username)
{
$this->delete('username = ' . (string) $username);
}
This function is being called from my AdminController, with this three lines of code.
$uname = $this->getRequest()->getParam('username');
$user = new Application_Model_DbTable_User();
$user->deleteUser($uname);
This error however, turns up.
Column not found: 1054 Unknown column 'test' in 'where clause'
With test being the user I am trying to delete.
This code is adapted from a previous code which deletes based on id, a INT field, which works perfectly fine. What am I doing wrong? I would be happy to give more detailed codes if needed. Thanks.
Your query isn't quoted:
$this->delete('username = ' . (string) $username);
This equates to:
WHERE username = test
If you use the where() method, it will do this for you:
$table->where('username = ?', $username);
Or (like the example in the docs):
$where = $table->getAdapter()->quoteInto('bug_id = ?', 1235);
$table->delete($where);