ANTLR v.3- Use of syntactic predicate for lookahead - antlr

Still learning how to properly use ANTLR... Here's my problem.
Say you have a (subset) of an UML grammar and an ANTLR Lexer/Parser with the following rules :
// Parser Rules
model
: 'MODEL' IDENTIFIER list_dec
;
list_dec
: declaration*
;
declaration
: class_dec ';'
| association ';'
| generalization ';'
| aggregation ';'
;
class_dec
: 'CLASS' IDENTIFIER class_content
;
...
association
: 'RELATION' IDENTIFIER 'ROLES' two_roles
;
two_roles
: role ',' role
;
role
: 'CLASS' IDENTIFIER multiplicity
;
...
I would like the 'role' rule to only allow the IDENTIFIER token if it matches an existing class IDENTIFIER. In other words, if you are given an input file and you run the lexer/parser on it, then all the classes that are referenced (e.g. the IDENTIFIER in the association rule) should exist. The problem is that a class might not exist (yet) at runtime (it can be declared anywhere in the file). What is the best approach to this ?
Thanks in advance...

This is probably best done after parsing. The parser creates some sort of tree for you, and afterwards you walk the tree and collect information about declared classes, and walk it a second time to validate the role tree/rule.
Of course, some things could be done with a bit of custom code:
grammar G;
options {
...
}
#parser::members {
java.util.Set<String> declaredClasses = new java.util.HashSet<String>();
}
model
: 'MODEL' IDENTIFIER list_dec
;
...
class_dec
: 'CLASS' id=IDENTIFIER class_content
{
declaredClasses.add($id.text);
}
;
...
role
: 'CLASS' id=IDENTIFIER multiplicity
{
if(!declaredClasses.contains($id.text)) {
// warning or exception in here
}
}
;
...
EDIT
Or with custom methods:
#parser::members {
java.util.Set<String> declaredClasses = new java.util.HashSet<String>();
void addClass(String id) {
boolean added = declaredClasses.add(id);
if(!added) {
// 'id' was already present, do something, perhaps?
}
}
void checkClass(String id) {
if(!declaredClasses.contains(id)) {
// exception, error or warning?
}
}
}
...
class_dec
: 'CLASS' id=IDENTIFIER class_content {addClass($id.text);}
;
role
: 'CLASS' id=IDENTIFIER multiplicity {checkClass($id.text);}
;

Related

Mongodb query problem, how to get the matching items of the $or operator

Thank you for first.
MongoDB Version:4.2.11
I have a piece of data like this:
{
"name":...,
...
"administration" : [
{"name":...,"job":...},
{"name":...,"job":...}
],
"shareholder" : [
{"name":...,"proportion":...},
{"name":...,"proportion":...},
]
}
I want to match some specified data through regular expressions:
For a example:
db.collection.aggregate([
{"$match" :
{
"$or" :
[
{"name" : {"$regex": "Keyword"}}
{"administration.name": {"$regex": "Keyword"}},
{"shareholder.name": {"$regex": "Keyword"}},
]
}
},
])
I want to set a flag when the $or operator successfully matches any condition, which is represented by a custom field, for example:{"name" : {"$regex": "Keyword"}}Execute on success:
{"$project" :
{
"_id":false,
"name" : true,
"__regex_type__" : "name"
}
},
{"administration.name" : {"$regex": "Keyword"}}Execute on success:"__regex_type__" : "administration.name"
I try do this:
{"$project" :
{
"_id":false,
"name" : true,
"__regex_type__" :
{
"$switch":
{
"branches":
[
{"case": {"$regexMatch":{"input":"$name","regex": "Keyword"}},"then" : "name"},
{"case": {"$regexMatch":{"input":"$administration.name","regex": "Keyword"}},"then" : "administration.name"},
{"case": {"$regexMatch":{"input":"$shareholder.name","regex": "Keyword"}},"then" : "shareholder.name"},
],
"default" : "Other matches"
}
}
}
},
But $regexMatch cannot match the array,I tried to use $unwind again, but returned the number of many array members, which did not meet my starting point.
I want to implement the same function as mysql this SQL statement in mongodb, like this:
SELECT name,administration.name,shareholder.name,(
CASE
WHEN name REGEXP("Keyword") THEN "name"
WHEN administration.name REGEXP("Keyword") THEN "administration.name"
WHEN shareholder.name REGEXP("Keyword") THEN "shareholder.name"
END
)AS __regex_type__ FROM db.mytable WHERE
name REGEXP("Keyword") OR
shareholder.name REGEXP("Keyword") OR
administration.name REGEXP("Keyword");
Maybe this method is stupid, but I don’t have a better solution.
If you have a better solution, I would appreciate it!!!
Thank you!!!
Since $regexMatch does not handle arrays, use $filter to filter individual array elements with $regexMatch, then use $size to see how many elements matched.
[{"$match"=>{"$or"=>[{"a"=>"test"}, {"arr.a"=>"test"}]}},
{"$project"=>
{"a"=>1,
"arr"=>1,
"src"=>
{"$switch"=>
{"branches"=>
[{"case"=>{"$regexMatch"=>{"input"=>"$a", "regex"=>"test"}},
"then"=>"a"},
{"case"=>
{"$gte"=>
[{"$size"=>
{"$filter"=>
{"input"=>"$arr.a",
"cond"=>
{"$regexMatch"=>{"input"=>"$$this", "regex"=>"test"}}}}},
1]},
"then"=>"arr.a"}],
"default"=>"def"}}}}]
[{"_id"=>BSON::ObjectId('5ffb2df748966813f82f15ad'), "a"=>"test", "src"=>"a"},
{"_id"=>BSON::ObjectId('5ffb2df748966813f82f15ae'),
"arr"=>[{"a"=>"test"}],
"src"=>"arr.a"}]

