@@ -10,7 +10,7 @@ use std::io::{BufRead, BufReader, Read};
1010lazy_static ! {
1111 static ref META_SYNTAXES_C : [ MetaSyntax ; 2 ] = [
1212 MetaSyntax :: new( "//" , None ) ,
13- MetaSyntax :: new( "/\\ *" , Some ( " \ \ */") )
13+ MetaSyntax :: new( r "/\*", Some ( r" \*/") )
1414 ] ;
1515 static ref META_SYNTAXES_HTML : [ MetaSyntax ; 1 ] = [ MetaSyntax :: new( "<!--" , Some ( "-->" ) ) ] ;
1616 static ref META_SYNTAXES_PY : [ MetaSyntax ; 1 ] = [ MetaSyntax :: new( "#" , None ) ] ;
@@ -47,29 +47,30 @@ struct MetaSyntax {
4747impl MetaSyntax {
4848 fn new ( comment_start : & ' static str , comment_end : Option < & ' static str > ) -> Self {
4949 // comment patterns
50- let comment_start_pattern = format ! ( "^(\\ s*){}\ \ s*" , comment_start) ;
50+ let comment_start_pattern = format ! ( r "^(\s*){}\s*", comment_start) ;
5151 let comment_end_pattern = match comment_end {
52- Some ( s) => format ! ( "(.*){}\ \ s*" , s) ,
52+ Some ( s) => format ! ( r "(.*){}\s*", s) ,
5353 None => "(.*)" . to_string ( ) ,
5454 } ;
5555
5656 // annotation patterns
5757 let solution_file = Regex :: new ( & format ! (
58- "{}SOLUTION\ \ s+FILE{}" ,
58+ r "{}SOLUTION\s+FILE{}",
5959 comment_start_pattern, comment_end_pattern
6060 ) )
6161 . unwrap ( ) ;
6262 let solution_begin = Regex :: new ( & format ! (
63- "{}BEGIN\ \ s+SOLUTION{}" ,
63+ r "{}BEGIN\s+SOLUTION{}",
6464 comment_start_pattern, comment_end_pattern
6565 ) )
6666 . unwrap ( ) ;
6767 let solution_end = Regex :: new ( & format ! (
68- "{}END\ \ s+SOLUTION{}" ,
68+ r "{}END\s+SOLUTION{}",
6969 comment_start_pattern, comment_end_pattern
7070 ) )
7171 . unwrap ( ) ;
72- let stub_begin = Regex :: new ( & format ! ( "{}STUB:\\ s*" , comment_start_pattern) ) . unwrap ( ) ;
72+ let stub_begin =
73+ Regex :: new ( & format ! ( r"{}STUB:[\s&&[^\n]]*" , comment_start_pattern) ) . unwrap ( ) ;
7374 let stub_end = Regex :: new ( & comment_end_pattern) . unwrap ( ) ;
7475
7576 Self {
@@ -128,14 +129,20 @@ impl<B: BufRead> Iterator for MetaSyntaxParser<B> {
128129 // check for stub
129130 if self . in_stub . is_none ( ) && meta_syntax. stub_begin . is_match ( & s) {
130131 log:: debug!( "stub start: '{}'" , s) ;
131- // save the syntax that started the current stub
132- self . in_stub = Some ( meta_syntax) ;
133132 // remove stub start
134133 s = meta_syntax
135134 . stub_begin
136135 . replace ( & s, |caps : & Captures | caps[ 1 ] . to_string ( ) )
137136 . to_string ( ) ;
138- log:: debug!( "parsed: '{}'" , s) ;
137+
138+ if s. trim ( ) . is_empty ( ) && meta_syntax. stub_end . is_match ( & s) {
139+ // empty oneliner stubs are replaced by a newline
140+ return Some ( Ok ( MetaString :: Stub ( "\n " . to_string ( ) ) ) ) ;
141+ }
142+
143+ // save the syntax that started the current stub
144+ self . in_stub = Some ( meta_syntax) ;
145+
139146 if s. trim ( ) . is_empty ( ) {
140147 // only metadata, skip
141148 return self . next ( ) ;
@@ -154,7 +161,6 @@ impl<B: BufRead> Iterator for MetaSyntaxParser<B> {
154161 . stub_end
155162 . replace ( & s, |caps : & Captures | caps[ 1 ] . to_string ( ) )
156163 . to_string ( ) ;
157- log:: debug!( "parsed: '{}'" , s) ;
158164 if s. trim ( ) . is_empty ( ) {
159165 // only metadata, skip
160166 return self . next ( ) ;
@@ -303,4 +309,57 @@ public class JavaTestCase {
303309 let actual = filter. map ( |l| l. unwrap ( ) ) . collect :: < Vec < MetaString > > ( ) ;
304310 assert_eq ! ( expected, actual) ;
305311 }
312+
313+ #[ test]
314+ fn stube ( ) {
315+ init ( ) ;
316+
317+ const PYTHON_FILE_STUB : & str = r#"
318+ # BEGIN SOLUTION
319+ print("a")
320+ # END SOLUTION
321+ # KOMMENTTI
322+ #STUB:class Kauppalista:
323+ #STUB:def __init__(self):
324+ #STUB:self.tuotteet = []
325+ #STUB:
326+ #STUB:def tuotteita(self):
327+ #STUB:return len(self.tuotteet)
328+ #STUB:
329+ #STUB:def lisaa(self, tuote: str, maara: int):
330+ #STUB:self.tuotteet.append((tuote, maara))
331+ #STUB:
332+ #STUB:def tuote(self, n: int):
333+ #STUB:return self.tuotteet[n - 1][0]
334+ #STUB:
335+ #STUB:def maara(self, n:int):
336+ #STUB:return self.uotteet[n - 1][1]
337+ "# ;
338+
339+ let expected: Vec < MetaString > = vec ! [
340+ MetaString :: str ( "\n " ) ,
341+ MetaString :: solution( "print(\" a\" )\n " ) ,
342+ MetaString :: str ( "# KOMMENTTI\n " ) ,
343+ MetaString :: stub( "class Kauppalista:\n " ) ,
344+ MetaString :: stub( " def __init__(self):\n " ) ,
345+ MetaString :: stub( " self.tuotteet = []\n " ) ,
346+ MetaString :: stub( "\n " ) ,
347+ MetaString :: stub( " def tuotteita(self):\n " ) ,
348+ MetaString :: stub( " return len(self.tuotteet)\n " ) ,
349+ MetaString :: stub( "\n " ) ,
350+ MetaString :: stub( " def lisaa(self, tuote: str, maara: int):\n " ) ,
351+ MetaString :: stub( " self.tuotteet.append((tuote, maara))\n " ) ,
352+ MetaString :: stub( "\n " ) ,
353+ MetaString :: stub( " def tuote(self, n: int):\n " ) ,
354+ MetaString :: stub( " return self.tuotteet[n - 1][0]\n " ) ,
355+ MetaString :: stub( "\n " ) ,
356+ MetaString :: stub( " def maara(self, n:int):\n " ) ,
357+ MetaString :: stub( " return self.uotteet[n - 1][1]\n " ) ,
358+ ] ;
359+
360+ let source = PYTHON_FILE_STUB . as_bytes ( ) ;
361+ let filter = MetaSyntaxParser :: new ( source, "py" ) ;
362+ let actual = filter. map ( |l| l. unwrap ( ) ) . collect :: < Vec < MetaString > > ( ) ;
363+ assert_eq ! ( expected, actual) ;
364+ }
306365}
0 commit comments