-
Notifications
You must be signed in to change notification settings - Fork 114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Options and Out thread-safe. #258
Conversation
- Split Main in 2 classes - Main the cli client - LexGenerator that generates java code - Replace manual command line parsing by commons-cli - Replace Options by GeneratorOptions, an immutable object - Remove all statics from Out - Deleted dead DEBUG statements - Throws exceptions when possible (which removes a few dependencies on this Out logger) - Also simplify error formatting with varaargs - Update maven-jflex-plugin - To reduce scope on this XL change: - Move anttask in a separate directory. Build broken, even though mostly update. TODO: Make it compile as a POM. - Move GUI in a separate directory. Build broken. TODO: Make it compile as a POM. - testsuite-maven-plugin build broken. Renamed Main to Tester to avoid confusion with jflex.Main.
This is only for early code review. I know that all POM modules don't compile and that tests probably don't pass. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking on that project, it looks like it's quite sizeable (makes sense, it threads through everything).
I think the approach is mostly good, main issues I can see are:
- avoiding external dependencies unless there really is a substantial benefit
DEBUG
should remain (it's not pretty, but it's not as dead as it looks, I'm still using it)- this PR is mixed in with the CLI PR (see comments there). Of course they depend on each other, but I'd still try to separate the new Options handling from the CLI parsing.
@@ -120,11 +120,6 @@ public int getNumClasses() { | |||
public void makeClass(IntCharSet set, boolean caseless) { | |||
if (caseless) set = set.getCaseless(scanner.getUnicodeProperties()); | |||
|
|||
if (DEBUG) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't remove DEBUG
, it's not dead or unused, it's just a static DEBUG option that I use when trying to get a trace of what's really going on in the algorithmic part. It's slightly horrible println
debugging, but IDE debugging takes way too long to set up for this.
It's Ok for DEBUG
to remain static, since it's only for developing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. Could the debugging be done on System.out
rather than Out
?
I was a bit unsure of the responsibiilty of Out. But because it's seems to have a state of the output (a count of warnings), it's not thread safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good point. I don't think it would be a problem to do the debug output on System.out
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
package jflex; | ||
|
||
import com.google.auto.value.AutoValue; | ||
import com.google.common.base.Optional; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not keen on introducing additional dependencies. The thing we're trying to achieve here seems relatively simple and pretty much the same as in the non-static setting. Do we gain much by using a builder pattern here instead of just a plain object with constructor for defaults?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AutoValue is only an annotation with compile-time dependency. In the end, this automated approach will only bring one (generated) class in the jar. I think its brings enough value (cleaner definition compared to getters and setters ; immmutable object by nature ; free toString and free equals) that's I want to convince you it's worth it.
On the other hand, guava is a huge beast. I didn't think about the cost, because I'm used to use it. It's probably not woth it just for Optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't actually find it cleaner ;-) It probably is cleaner when you are used to the framework, because then it's a standardised pattern, but if you're not used to it, it's another largish library to look at.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the dependency point, separately, because I feel somewhat strongly about that:
Introducing additional dependencies can have a rather large cost, it depends on how large the project is and what the dependencies are doing. Mostly, these are:
- you need to understand the dependency/library you are using
- you need to deal with the additional complexity of managing them. mvn does that well, but that's only one of many build methods we are trying to support.
- users (developers) need to track and install them as well
- the dependencies will develop and you have to maintain compatibility
We've so far managed to have the cup runtime as the only dependency for JFlex, which is very nice.
Of course there are many advantages as well, esp if you are using those dependencies a lot or know them well anyway. It's a trade-off. The simple kind of CLI parsing and options would be worth a dependency if we had a set of projects that all do the same thing. For just JFlex, that code is so simple that I find it much easier to avoid the build time messiness and the need to keep track of what an external library is doing.
@@ -23,8 +23,6 @@ | |||
*/ | |||
public final class IntCharSet { | |||
|
|||
private static final boolean DEBUG = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are not dead, should stay in and are fine to remain static.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -44,15 +44,6 @@ public Macros() { | |||
* @return <code>true</code>, iff the macro name has not been stored before. | |||
*/ | |||
public boolean insert(String name, RegExp definition) { | |||
|
|||
if (Options.DEBUG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should remain. It's Ok to move it out of the Options class, but there should be a global static DEBUG flag somewhere that generates a detailed trace when needed (I was actually about to use this for looking at the issue about macros in char classes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
jflex/src/main/java/jflex/Main.java
Outdated
import jflex.unicode.UnicodeProperties; | ||
import org.apache.commons.cli.CommandLine; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems mixed with the other PR on changing the CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I started here when I refactored the (jflex) Options, and then realized that the commons-cli change was unrelated and could be moved in a different channge (now PR #259)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
jflex/src/main/java/jflex/NFA.java
Outdated
if (Options.DEBUG) | ||
Out.debug( | ||
"Adding nfa for regexp " + regExpNum + " :" + Out.NL + regExps.getRegExp(regExpNum)); | ||
if (GeneratorOptions.DEBUG) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good. I didn't first see that GeneratorOptions.DEBUG
is still around. The other parts that used Options.DEBUG
should use this one, and the other smaller scope static DEBUG
s can just stay in the classes they are (they are separate either because they slow things down a lot or produce huge amounts of output unless you are looking at specific test cases).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one was easy to keep because the NFA already depends on the Out instance. I'm afraid the others were not, and I didn't want to bring a dep on Out just for a DEBUG statement.
# Conflicts: # jflex-maven-plugin/src/main/java/de/jflex/plugin/maven/JFlexMojo.java # jflex/pom.xml # testsuite/jflex-testsuite-maven-plugin/src/main/java/jflextest/Exec.java # testsuite/jflex-testsuite-maven-plugin/src/main/java/jflextest/JFlexTestsuiteMojo.java # testsuite/jflex-testsuite-maven-plugin/src/main/java/jflextest/TestCase.java
Sorry for the noise - Im fine with moving this to 1.8.0, just clicked the wrong button! |
TODO: Test the GUI. I guess I broke it. |
Not compiled / not tested
The Lucene/Solr build uses JFlex's Ant task to generate multiple scanners, and options from previous invocations in the same Ant session bleed into further invocations. E.g. if I specify a non-default skeleton for one scanner, it will be used for all further invocations that don't specify a skeleton (expecting to use the default skeleton). I haven't tried the work done here - thanks @regisd for your efforts! - but I just wanted to point out that thread safety is not the only issue here: serialized same-session invocations are also problematic in all released JFlex versions. |
This is old and there are many merge conflicts. I'm giving up for now.
This is not really the behaviour I would expect, but it could be supported by the ant task itself, i.e. the ant task keeps a reference to OptionsBuilder, and updates between invocations. |
Main
in 2 classesMain
the cli clientLexGenerator
that generates java codeMain.generate(lexFile);
becomesnew LexGenerator(generatorOptions).generate(lexFile)
Options
an immutable objectSystem.out
forDEBUG
statementsThe goal is to make the generator thread-safe. #214