Is there some way to test my grammar which refer to EAttributes? - dsl

I am stuck at one point as I am unable to test my grammar using Junit test cases. Below is my complete grammar.
ExpressionModel:
expression=Expression;
Expression:
Comparison;
Comparison returns Expression:
Primary ({Comparison.left=current} op=("=" | "!=" | ">=" | "<=" | ">" | "<")right=Primary)* ;
Primary returns Expression:
'(' Expression ')' |
{Not} "!" expression=Primary |
Atomic;
Atomic returns Expression:
{IntConstant} value=INT |
{StringConstant} value=STRING |
{BoolConstant} value=('true' | 'false') |
{VariableRef} variable=[ecore::EAttribute|QualifiedName];
QualifiedName:
ID ('.' ID)*;
If i test my code generator for this grammar by launching an eclipse instance, all i have to do is create an ".ecore" file in the src folder and another file for my grammar and i am easily able to access my variable created in ".ecore" file.
What i mean to say is after launching an eclipse instance, i created a "test.ecore" file having a class "vars" and an EAttribute "alpha" which is of EString type and i created another file "testModel.dsl" now i am easily able to access "vars.alpha" inside this file. Can anyone please help me how to perform same steps if i want to test my code generator without launching an eclipse instance. It would be of great help to me.
I am trying to test below test case-->
#RunWith(XtextRunner)
#InjectWith(ExtendedMyDslInjectorProvider)
class ExpressionDSLCompilationTest {
#Inject extension CompilationTestHelper
#Inject extension ParseHelper
#Inject extension ReflectExtensions
#Inject extension IQualifiedNameProvider
#Inject Provider<XtextResourceSet> resourceSetProvider
#Test
def void ReturnVariable() {
val fooPackage = EcoreFactory::eINSTANCE.createEPackage
fooPackage.name = "foo"
fooPackage.nsPrefix = "foo"
fooPackage.nsURI = "http://foo"
val fooClass = EcoreFactory::eINSTANCE.createEClass
fooClass.name = "vars"
fooPackage.EClassifiers.add(fooClass)
val fooattr = EcoreFactory::eINSTANCE.createEAttribute
fooattr.name = "alpha"
fooattr.EType = EcorePackage::eINSTANCE.EString
val resourceset = resourceSetProvider.get
val resource = resourceset.createResource(URI.createURI("hiTest.ecore"))
fooClass.EStructuralFeatures.add(attr)
resource.contents.add(fooPackage)
// val model = '''foo.vars.alpha'''.parse(resourceset)
'''foo.vars.alpha'''.compile [
getCompiledClass.newInstance => [
assertEquals(
"foo.vars.alpha",
it.invoke("generateCodeForExpression")
)
]
]
}
class ExtendedMyDslInjectorProvider extends ExpressionDSLInjectorProvider {
override internalCreateInjector() {
EcoreSupportStandaloneSetup.setup
return super.internalCreateInjector
}
}
I have already followed steps mentioned in https://www.eclipse.org/forums/index.php/t/1081785/
but this is of no use as it is giving me null pointer exception when i run my test case. Any help will be appreciated.
I am adding a piece of my code generator and highlighting the piece where it is giving error. Hope it will be enough.
class ExpressionDSLGenerator extends AbstractGenerator {
#Inject extension IQualifiedNameProvider
/*Generate Java Code with the name of java file as same as that of ".mexpression" file*/
override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
var str = ""
for (e : resource.allContents.toIterable.filter(ExpressionModel)) {
str += e.checkCompileForFunctionsOrExpresssion
}
fsa.generateFile('''«resource.URI.lastSegment.substring(0,resource.URI.lastSegment.indexOf("."))».java''', str)
}
/*Generates the body of .Java File having class and single checkExpression
Method for Expressions and Functions Separately */
def String checkCompileForFunctionsOrExpresssion(ExpressionModel model) {
'''
public class «model.eResource.URI.lastSegment.substring(0,model.eResource.URI.lastSegment.indexOf("."))»{
public «getExpressionReturnType(model)» generateCodeForExpression() {
return «getExpressionReturnBody(model.expression)»;
}
}
'''
}
def getExpressionReturnType(ExpressionModel model) {
/*If expression is not a comparison and just a single variable or value, we must return value's data type*/
if (model.eContents.size < 2) {
model.expression.getValueReturnType
} /* Return boolean since it will be a comparison*/ else {
"boolean"
}
}
// Utility method to get return type of an expression
def getValueReturnType(Expression e) {
if (e.isInt) {
"int"
} else if (e.isString) {
"String"
} else if (e.isVariable) {
e.variableReturnsType
} else {
"boolean"
}
}
// Utility method to set return type on the basis of variable's return type
def getVariableReturnsType(Expression e) {
switch (e) {
VariableRef: {
<part giving error:-->e.variable.EType is coming to be null, hence null pointer exception>**e.variable.EType.name.equals("EString") ? "String" : e.variable.EType.name.equals(
"EInt") ? "int" : "boolean"**</part giving error>
}
}
}
// Utility method to get return body of an expression
def String getExpressionReturnBody(Expression e) {
switch (e) {
VariableRef: {
getVariableReturn(e.variable)
}
IntConstant: {
e.value.intConstantReturn
}
BoolConstant: {
e.value.booleanConstantReturn
}
StringConstant: {
e.value.stringConstantReturn
}
Not: {
e.expression.notExpressionReturn
}
Comparison: {
val left = e.left.getExpressionReturnBody as String
val right = e.right.getExpressionReturnBody as String
if (e.left.isString) {
getStringCompareBody(left, right, e.op)
} else if (e.left.isBoolean) {
getBoolCompareBody(left, right, e.op)
} else if (e.left.isVariable) {
getVariableReturnsBody(e.left, left, right, e.op)
} else {
getOthersCompareBody(left, right, e.op)
}
}
}
}
// return variable's full name
def getVariableReturn(EAttribute e) {
e.fullyQualifiedName + ""
}
// return integer value
def getIntConstantReturn(int value) {
value + ""
}
// return boolean value
def getBooleanConstantReturn(String value) {
Boolean::parseBoolean(value) + ""
}
// return string value
def getStringConstantReturn(String value) {
"\"" + value + "\""
}
// return not value of the given expression
def getNotExpressionReturn(Expression value) {
"!(" + value.getExpressionReturnBody + ")"
}
// Utility method to check if Expression is a String
def isString(Expression e) {
switch (e) {
StringConstant: {
true
}
default: {
false
}
}
}
// Utility method to check if Expression is a boolean
def isBoolean(Expression e) {
switch (e) {
BoolConstant: {
true
}
default: {
false
}
}
}
// Utility method to check if Expression is a variable
def isVariable(Expression e) {
switch (e) {
VariableRef: {
true
}
default: {
false
}
}
}
// return body of comparison expression for string
def getStringCompareBody(String left, String right, String op) {
switch (op) {
case '=': "(" + left + ".equals(" + right + "))"
case '!=': "!(" + left + ".equals(" + right + "))"
default: false + ""
}
}
// return body of comparison expression for boolean
def getBoolCompareBody(String left, String right, String op) {
switch (op) {
case '=': "(" + left + "==" + right + ")"
case '!=': "(" + left + "!=" + right + ")"
default: false + ""
}
}
// return body of comparison expression for other's
def getOthersCompareBody(String left, String right, String op) {
switch (op) {
case '<': "(" + left + "<" + right + ")"
case '>': "(" + left + ">" + right + ")"
case '>=': "(" + left + ">=" + right + ")"
case '<=': "(" + left + "<=" + right + ")"
case '=': "(" + left + "==" + right + ")"
case '!=': "!(" + left + "==" + right + ")"
default: false + ""
}
}
// body for variable type
def getVariableReturnsBody(Expression e, String left, String right, String operator) {
switch (e) {
VariableRef: {
e.variable.EType.name.equals("EString")
? getStringCompareBody(left, right, operator) : e.variable.EType.name.equals(
"EBoolean") ? getBoolCompareBody(left, right, operator) : getOthersCompareBody(left, right,
operator)
}
}
}
}

