antlr4 visitor does not work - groovy

I am trying to process .pas file. I generated lexers, parsers, visitors, listeners for grammar
Here is my custom visitor implementation
class GroovyPascalVisitor extends PascalBaseVisitor<ScriptSkeleton> {
private static final String PASCAL_SCRIPT_NAME = "PascalScript"
#Lazy ScriptSkeleton scriptSkeleton = new ScriptSkeleton()
#Override
public ScriptSkeleton visitProgramHeading(
PascalParser.ProgramHeadingContext ctx) {
log.info "Visiting program heading"
def scriptName = ctx.identifier().getText()?.trim()
if (!scriptName) {
scriptName = PASCAL_SCRIPT_NAME +
"${new Random().nextInt(1000)}"
}
scriptSkeleton.scriptName = scriptName
return scriptSkeleton
}
}
Here is the code in my script
def file = new ANTLRFileStream(pas)
def lexer = new PascalLexer(file)
def parser = new PascalParser(new CommonTokenStream(lexer))
tree = parser.program()
stringTree = tree.toStringTree(parser)
visitor = new GroovyPascalVisitor()
skeleton = visitor.visit(tree)
The .pas file content looks like this
program HelloWorld;
begin
writeln('Hello, World!');
end.
But when I run script - it does not println message from log and object scriptSkeleton is null, meaning that it does not invoke visitProgramHeading at all.
What it is the problem?

Related

Error: md5sum: stat '>': No such file or directory