Complex MongodbDB query in Mule4

I am trying to make a Mongodb query in Mule with the $in function, but mule says Invalid input '$', expected Namespace or NameIdentifier
have a collection that stores user authorization
{
"_id" : ObjectId("584a0dea073d4c3e976140a9"),
"partnerDataAccess" : [
{
"factoryID" : "Fac-1",
"partnerID" : "Part-1"
}
],
"userID" : "z12",
}
{
"_id" : ObjectId("584f5eba073d4c3e976140ab"),
"partnerDataAccess" : [
{
"factoryID" : "Fac-1",
"partnerID" : "Part-2"
},
{
"factoryID" : "Fac-2",
"partnerID" : "Part-2"
}
],
"userID" : "w12",
}
the flow will submit a userID and partnerID and query the database to see if authorization exist
when I query from Robo 3T, I write queries like this
e.g. user w12 and partner Part-2
db.getCollection('user').find({
userID:"w12", "partnerDataAccess.partnerID": {$in : ["Part-2", "ALL"]}
})
The $in was used because there is the "ALL" setting for admins
but while I try to put the find part into the Mongodb connector, Mule gives error during development and runtime
Hardcoded:
<mongo:find-one-document collectionName="user" doc:name="Find one document" doc:id="a03a6689-6b9d-473c-b8a6-3b8d1e989e38" config-ref="MongoDB_Config">
<mongo:find-query ><![CDATA[#[{
userID:"w12",
"partnerDataAccess.partnerID": {$in : ["Part-2", "ALL"]}
}]]]></mongo:find-query>
</mongo:find-one-document>
parametized
<mongo:find-one-document collectionName="user" doc:name="Find one document" doc:id="a03a6689-6b9d-473c-b8a6-3b8d1e989e38" config-ref="MongoDB_Config">
<mongo:find-query ><![CDATA[#[{
userID: payload.User,
"partnerDataAccess.partnerID": {$in : [ payload.partner, "ALL"]}
}]]]></mongo:find-query>
</mongo:find-one-document>
Error:
during development:
Invalid input '$', expected } or ~ or , (line 3, column 38):
Runtime:
Message : "Script '{
userID:"w12",
"partnerDataAccess.partnerID": {$in : ["Part-2", "ALL"]}
} ' has errors:
Invalid input '$', expected Namespace or NameIdentifier (line 3, column 38):
at 3 : 3" evaluating expression:
I have tried removing the $ or escaping the $ with backslash but it does not work
I know my query is not actually complex, welcome any help
seems to have found the correct way
><![CDATA[#[{
userID:"w12",
"partnerDataAccess.partnerID": {"\$in" : ["Part-2", "ALL"]}
}]]]>

Security rules and query for a document sharing app

