zen0wu / topcoder-greed

greedy editor for topcoder arena
Apache License 2.0
229 stars 45 forks source link

Idea: Custom Files #38

Closed vexorian closed 10 years ago

vexorian commented 11 years ago

Hello, I have an idea that requires more work than a simple commit.

The template engine is very powerful, we can even create unit tests.

I think it would be useful to allow Greed to create other kinds of files, not just unit tests or source, but anything according to configuration.

In configuration:

cpp {
        customFile1 { 
              filePattern = "${Problem.Name}.in"
              template = "InputTemplate.in"
              override = false
        }
}

So now a file called ProblemName.in will be generated in the folder. When generating it the template engine will use file "InputTemplate.in" .

So in this specific case, the template file would be the necessary template to generate an ACM-style input file for the problem. This should be possible with the template engine. Although maybe we need an array length replacement variable. Then the user would call a custom tester template that reads test cases from a file.

There should be support for more than one custom file. For example, input and output.

There are many uses for this. For example generating project files. Or run scripts, and whatever the user could think about.

zen0wu commented 11 years ago

This is an amazing idea! I'm always looking for new features of Greed and this is certainly one. Maybe we can go one step further and think about not only the source code, the test code, the unit test code, the input output template, but also other things? And we can also adjust old configuration to be consistent under this configuration template and it's just cool!

vexorian commented 11 years ago

I guess what we need is to decide how it will work.

I wonder if the config system allows something like this:

greed {
  templates {
    pathPattern = "sol"
    cpp {
        tmplFile = "Template.cpp"
        testTmplFile = "TestTemplate.cpp"
        spec.longIntTypeName = "long"
        files = "in, out, exttester" #declare the names of the files

        in { # we use the names declared in files="" as a section
            tmplFile = "Input.in"
            filename = "${ClassName}.in"
            override = True
        }

        out { # we use the names declared in files="" as a section
            tmplFile = "Onput.out"
            filename = "${ClassName}.in"
            override = True
        }

        exttester {
            tmplFile = "Ext.cpp"
            filename = "${ClassName}Tester.cpp"
            override = False
            # For example, this would allow User to put most of the tester in another file instead
            # of the ${ClassName}.cpp one.
        }
    }
  }
}

The usual code template and tester template would stay outside of the files thing, because unlike custom files, you need two templates to make them work. I wonder if there is a work around though.

zen0wu commented 11 years ago

First about the configuration file, are you asking that if the files variable can be used to declare a list of templates? If so, it can. You can do files = [in, out, exttester], I'm not quite sure about its details, I guess it doesn't matter. The offical doc for the configuration lib is here https://github.com/typesafehub/config.

And about the second question of yours, you're saying that the source code template actually contains the test template, so it must be special treated, right? You're right about that. I think a possible workaround is that, we can bind a template name or a property name to bind to, to each template, and the generated code is bound to the model with the name. For example,

greed {

  templates {
    pathPattern = "sol"
    cpp {
        spec.longIntTypeName = "long"

        # there should be a better name, templates has already been used
        # and I'm not quite sure about how to define an array here, let's just leave it like this
        templates = [
           test {
             # Here we have several options, we can have the template with "bindTo" property
             # not generated and just write the data in the model
             # or we just don't generate file if there's no `fileName` property defined in this template
             bindTo = "TestCode" 
             templateFile = "TestTemplate.cpp"
           }
           source {
              # In this template we can use "${TestCode}" since it's bound by the last template
              templateFile = "Template.cpp"
              fileName = "${ClassName}.cpp"
              override = true
           }
           unitTest {
              foo = bar
           }
           in {
              # ...
           }
        ]
    }
  }
}

This way we can abstract away the particularity of default template and use them as they're normal templates. This approach may encounter the order issues. The user must define the templates in order that the current template can only use the previous bound ones, which may not be a good user experience. Of course this is just a simple idea. What do you think?

zen0wu commented 11 years ago

@vexorian Here is a conf file which may satisfy our idea. https://github.com/shivawu/topcoder-greed/blob/tmpl-seq/src/test/resources/test.conf However, it has a drawback that, we cannot split files, the output file can only be one file. This may limit the original idea where you may want to split samples into different files. What do you think?

vexorian commented 11 years ago

Do you mean that we cannot make a different output file for each test case? That sounds difficult to do, but I think that the easiest approach rather than complicating the configuration file, would be for the user to write a script to split the output file if he really needs the files split.

Questions:

Like if I did :

templates {
     makefile {
             override = True
             outputFileName = "${Problem.Name}/Makefile"
     }
     lang.cpp.templateSeq = [ test, source, testcases, problem, makefile ]
     lang.cpp.templates = ${greed.templates} {
              makefile.templatefile = "Makefile.template"
     }
}