#Inject extension ValidationTestHelper h
...
val model = '''foo.vars.alpha'''.parse(resourceset)
model.assertNoErrors
which is the adaption of the forum snippet to your context works perfectly fine
if you want to use CompilationTestHelper then you have to customize it for the resourcetset to add the resource there
e.g.
val model = '''foo.vars.alpha'''.parse(resourceset)
model.assertNoErrors
compile(resourceset) [
getCompiledClass.newInstance => [
assertEquals(
"foo.vars.alpha",
it.invoke("generateCodeForExpression")
)
]
]

Related

concurrent query and insert have any side effect in android with objectbox?

In my android project, I use objectbox as database, if I insert with lock and query without lock, is there any side effect ? such as crash and so on.
fun query(uniqueId: String = ""): MutableList<T> {
if (box.store.isClosed) return mutableListOf()
val query = box.query()
withQueryBuilder(query, uniqueId)
//开始
return query.build().find()
}
private fun putInner(entity: T): Long {
synchronized(box.store) {
if (box.store.isClosed) return -1
if (entity.unique.isBlank()) {
entity.unique = entity.providerUnique()
}
entity.timestamp = System.currentTimeMillis()
return try {
box.put(entity).let { id -> entity.id = id }
entity.id
} catch (ex: Exception) {
-1
}
}
}