I am trying to write a program that runs the Linux commands using Scala.
I have written a snippet of code to run the functionalities of md5sum command.
Code snippet
object Test extends App {
import sys.process._
case class md5sum_builder private(i: Seq[String]) {
println(i)
protected def this() = this(Seq(""))
def optionCheck() = new md5sum_builder(i :+ "-c")
def files(file: String) = new md5sum_builder(i :+ file)
def hashFile(hashfile: String) = new md5sum_builder(i :+ hashfile)
def assignment(operator: String) = new md5sum_builder(i :+ operator)
def build() = println(("md5sum" + i.mkString(" ")).!!)
}
object md5sum_builder {
def apply() = new md5sum_builder
}
md5sum_builder().files("text.txt").files("text1.txt").assignment(">").hashFile("hashes.md5").build()
}
When I try to run the command md5sum text.txt text1.txt > hashes.md5 using this program, it throws the error:
Error: md5sum: stat '>': No such file or directory
I don't know why. Any way to make it work?
Your interface doesn't appear to be well thought out. Notice that files(), hashFile(), and assignment() all do the same thing. So someone could come along and do something like this ...
md5sum_builder().assignment("text0.txt")
.hashFile("text1.txt")
.files(">") // <--shell redirection won't work
.assignment("hashes.md5")
.build()
... and get the same (non-functional) result as your posted example.
Here's a modification that corrects for that as well as allowing redirected output.
case class md5sum_builder private(i :Seq[String], outfile :String = "/dev/null") {
protected def this() = this(Seq.empty[String])
def optionCheck(file :String) = this.copy(i = i ++ Seq("-c", file))
def file(file: String) = this.copy(i = i :+ file)
def hashFile(file: String) = this.copy(outfile = file)
def build() = println(("md5sum" +: i).#|(Seq("tee", outfile)).!!)
}
Now the methods can be in almost any order and still get the expected results.
md5sum_builder().file("text0.txt")
.hashFile("hashes.md5")
.file("text1.txt")
.build()

load external jar in groovy script in SoapUI

I need to call a method inside Jar from groovy script inside SoapUI project.
Due to the lack of administrative access I can't place that jar in "../bin/ext" folder in SaopUI intall directory.
So the only option left is load the jar in runtime and call the method. Very simple approach.
I tried the below approach.
this.class.classLoader.rootLoader.addURL(new URL("file:///H://Foo-2//Foo.jar"));
def cls = Class.forName("test").newInstance();
cls.add()
This is not working as rootLoader is null.
second approach .
def classLoader = ClassLoader.systemClassLoader
def newClassLoader = new URLClassLoader([new File("file:///H://Foo-2//Foo.jar")
.toString().toURL()] as URL[], classLoader)
def cls = Class.forName("test").newInstance();
this is not working too , it's giving me ClassNotFoundException.
I spent a day in this. even change the class name to lower case after seeing this thread.
Edit 1
I tried this too. and change my code like this.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def classpathHacker = new com.eviware.soapui.support.ClasspathHacker ()
log.info "utils=" + groovyUtils
mystring = "file://H://Baz.jar"
com.eviware.soapui.support.ClasspathHacker.addURL( new URL(mystring) )
def cls = new bar() // how to call the static method add of `bar` class ?
log.info cls
My Jar code is too simple. Here it is
public class bar {
public static void main(String[] args) {
add();
}
public static void add(){
String path = "H:" + File.separator + "Groovy" + File.separator + "hi.txt";
File f = new File(path);
f.getParentFile().mkdirs();
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
What all the other option I have? What i am doing wrong?
Solved. Here is the final Groovy script.
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def classpathHacker = new com.eviware.soapui.support.ClasspathHacker ()
path = groovyUtils.getProjectPath()
myfile = new java.io.File(path + "/Baz.jar")
mystring = "file://" + path + "/Baz.jar"
log.info "myfile=" + myfile
classpathHacker.addFile( myfile )
com.eviware.soapui.support.ClasspathHacker.addFile( myfile )
com.eviware.soapui.support.ClasspathHacker.addURL( new URL(mystring) )
//import Baz
def instance = this.class.classLoader.loadClass( 'bar', true, false )?.newInstance()
instance.add();
Do you know about com.eviware.soapui.support.ClasspathHacker?
Maybe that is away to go about it, if you really cannot put it to the /ext folder.
Reference:
https://community.smartbear.com/t5/SoapUI-Open-Source/Soapui-is-not-loading-external-jar-file-location-added-to/td-p/7619
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
def classpathHacker = new com.eviware.soapui.support.ClasspathHacker ()
log.info "utils=" + groovyUtils
path = groovyUtils.getProjectPath()
myfile = new java.io.File(path + "/ojdbc14.jar")
mystring = "file://" + path + "/ojdbc14.jar"
log.info "myfile=" + myfile
classpathHacker.addFile( myfile )
com.eviware.soapui.support.ClasspathHacker.addFile( myfile )
com.eviware.soapui.support.ClasspathHacker.addURL( new URL(mystring) )
import groovy.sql.*
def sql = groovy.sql.Sql.newInstance( db, userid, password, 'oracle.jdbc.driver.OracleDriver' )

Groovy map constructor keys to different variable names

I have JSON looking like:
{
"days": [
{
"mintemp": "21.8"
}
]
}
With Groovy, I parse it like this:
class WeatherRow {
String mintemp
}
def file = new File("data.json")
def slurper = new JsonSlurper().parse(file)
def days = slurper.days
def firstRow = days[0] as WeatherRow
println firstRow.mintemp
But actually, I would like to name my instance variable something like minTemp (or even something completely random, like numberOfPonies). Is there a way in Groovy to map a member of a map passed to a constructor to something else?
To clarify, I was looking for something along the lines of #XmlElement(name="mintemp"), but could not easily find it:
class WeatherRow {
#Element(name="mintemp")
String minTemp
}
Create a constructor that takes a map.
Runnable example:
import groovy.json.JsonSlurper
def testJsonStr = '''
{"days": [
{ "mintemp": "21.8" }
]}'''
class WeatherRow {
String minTemp
WeatherRow(map) {
println "Got called with constructor that takes a map: $map"
minTemp = map.mintemp
}
}
def slurper = new JsonSlurper().parseText(testJsonStr)
def days = slurper.days
def firstRow = days[0] as WeatherRow
println firstRow.minTemp
Result:
Got called with constructor that takes a map: [mintemp:21.8]
21.8
(of course you'd remove the println line, it's just there for the demo)
You can achieve this using annotation and simple custom annotation processor like this:
1. Create a Custom Annotation Class
#Retention(RetentionPolicy.RUNTIME)
#interface JsonDeserializer {
String[] names() default []
}
2. Annotate your instance fields with the custom annotation
class WeatherRow{
#JsonDeserializer(names = ["mintemp"])
String mintemp;
#JsonDeserializer(names = ["mintemp"])
String minTemp;
#JsonDeserializer(names = ["mintemp"])
String numberOfPonies;
}
3. Add custom json deserializer method using annotation processing:
static WeatherRow fromJson(def jsonObject){
WeatherRow weatherRow = new WeatherRow();
try{
weatherRow = new WeatherRow(jsonObject);
}catch(MissingPropertyException ex){
//swallow missing property exception.
}
WeatherRow.class.getDeclaredFields().each{
def jsonDeserializer = it.getDeclaredAnnotations()?.find{it.annotationType() == JsonDeserializer}
def fieldNames = [];
fieldNames << it.name;
if(jsonDeserializer){
fieldNames.addAll(jsonDeserializer.names());
fieldNames.each{i ->
if(jsonObject."$i")//TODO: if field type is not String type custom parsing here.
weatherRow."${it.name}" = jsonObject."$i";
}
}
};
return weatherRow;
}
Example:
def testJsonStr = '''
{
"days": [
{
"mintemp": "21.8"
}
]
}'''
def parsedWeatherRows = new JsonSlurper().parseText(testJsonStr);
assert WeatherRow.fromJson(parsedWeatherRows.days[0]).mintemp == "21.8"
assert WeatherRow.fromJson(parsedWeatherRows.days[0]).minTemp == "21.8"
assert WeatherRow.fromJson(parsedWeatherRows.days[0]).numberOfPonies == "21.8"
Check the full working code at groovyConsole.

groovy print environments from groovy.config

how do I print available environments from a config file? What is the form of the ojbect ConfigSlurper creates?
I tried
def config2 = new ConfigSlurper().parse(new File('obieeadmincfg.groovy').toURL())
config2.config.environments.each { println ${it} }
and
println prettyPrint(toJson(config2))
and
for ( i in 0 ..config2.config.environments.size()-1)
println config2.config.environments[i]
groovy.config
//Config3.groovy
obieadmin {
//default values
serverurl = "http://default.mycompany.com"
}
environments {
pldev01 {
obieeadmin {
serverurl = 'devgdwobi03.x.com'
}
}
plsbx02 {
obieeadmin {
serverurl = 'devgdwobi03.x.com'
}
}
}
I'm afraid you can't do this out-of box.
But using a bit of Groovy Metaprogramming it's achievable.
Groovy config slurper parses proper Groovy file, and you can do the same with GroovyShell. You can catch call to environment method providing closure in binding. In that closure you have to collect all top-level method calls(with same methodMissing).
Providing base script with property and method missing handlers, you can suppress runtime errors, and execute script without much care to other properties.
Not the nicest path, but it works.
package test
import org.codehaus.groovy.control.CompilerConfiguration
class A extends Script {
def propertyMissing(String name) { null }
def propertyMissing(String name, def arg) {}
def methodMissing(String name, def args) {}
#Override Object run() { null }
}
class NameCollector {
def envs = []
def methodMissing(String name, def args) { envs << name }
}
// configure interceptors.
def configuration = new CompilerConfiguration()
configuration.scriptBaseClass = 'test.A'
def nc = new NameCollector()
def environments = { Closure it ->
it.delegate = nc;
it.resolveStrategy = Closure.DELEGATE_ONLY
it()
}
// execute config script
new GroovyShell([environments: environments] as Binding, configuration).evaluate(new File("config.groovy"))
nc.envs // Return, print them.
Not sure if this is going to work forever but currently you can do it by overriding the setting for the 'environments' conditional block, like this:
def config = """environments {
dev {
foo = "bar"
}
prod {
foo = "baz"
}
}"""
def configSlurper = new ConfigSlurper()
configSlurper.registerConditionalBlock('environments', null)
assert configSlurper.parse(config).environments.keySet() == ['dev', 'prod'].toSet()

Groovy DSL: How can I let two delegating classes handle different parts of a DSLScript?

Let's say I have a DSL like this
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "I'm doing dsl stuff"}
One would have a delegating class implementing the methods 'setup' and 'doStuff' usually. Beside, one could write common Groovy code to be executed (println...).
What I am searching for, is a way to execute this in two steps. In the first step only the setup method should be processed (neither println). The second step handles the other parts.
At the moment, I have two delegating classes. One implements 'setup' the other one implements 'doStuff'. But both execute the println statement, of course.
You can create a single class to intercept the method calls from the script and let it coordinate the following method invoke. I did it through reflection, but you can go declarative if you want. These are the model and script classes:
class FirstDelegate {
def setup(closure) { "firstDelegate.setup" }
}
class SecondDelegate {
def doStuff(closure) { "secondDelegate.doStuff" }
}
class MethodInterceptor {
def invokedMethods = []
def methodMissing(String method, args) {
invokedMethods << [method: method, args: args]
}
def delegate() {
def lookupCalls = { instance ->
def invokes = instance.metaClass.methods.findResults { method ->
invokedMethods.findResult { invocation ->
invocation.method == method.name ?
[method: method, invocation: invocation] : null
}
}
invokes.collect { invoked ->
invoked.method.invoke(instance, invoked.invocation.args)
}
}
return lookupCalls(new FirstDelegate()) + lookupCalls(new SecondDelegate())
}
}
Here be scripts and assertions:
import org.codehaus.groovy.control.CompilerConfiguration
def dsl = '''
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "Ima doing dsl stuff"}
'''
def compiler = new CompilerConfiguration()
compiler.scriptBaseClass = DelegatingScript.class.name
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
script = shell.parse dsl
interceptor = new MethodInterceptor()
script.setDelegate interceptor
script.run()
assert interceptor.invokedMethods*.method == [ 'setup', 'doStuff' ]
assert interceptor.delegate() ==
['firstDelegate.setup', 'secondDelegate.doStuff']
Notice I didn't bothered intercepting println call, which is a DefaultGroovyMethods thus, a little more cumbersome to handle.
Also having the class MethodInterceptor implementing the method delegate() is not a good idea, since this allows the user-defined script to call it.
I found a way to split up execution of the DSL script. I used a CompilationCustomizer to remove every statement from AST except the doFirst{}. So the first run will only execute doFirst. The second run does everything else. Here's some code:
class DoFirstProcessor {
def doFirst(Closure c) {
c()
}
}
class TheRestProcessor {
def doStuff(Closure c) {
c()
}
def methodMissing(String name, args) {
//nothing to do
}
}
def dsl = "
println 'this is text that will not be printed out in first line!'
doFirst { println 'First things first: e.g. setting up environment' }
doStuff { println 'doing some stuff now' }
println 'That is it!'
"
class HighlanderCustomizer extends CompilationCustomizer {
def methodName
HighlanderCustomizer(def methodName) {
super(CompilePhase.SEMANTIC_ANALYSIS)
this.methodName = methodName
}
#Override
void call(SourceUnit sourceUnit, GeneratorContext generatorContext, ClassNode classNode) throws CompilationFailedException {
def methods = classNode.getMethods()
methods.each { MethodNode m ->
m.code.each { Statement st ->
if (!(st instanceof BlockStatement)) {
return
}
def removeStmts = []
st.statements.each { Statement bst ->
if (bst instanceof ExpressionStatement) {
def ex = bst.expression
if (ex instanceof MethodCallExpression) {
if (!ex.methodAsString.equals(methodName)) {
removeStmts << bst
}
} else {
removeStmts << bst
}
} else {
removeStmts << bst
}
}
st.statements.removeAll(removeStmts)
}
}
}
}
def cc = new CompilerConfiguration()
cc.addCompilationCustomizers new HighlanderCustomizer("doFirst")
cc.scriptBaseClass = DelegatingScript.class.name
def doFirstShell = new GroovyShell(new Binding(), cc)
def doFirstScript = doFirstShell.parse dsl
doFirstScript.setDelegate new DoFirstProcessor()
doFirstScript.run()
cc.compilationCustomizers.clear()
def shell = new GroovyShell(new Binding(), cc)
def script = shell.parse dsl
script.setDelegate new TheRestProcessor()
script.run()
I did another variation of this where I execute the DSL in one step. See my blog post about it: http://hackserei.metacode.de/?p=247

Resources