?

zen0wu commented 11 years ago

Yes, that's what I meant. It would be nice to split the sample to different files so that the tester can easily go through them by the file structure, otherwise we may need to define a syntax for the samples (maybe XML), and it may be complicated and not user-friendly due to its complexity. I agree that it's a good idea that user can do some self work. Here we cannot do this in the configuration file elegantly because the configuration file is not as powerful as the template engine, and it would be messy to write all these logic in the configuration. What I thought was that, define the sample template to be a template like samples.template, then define some writing-to-file logic in the template, like

  ${foreach}
     ${write to file}
       ...
     ${end}
  ${end}

Unfortunately, the template engine is not powerful enough to handle this, either (maybe, I have not thought this through), So my next step of the plan is to write a new template engine, of course this one is even bigger, we have to do these things one-by-one.

Another idea is to define some post processing hook for the templates, for example:

  templates {
    samples { 
       tmplFile = ...
       postProcessing = greed.InputFileSplitter
    }
 }

This can be a workaround of this with enough generality, in which user can apply predefined behaviour for all the templates. And we still have the flexibility of defining other post-processing hooks for other templates, which means it's not only for the sample template. What do you think of this one?

About the questions, funny thing is that all your questions are related to each other. :-)

vexorian commented 11 years ago

In my opinion the default should stay saving tests inside the code, as executing a single source file is straightforward and requires little tinkering. But it would be nice to allow people to choose otherwise.

My initial idea was just to let greed create ACM-style input that has the number of test cases as the first integer. Then the tester can read multiple cases. But I see the use in allowing the test cases to be separated in files.

I honestly think the template engine is too complex as is. Allowing some pre/post processing might be better. Actually, it would be nice to be able to have triggers. For example, I would like to call a command whenever a file is created. I think the cleanest way to do something like this is by giving Greed err... plugin support. But that's bigger work for later.

zen0wu commented 10 years ago

@vexorian Sorry for late response. I was outside travelling.

https://github.com/shivawu/topcoder-greed/blob/tmpl-seq/src/test/resources/test.conf I update the template with an afterGen hook, by which we can let user to execute custom external commands, and they can write scripts to do whatever they want.

What do you think of this way?

vexorian commented 10 years ago

It seems good.

zen0wu commented 10 years ago

I've done most coding work, including:

Check it out, in the tmpl-seq branch. I hope we can finish this and release a 2.0 in a few days or weeks.

Features still missing:

vexorian commented 10 years ago

Excellent, I am currently busy writing editorial, will make sure to check it out tomorrow.

vexorian commented 10 years ago

I have been testing it.