Semantically disambiguating an ambiguous syntax

Using Antlr 4 I have a situation I am not sure how to resolve. I originally asked the question at https://groups.google.com/forum/#!topic/antlr-discussion/1yxxxAvU678 on the Antlr discussion forum. But that forum does not seem to get a lot of traffic, so I am asking again here.
I have the following grammar:
expression
: ...
| path
;
path
: ...
| dotIdentifierSequence
;
dotIdentifierSequence
: identifier (DOT identifier)*
;
The concern here is that dotIdentifierSequence can mean a number of things semantically, and not all of them are "paths". But at the moment they are all recognized as paths in the parse tree and then I need to handle them specially in my visitor.
But what I'd really like is a way to express the dotIdentifierSequence usages that are not paths into the expression rule rather than in the path rule, and still have dotIdentifierSequence in path to handle path usages.
To be clear, a dotIdentifierSequence might be any of the following:
A path - this is a SQL-like grammar and a path expression would be like a table or column reference in SQL, e.g. a.b.c
A Java class name - e.g. com.acme.SomeJavaType
A static Java field reference - e.g. com.acme.SomeJavaType.SOME_FIELD
A Java enum value reference - e.g. com.acme.Gender.MALE
The idea is that during visitation "dotIdentifierSequence as a path" resolves as a very different type from the other usages.
Any idea how I can do this?
The issue here is that you're trying to make a distinction between "paths" while being created in the parser. Constructing paths inside the lexer would be easier (pseudo code follows):
grammar T;
tokens {
JAVA_TYPE_PATH,
JAVA_FIELD_PATH
}
// parser rules
PATH
: IDENTIFIER ('.' IDENTIFIER)*
{
String s = getText();
if (s is a Java class) {
setType(JAVA_TYPE_PATH);
} else if (s is a Java field) {
setType(JAVA_FIELD_PATH);
}
}
;
fragment IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]*;
and then in the parser you would do:
expression
: JAVA_TYPE_PATH #javaTypeExpression
| JAVA_FIELD_PATH #javaFieldExpression
| PATH #pathExpression
;
But then, of course, input like this java./*comment*/lang.String would be tokenized wrongly.
Handling it all in the parser would mean manually looking ahead in the token stream and checking if either a Java type, or field exists.
A quick demo:
grammar T;
#parser::members {
String getPathAhead() {
Token token = _input.LT(1);
if (token.getType() != IDENTIFIER) {
return null;
}
StringBuilder builder = new StringBuilder(token.getText());
// Try to collect ('.' IDENTIFIER)*
for (int stepsAhead = 2; ; stepsAhead += 2) {
Token expectedDot = _input.LT(stepsAhead);
Token expectedIdentifier = _input.LT(stepsAhead + 1);
if (expectedDot.getType() != DOT || expectedIdentifier.getType() != IDENTIFIER) {
break;
}
builder.append('.').append(expectedIdentifier.getText());
}
return builder.toString();
}
boolean javaTypeAhead() {
String path = getPathAhead();
if (path == null) {
return false;
}
try {
return Class.forName(path) != null;
} catch (Exception e) {
return false;
}
}
boolean javaFieldAhead() {
String path = getPathAhead();
if (path == null || !path.contains(".")) {
return false;
}
int lastDot = path.lastIndexOf('.');
String typeName = path.substring(0, lastDot);
String fieldName = path.substring(lastDot + 1);
try {
Class<?> clazz = Class.forName(typeName);
return clazz.getField(fieldName) != null;
} catch (Exception e) {
return false;
}
}
}
expression
: {javaTypeAhead()}? path #javaTypeExpression
| {javaFieldAhead()}? path #javaFieldExpression
| path #pathExpression
;
path
: dotIdentifierSequence
;
dotIdentifierSequence
: IDENTIFIER (DOT IDENTIFIER)*
;
IDENTIFIER
: [a-zA-Z_] [a-zA-Z_0-9]*
;
DOT
: '.'
;
which can be tested with the following class:
package tl.antlr4;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class Main {
public static void main(String[] args) {
String[] tests = {
"mu",
"tl.antlr4.The",
"java.lang.String",
"foo.bar.Baz",
"tl.antlr4.The.answer",
"tl.antlr4.The.ANSWER"
};
for (String test : tests) {
TLexer lexer = new TLexer(new ANTLRInputStream(test));
TParser parser = new TParser(new CommonTokenStream(lexer));
ParseTreeWalker.DEFAULT.walk(new TestListener(), parser.expression());
}
}
}
class TestListener extends TBaseListener {
#Override
public void enterJavaTypeExpression(#NotNull TParser.JavaTypeExpressionContext ctx) {
System.out.println("JavaTypeExpression -> " + ctx.getText());
}
#Override
public void enterJavaFieldExpression(#NotNull TParser.JavaFieldExpressionContext ctx) {
System.out.println("JavaFieldExpression -> " + ctx.getText());
}
#Override
public void enterPathExpression(#NotNull TParser.PathExpressionContext ctx) {
System.out.println("PathExpression -> " + ctx.getText());
}
}
class The {
public static final int ANSWER = 42;
}
which would print the following to the console:
PathExpression -> mu
JavaTypeExpression -> tl.antlr4.The
JavaTypeExpression -> java.lang.String
PathExpression -> foo.bar.Baz
PathExpression -> tl.antlr4.The.answer
JavaFieldExpression -> tl.antlr4.The.ANSWER