I make a notes-style app with collaborative features and want to set-up safe security rules.
The problem is: my security rules do not work with my database query.
The Firebase security rules simulator shows correct results when I test access to notes for authenticated users.
But in the app I get the message "Listener at /notes failed: permission_denied".
I've found some nice examples of security rules here
Firebase: Security rules for a collaborative app
and here
https://gist.github.com/katowulf/4741111
but these are not that different from what I have.
I suspect the problem could either be in the query or in the lack of indexing rules (".indexOn").
My query is:
- (void)setupQuery {
NSString *email = [FirebaseAuthorization shared].currentUserEmail;
self.reference = [[[FIRDatabase database] reference] child:#"notes"];
NSString *query = [NSString stringWithFormat:#"document/users/%#", email.MD5String];
self.query = [[self.reference queryOrderedByChild:query] queryEqualToValue:#(YES)];
}
My security rules are:
{
"rules": {
"notes" : {
"$note_id" : {
".read": "data.child('document/users/'+root.child('users/'+auth.uid+'/email_md5').val()).val() === true",
".write": "(data.child('document/users/'+root.child('users/'+auth.uid+'/email_md5').val()).val() === true) || (root.child('users/'+auth.uid+'/email').val() === root.child('users/'+newData.child('document/author').val()+'/email').val())",
".indexOn": "document/users"
}
},
"users" : {
"$user_id" : {
".read": "auth.uid === $user_id",
".write": " ( auth.uid == newData.val() ) || ( auth.uid == $user_id )"
}
}
}
}
And my database structure is:
{
"notes" : {
"NOTE_ID_1" : {
"document" : {
"author" : "user_id_1",
"users" : {
"email_1_md5#email-com" : true,
"email_2_md5#email-com" : true
}
}
}
"NOTE_ID_2" : {
"document" : {
"author" : "user_id_2",
"users" : {
"email_3_md5#email-com" : true,
"email_4_md5#email-com" : true,
}
}
}
}
"users" : {
"iser_id_1" : {
"email" : "email_1#email.com",
"email_md5" : "email_2_md5#email-com"
}
}
}
I expect the query to work with tight security rules (each user has access to his notes only), but now it only works with loose security rules (each user has access to all notes).
Firebase security rules don't filter the data on your behalf. They merely enforce that all data access is authorized.
This it the code for your query
self.reference = [[[FIRDatabase database] reference] child:#"notes"];
NSString *query = [NSString stringWithFormat:#"document/users/%#", email.MD5String];
self.query = [[self.reference queryOrderedByChild:query] queryEqualToValue:#(YES)];
In order to run this code, the user must have some form of read permission at notes. Since nobody has read permission on that node, the rules engine rejects the read.
This is known as rules are not filters in the documentation, and in many other questions about the topic.
Note that you can nowadays use security rules to allow reads with certain queries, through query-based rules. When using this, you build the relevant query in your code, and then use security rules to only allow data access with that specific query.
In your case this would be a .read rule on /notes that matches the query you're building. It'd be something like this for your use-case
{
"rules": {
"notes" : {
".read": "
query.orderByChild == 'document/users/'+auth.uid &&
query.equalTo == true
"
}
}
}
Note though that I'm not sure whether this condition actually matches your query.
Even if it does, the lack of an index would make the security point moot (as without an index all filtering is done on the client). For more on this, see my answer here: Firebase query if child of child contains a value. Such an inverted index would also allow you to implement security in your fan-out (write) logic, instead of in the read operation, ensuring much better read scalability.

Grammar.parse seems to loop forever and use 100% CPU

Reposted from the #perl6 IRC channel, by jkramer, with permission
I'm playing with grammars and trying to parse an ini-style file but somehow Grammar.parse seems to loop forever and use 100% CPU. Any ideas what's wrong here?
grammar Format {
token TOP {
[
<comment>*
[
<section>
[ <line> | <comment> ]*
]*
]*
}
rule section {
'[' <identifier> <subsection>? ']'
}
rule subsection {
'"' <identifier> '"'
}
rule identifier {
<[A..Za..z]> <[A..Za..z0..9_-]>+
}
rule comment {
<[";]> .*? $$
}
rule line {
<key> '=' <value>
}
rule key {
<identifier>
}
rule value {
.*? $$
}
}
Format.parse('lol.conf'.IO.slurp)
Token TOP has the * quantifier on a subregex that can parse an empty string (because both <comment> and the group that contains <section> have a * quantifier on their own).
If the inner subregex matches the empty string, it can do so infinitely many times without advancing the cursor. Currently, Perl 6 has no protection against this kind of error.
It looks to me like you could simplify your code to
token TOP {
<comment>*
[
<section>
[ <line> | <comment> ]*
]*
}
(there is no need for the outer group of [...]*, because the last <comment> also matches comments before sections.

Two "id" fields in one MongoDB collection with Rails 3?

I've got a Rails 3.0.9 project using the latest version of MongoDB and Mongoid 2.2.
I imported a CSV with an "id" field into a MongoDB collection named College, resulting in a collection like so:
{ "_id" : ObjectID("abc123"), "id" : ######, ... }
Observations:
The show action results in a URL utilizing the ObjectID
Displaying 'college.id' in index.html.erb displays the ObjectID
Questions:
How do I use the original "id" field as the parameter
Is "id" reserved by MongoDB, meaning I need to rename the "id" field in the
College collection (perhaps to "code") - if so, how?
Thanks!
Update
Answer:
db.colleges.update( { "name" : { $exists : true } } , { $rename : { "id" : "code" } }, false, true )
I used "name" since that was a field I could check for the existence.
_id is a reserved and required property in MongoDB - I think mongoid is mapping id to _id since that makes sense. There might be a way to access the id property through mongoid but I think you are much better off renaming the id column to something else to avoid confusion in the future.
{ $rename : { old_field_name : new_field_name } }
will rename the field name in a document (mongo 1.7.2+).
so
db.college.update({ "_id" : { $exists : true }}, { $rename : { 'id' : 'code' } }, false, true);
should update every record in that collection and rename the id field to code.
(obviously test this before running in any important data)