I tried to make an input file template (That has all tests in the same file and begins with the number of tests. After the changes I added to the new pull request it generates this for SRM594 FoxAndGo3:

6
3
"o.o"
".o."
"o.o"
3
"..."
".o."
"..."
5
"xxxxx"
"xxoxx"
"xo.ox"
"xxoxx"
"xxxxx"
5
".xox."
".o.ox"
"x.o.o"
"ox.ox"
".ox.."
5
"o.o.o"
".ox.."
"oxxxo"
"..x.."
"o.o.o"
3
"..."
"..."
"..."

We probably need a way to render string valuess without quotes. Perhaps a custom renderer?

zen0wu commented 10 years ago

I see what you mean about the string without quotes. Could you please share your templates with me so that we can discuss what's the best way to do this.

The config file will get complicated, for sure, because we have moved the source,test,unittest logic from code to config. But it should not affect the users, they don't need to write the whole config.

About the share.basicTemplate, I don't see that's quite useful, since we will be trading two lines of common code with a deeper level of inheritance semantic and we still need to write the ${greed.shared.basicTemplate} on each templateDef. Seems also a big boilerplate. In fact, the default value can be set in the code so that we don't need to do these initialization, I just thought this way it's more clear what the default value is.

About the last point, do you mean that, when OutputFileExtension is "", the file will not get created? In my opinion, it will create a file named OutputFileName. (note the last dot). But I haven't tested it. Anyway, this is a bug.

vexorian commented 10 years ago

Well then, it is a bug. When OutputFileExtension is not declared, the file is not created and there is no mistake report.

Also, not all files are supposed to have extension. There has to be a way to be able to create a file without a '.' in it. For example, what if user wants to create a "Makefile" file?

vexorian commented 10 years ago

Sorry about that, I didn't notice pasting the template would break the comment because of < characters. Here it is again: The template:

${NumOfExamples}
${<foreach Examples e}
${<foreach e.Input in}
${<if in.Param.Type.Array}
${in.ValueListLength}
${<foreach in.ValueList v }
${v}
${<end}
${<else}
${in.Value}
${<end}
${<end}
${<end}

My plan is to have the output in a different file and the checker would open the two files. Then it would be possible to add test cases like you'd add cases to files when competing in non-topcoder contests. If there was a way to remove quotes when rendering ${v} ...

zen0wu commented 10 years ago

I updated the string util renderer with a unquote command, try it out. But be aware of the empty string, which must be special treated while reading.

vexorian commented 10 years ago

Empty string is indeed a problem. Although they are rare in problems. I was going to rely on reading the whole line instead of just the next string, because white space inside strings would also be complicated to handle. Maybe {"aa...aa", "xxx..."} format is preferable to some in input files, but that would need the custom tester to parse input.

zen0wu commented 10 years ago

Yes, that's usually how it's done. You can start writing a parser, which may be quite complicated and let's see how can we handle all the cases with clean and simple code. BTW, I fix the empty file extension bug.

zen0wu commented 10 years ago

After build.gradle is updated, you should use gradle fatJar to do the package thing.

vexorian commented 10 years ago

fatJar generates a jar that contains the com folder. But the plugin still doesn't instance. I will take a further look.

zen0wu commented 10 years ago

So is it working now?

vexorian commented 10 years ago

The fatjar creates a jar that seems to contain everything, but for some reason the arena hangs when I try to open the plugin. It doesn't happen when I compile using the old build script.

Yesterday, during the match I found an unfortunate bug in tmpl-seq, greed was sending empty source files to TopCoder.

zen0wu commented 10 years ago

That's very strange. You can open the java console when you started arena, and see what's going on there. And what bug? Sorry for your loss. - -

vexorian commented 10 years ago

Sorry for taking this long, I've been busy.

I tested with console, and it turns out that Greed halts when it can't read the version file. Which is not added to the jar, even when building with ./gradlew fatjar

zen0wu commented 10 years ago

I've implemented the afterGen hook, and also the problem statement template, how did it go with the testcase template?

vexorian commented 10 years ago

Not terribly bad: https://dl.dropboxusercontent.com/u/95690732/greed/template.in https://dl.dropboxusercontent.com/u/95690732/greed/template.out

I just got too busy and couldn't finish the tester yet. Well, I do have this that translates input to output: https://dl.dropboxusercontent.com/u/95690732/greed/C%2B%2B-gcc.in.test.tmpl

But I guess a checker is needed.

On Wed, Nov 6, 2013 at 10:01 AM, Shiva Wu notifications@github.com wrote:

I've implemented the afterGen hook, and also the problem statement template, how did it go with the testcase template?

— Reply to this email directly or view it on GitHubhttps://github.com/shivawu/topcoder-greed/issues/38#issuecomment-27875112 .

zen0wu commented 10 years ago

Good job. No problem, I'll pick up where you left.

zen0wu commented 10 years ago

I pushed a testcase template and a c++ parser. I've merged the input and output into one file, and each testcase use a -- as its prefix to identify a testcase is following. Please help me test it and let me know your opinion, including the format of the testcase, the implementation of the template, and so on.

vexorian commented 10 years ago

This is not going to be the default behavior, right?

I think that as a sample it is good to have the input and output in the same file. -- is not bad.

I have been testing on many problems and so far no issues.

zen0wu commented 10 years ago

What I was considering is the usability. If we split into two files, the user will have to edit two files when trying to add new cases, especially in a fierce contest, it will cost more time, and our parser is more complicated to parse two files. Also, if we have the number of testcases in the front of the file, the user has to change that too, so I removed it.

vexorian commented 10 years ago

What I tried is that by default Greed will use the templates that put test cases inside the source code (like before) ? Or will it use these external files?

zen0wu commented 10 years ago

Yes, I'm hoping the default behaviour is to separate the code with the data.

vexorian commented 10 years ago

It will be more complex to setup, it needs the sample file in the work directory when the program is executed.

zen0wu commented 10 years ago

Yes, of course we need to come up with a convention about the file location and stuff. What's your suggestion?

vexorian commented 10 years ago

As far as putting the test cases in a separate file, I don't think it can be much better than the current idea. Just make sure to leave the old templates in the jar and it will be just ok.

zen0wu commented 10 years ago

Yes, the old template will be left there for backward compatibility. Maybe there's someone out there like the old way.

vexorian commented 10 years ago

Me, for example.

Actually, I have all test cases in the source file, but only the test cases and in a very convenient bracket-based format. http://vexorian.blogspot.com/2013/10/c-and-python-topcoder-generic-testers.html

zen0wu commented 10 years ago

Wow! I'm really impressed. Your templates are very cool. I haven't read your blog before (blogspot is not accessible in my area...) If you're willing to, we can add your template to the codebase and release them with 2.0, with adjustment to the new features, if needed.

Also, I'm almost finished with the new features, what do you think of the templates now? If you have no further concerns, we can start with the other templates, copying the C++ one. You can be in charge of the Python one, since I'm not much of a Pythoner.

On Mon, Nov 11, 2013 at 10:23 AM, vexorian notifications@github.com wrote:

Me, for example.

Actually, I have all test cases in the source file, but only the test cases and in a very convenient bracket-based format. http://vexorian.blogspot.com/2013/10/c-and-python-topcoder-generic-testers.html

— Reply to this email directly or view it on GitHubhttps://github.com/shivawu/topcoder-greed/issues/38#issuecomment-28168233 .

Chenyang WU Shanghai Jiao Tong University Cell: +86-15801929580 Address: No. 800 Dong Chuan Rd, Minhang District, Shanghai

vexorian commented 10 years ago

My templates are a bit specific and need an external tester library file. So I never thought of adding them to Greed's jar, but if you want them it is cool. Actually, now with the custom templates, the tester library file can be a template too that is called only the first time you open a problem.

I must admit I am not very good with python I/O, but I can try.

vexorian commented 10 years ago

A good thing about a sample file is that if user adds some sample cases, the sample cases can stay even if (s)he switches language.

zen0wu commented 10 years ago

Yes, that's the default behaviour now, since the override property of these templates are false. However, if the user click 'Regenerate code', it will be overwritten since it has a force regenerate behaviour. But old files will be backed up.

On Mon, Nov 11, 2013 at 11:03 AM, vexorian notifications@github.com wrote:

A good thing about a sample file is that if user adds some sample cases, the sample cases can stay even if (s)he switches language.

— Reply to this email directly or view it on GitHubhttps://github.com/shivawu/topcoder-greed/issues/38#issuecomment-28170197 .

Chenyang WU Shanghai Jiao Tong University Cell: +86-15801929580 Address: No. 800 Dong Chuan Rd, Minhang District, Shanghai

zen0wu commented 10 years ago

I've finished all the external test template, including python. It's easier than I thought. Test it out and let me know your opinions.

zen0wu commented 10 years ago

2.0-beta is released, guys! @vexorian @wookayin @starforever @ashashwat @tomtung @jbransen Test it out when you get time, tons of new features, you'll be impressed.

wookayin commented 10 years ago

Great job, @shivawu and @vexorian. I was keeping my eyes on your impressive workings, and it's time to check it out for further enhancements. Cheers!

ashashwat commented 10 years ago

2.0-beta is not working for my case, so far.

This was the error I got.

Greetings from Greed Problem : MarblesInABag Score : 1000 Set problem error, message says "null"

After I reloaded my config, it says -

Reloading your configuration from "/Volumes/CoreHD/Repository/TC//greed.conf"

There is no greed.conf anymore in my root dir. After asking to regenerate the source code, it gives me the same error -

Greetings from Greed Problem : MarblesInABag Score : 1000 Set problem error, message says "null"

After I copied default.conf from source as greed.conf in my root directory, I got these errors.

Greetings from Greed Problem : MarblesInABag Score : 1000 Generating template [filetest] Template file "builtin filetest/cpp.tmpl" not found Generating template [source] Template file "builtin source/cpp.tmpl" not found Generating template [testcase] Template file "builtin testcase/testcases.tmpl" not found Generating template [problem-desc] Template file "builtin problem/desc.html.tmpl" not found All set, good luck!

On Tue, Nov 12, 2013 at 8:19 PM, Jongwook Choi notifications@github.comwrote:

Great job, @shivawu https://github.com/shivawu and @vexorianhttps://github.com/vexorian. I was keeping my eyes on your impressive workings, and then I will check it out for further enhancements. Cheers!

— Reply to this email directly or view it on GitHubhttps://github.com/shivawu/topcoder-greed/issues/38#issuecomment-28298741 .

zen0wu commented 10 years ago

I'm not sure what's the error is. It works at my side. I updated the README with the way to see detailed logging. Please following the instructions and raise an issue with the detailed exceptions with it. Thanks.

ashashwat commented 10 years ago

I have yet to sort out the problem completely but so far I can certainly say this, it is now packed with one hell of feature-set.

Thanks a lot for the awesome work.

zen0wu commented 10 years ago

You're welcome! Nice usage about the post processing hooks, I've never thought it that way. If you have any other feature requests or ideas, do not hesitate to share it!