Creation of custom comparator for map in groovy

I have class in groovy
class WhsDBFile {
String name
String path
String svnUrl
String lastRevision
String lastMessage
String lastAuthor
}
and map object
def installFiles = [:]
that filled in loop by
WhsDBFile dbFile = new WhsDBFile()
installFiles[svnDiffStatus.getPath()] = dbFile
now i try to sort this with custom Comparator
Comparator<WhsDBFile> whsDBFileComparator = new Comparator<WhsDBFile>() {
#Override
int compare(WhsDBFile o1, WhsDBFile o2) {
if (FilenameUtils.getBaseName(o1.name) > FilenameUtils.getBaseName(o2.name)) {
return 1
} else if (FilenameUtils.getBaseName(o1.name) > FilenameUtils.getBaseName(o2.name)) {
return -1
}
return 0
}
}
installFiles.sort(whsDBFileComparator);
but get this error java.lang.String cannot be cast to WhsDBFile
Any idea how to fix this? I need to use custom comparator, cause it will be much more complex in the future.
p.s. full source of sample gradle task (description of WhsDBFile class is above):
project.task('sample') << {
def installFiles = [:]
WhsDBFile dbFile = new WhsDBFile()
installFiles['sample_path'] = dbFile
Comparator<WhsDBFile> whsDBFileComparator = new Comparator<WhsDBFile>() {
#Override
int compare(WhsDBFile o1, WhsDBFile o2) {
if (o1.name > o2.name) {
return 1
} else if (o1.name > o2.name) {
return -1
}
return 0
}
}
installFiles.sort(whsDBFileComparator);
}
You can try to sort the entrySet() :
def sortedEntries = installFiles.entrySet().sort { entry1, entry2 ->
entry1.value <=> entry2.value
}
you will have a collection of Map.Entry with this invocation. In order to have a map, you can then collectEntries() the result :
def sortedMap = installFiles.entrySet().sort { entry1, entry2 ->
...
}.collectEntries()
sort can also take a closure as parameter which coerces to a Comparator's compare() method as below. Usage of toUpper() method just mimics the implementation of FilenameUtils.getBaseName().
installFiles.sort { a, b ->
toUpper(a.value.name) <=> toUpper(b.value.name)
}
// Replicating implementation of FilenameUtils.getBaseName()
// This can be customized according to requirement
String toUpper(String a) {
a.toUpperCase()
}

Create Address String from CLPlacemark

Can anyone suggest a cleaner was to create a address string from a CLPlacemark.
At present I am using this extension
extension CLPlacemark {
func makeAddressString() -> String {
var address = ""
if subThoroughfare != nil { address = address + " " + subThoroughfare! }
if thoroughfare != nil { address = address + " " + thoroughfare! }
if locality != nil { address = address + " " + locality! }
if administrativeArea != nil { address = address + " " + administrativeArea! }
if postalCode != nil { address = address + " " + postalCode! }
if country != nil { address = address + " " + country! }
return address
}
}
All the instance variables are optionals hence the checking for nil, and I want in the same order of street number, to street, etc.
CLPlacemark has a postalAddress property of type CNPostalAddress. You can format that into a locale-aware string using the CNPostalAddressFormatter.
let formatter = CNPostalAddressFormatter()
let addressString = formatter.string(from: placemark.postalAddress)
You can now flatMap on an Array of Optionals in order to filter out nil values (I think this works since Swift 2). Your example is now basically a one-liner (if you delete the line breaks I inserted for readability):
extension CLPlacemark {
func makeAddressString() -> String {
return [subThoroughfare, thoroughfare, locality, administrativeArea, postalCode, country]
.flatMap({ $0 })
.joined(separator: " ")
}
}
You can take this further, and use nested arrays to achieve more complex styles. Here is an example of a German style shortened address (MyStreet 1, 1030 City):
extension CLPlacemark {
var customAddress: String {
get {
return [[thoroughfare, subThoroughfare], [postalCode, locality]]
.map { (subComponents) -> String in
// Combine subcomponents with spaces (e.g. 1030 + City),
subComponents.flatMap({ $0 }).joined(separator: " ")
}
.filter({ return !$0.isEmpty }) // e.g. no street available
.joined(separator: ", ") // e.g. "MyStreet 1" + ", " + "1030 City"
}
}
}
This should work too.
extension CLPlacemark {
func makeAddressString() -> String {
// Unwrapping the optionals using switch statement
switch (self.subThoroughfare, self.thoroughfare, self.locality, self.administrativeArea, self.postalCode, self.country) {
case let (.Some(subThoroughfare), .Some(thoroughfare), .Some(locality), .Some(administrativeArea), .Some(postalCode), .Some(country)):
return "\(subThoroughfare), \(thoroughfare), \(locality), \(administrativeArea), \(postalCode), \(country)"
default:
return ""
}
}
}
Check out this post for reference:
http://natashatherobot.com/swift-unwrap-multiple-optionals/
EDIT - This will only work if none of the optionals are nil, if one is nil the case will not match. Check the reference link to see how you can detect cases where one might be nil.

Gradle: Force Custom Task to always run (no cache)

I wrote up a custom Gradle task to handle some dependency resolution on the file system where the paths are configurable. I want tasks of this type to always run. It seems though they only run once, I'm guessing because the inputs never seem to change.
I am aware of using configurations { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' } to effectively disable the cache, but I only want it to apply to very specific tasks. Also am aware of --rerun-tasks command line prompt, which is also similar. Neither feel like the best solution, there must be a way to set this up properly in the custom task definition.
Follows is my current implementation. I also had a version prior where the first 3 def String statements were instead #Input annotated String declarations.
class ResolveProjectArchiveDependency extends DefaultTask {
def String archiveFilename = ""
def String relativeArchivePath = ""
def String dependencyScope = ""
#OutputFile
File outputFile
#TaskAction
void resolveArtifact() {
def arcFile = project.file("dependencies/"+dependencyScope+"/"+archiveFilename)
def newArcFile = ""
if(project.hasProperty('environmentSeparated') && project.hasProperty('separatedDependencyRoot')){
println "Properties set denoting the prerelease environment is separated"
newArcFile = project.file(project.ext.separatedDependencyRoot+relativeArchivePath+archiveFilename)
} else {
newArcFile = project.file('../../'+relativeArchivePath+archiveFilename)
}
if(!newArcFile.isFile()){
println "Warn: Could not find the latest copy of " + archiveFilename + ".."
if(!arcFile.isFile()) {
println "Error: No version of " + archiveFilename + " can be found"
throw new StopExecutionException(archiveFilename +" missing")
}
}
if(!arcFile.isFile()) {
println archiveFilename + " jar not in dependencies, pulling from archives"
} else {
println archiveFilename + " jar in dependencies. Checking for staleness"
def oldHash = generateMD5(new File(arcFile.path))
def newHash = generateMD5(new File(newArcFile.path))
if(newHash.equals(oldHash)) {
println "Hashes for the jars match. Not pulling in a copy"
return
}
}
//Copy the archive
project.copy {
println "Copying " + archiveFilename
from newArcFile
into "dependencies/"+dependencyScope
}
}
def generateMD5(final file) {
MessageDigest digest = MessageDigest.getInstance("MD5")
file.withInputStream(){is->
byte[] buffer = new byte[8192]
int read = 0
while( (read = is.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
}
byte[] md5sum = digest.digest()
BigInteger bigInt = new BigInteger(1, md5sum)
return bigInt.toString(16)
}
}
Here's an example of usage of the task:
task handleManagementArchive (type: com.moremagic.ResolveProjectArchiveDependency) {
archiveFilename = 'management.jar'
relativeArchivePath = 'management/dist/'
dependencyScope = 'compile/archive'
outputFile = file('dependencies/'+dependencyScope+'/'+archiveFilename)
}
You can achieve this by setting outputs.upToDateWhen { false } on the task.
This can be performed in your build.gradle file:
handleManagementArchive.outputs.upToDateWhen { false }
It can also be done in the constructor of your custom task.
ResolveProjectArchiveDependency() {
outputs.upToDateWhen { false }
}

Resources