From 538977c4fd48123cf89378d991aee0cc42892803 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Wed, 17 Apr 2019 16:07:08 +0200 Subject: [PATCH 01/10] WIP : debugging scanner --- .gitignore | 2 ++ qtc/main.go | 67 +++++++++++++++++++++++++++---------- qtc/parser.go | 8 ++--- qtc/scanner.go | 90 ++++++++++++++++++++++++++++++-------------------- 4 files changed, 110 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 6e92f57..415675a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ tags +**/*.qtpl.go +*.qtpl.go \ No newline at end of file diff --git a/qtc/main.go b/qtc/main.go index 7216a0a..8ab82d0 100644 --- a/qtc/main.go +++ b/qtc/main.go @@ -1,7 +1,9 @@ package main import ( + "bytes" "flag" + "fmt" "go/format" "io/ioutil" "log" @@ -27,27 +29,58 @@ var logger = log.New(os.Stderr, "qtc: ", log.LstdFlags) var filesCompiled int +type tt struct { + ID int + Value string +} + +func testIt() { + str := "header {%stripspace %} toto et tata {%endstripspace %} footer" + r := bytes.NewBufferString(str) + s := NewScanWithTagConf(r, "memory", "{%", "%}") + var tokens []tt + i := 0 + for s.Next() { + tok := s.Token() + id := tok.ID + val := string(tok.Value) + fmt.Printf("%d - %s\n", id, val) + tokens = append(tokens, tt{ + ID: s.Token().ID, + Value: string(s.Token().Value), + }) + fmt.Printf("token[%d] : %d - %s\n", i, s.Token().ID, string(s.Token().Value)) + i++ + } + count := len(tokens) + + fmt.Printf("found %d tokens when scanning %q. \n", count, str) +} + func main() { - flag.Parse() - if len(*file) > 0 { - compileSingleFile(*file) - return - } + testIt() - if len(*ext) == 0 { - logger.Fatalf("ext cannot be empty") - } - if len(*dir) == 0 { - *dir = "." - } - if (*ext)[0] != '.' { - *ext = "." + *ext - } + // flag.Parse() + + // if len(*file) > 0 { + // compileSingleFile(*file) + // return + // } + + // if len(*ext) == 0 { + // logger.Fatalf("ext cannot be empty") + // } + // if len(*dir) == 0 { + // *dir = "." + // } + // if (*ext)[0] != '.' { + // *ext = "." + *ext + // } - logger.Printf("Compiling *%s template files in directory %q", *ext, *dir) - compileDir(*dir) - logger.Printf("Total files compiled: %d", filesCompiled) + // logger.Printf("Compiling *%s template files in directory %q", *ext, *dir) + // compileDir(*dir) + // logger.Printf("Total files compiled: %d", filesCompiled) } func compileSingleFile(filename string) { diff --git a/qtc/parser.go b/qtc/parser.go index e313205..c65082e 100644 --- a/qtc/parser.go +++ b/qtc/parser.go @@ -13,7 +13,7 @@ import ( ) type parser struct { - s *scanner + s *Scanner w io.Writer packageName string prefix string @@ -805,7 +805,7 @@ func (p *parser) Printf(format string, args ...interface{}) { fmt.Fprintf(w, "\n") } -func skipTagContents(s *scanner) error { +func skipTagContents(s *Scanner) error { tagName := string(s.Token().Value) t, err := expectTagContents(s) if err != nil { @@ -817,11 +817,11 @@ func skipTagContents(s *scanner) error { return err } -func expectTagContents(s *scanner) (*token, error) { +func expectTagContents(s *Scanner) (*token, error) { return expectToken(s, tagContents) } -func expectToken(s *scanner, id int) (*token, error) { +func expectToken(s *Scanner, id int) (*token, error) { if !s.Next() { return nil, fmt.Errorf("cannot find token %s: %v", tokenIDToStr(id), s.LastError()) } diff --git a/qtc/scanner.go b/qtc/scanner.go index f48f84a..f8b30e2 100644 --- a/qtc/scanner.go +++ b/qtc/scanner.go @@ -48,11 +48,13 @@ func (t *token) String() string { return fmt.Sprintf("Token %q, value %q", tokenIDToStr(t.ID), t.Value) } -type scanner struct { - r *bufio.Reader - t token - c byte - err error +type Scanner struct { + openingTag []byte + closingTag []byte + r *bufio.Reader + t token + c byte + err error filePath string @@ -69,21 +71,37 @@ type scanner struct { rewind bool } -func newScanner(r io.Reader, filePath string) *scanner { - return &scanner{ +/* +NewScanWithTagConf do something usefull +*/ +func NewScanWithTagConf(r io.Reader, filePath string, openTag string, closeTag string) *Scanner { + return newScannerWithTagConf(r, filePath, openTag, closeTag) +} + +func newScannerWithTagConf(r io.Reader, filePath string, openTag string, closeTag string) *Scanner { + return &Scanner{ + r: bufio.NewReader(r), + filePath: filePath, + openingTag: []byte(openTag), + closingTag: []byte(closeTag), + } +} + +func newScanner(r io.Reader, filePath string) *Scanner { + return &Scanner{ r: bufio.NewReader(r), filePath: filePath, } } -func (s *scanner) Rewind() { +func (s *Scanner) Rewind() { if s.rewind { panic("BUG: duplicate Rewind call") } s.rewind = true } -func (s *scanner) Next() bool { +func (s *Scanner) Next() bool { if s.rewind { s.rewind = false return true @@ -166,7 +184,7 @@ func (s *scanner) Next() bool { } } -func (s *scanner) readPlain() bool { +func (s *Scanner) readPlain() bool { if !s.readTagContents() { return false } @@ -177,35 +195,35 @@ func (s *scanner) readPlain() bool { v := s.stopCapture() s.t.init(text, startLine, startPos) if ok { - n := bytes.LastIndex(v, strTagOpen) + n := bytes.LastIndex(v, s.openingTag) v = v[:n] s.t.Value = append(s.t.Value[:0], v...) } return ok } -var strTagOpen = []byte("{%") +//var strTagOpen = openingTag //[]byte("{%") -func (s *scanner) skipComment() bool { +func (s *Scanner) skipComment() bool { if !s.readTagContents() { return false } return s.skipUntilTag("endcomment") } -func (s *scanner) skipUntilTag(tagName string) bool { +func (s *Scanner) skipUntilTag(tagName string) bool { ok := false for { if !s.nextByte() { break } - if s.c != '{' { + if s.c != s.openingTag[0] { continue } if !s.nextByte() { break } - if s.c != '%' { + if s.c != s.openingTag[1] { s.unreadByte('~') continue } @@ -226,7 +244,7 @@ func (s *scanner) skipUntilTag(tagName string) bool { return ok } -func (s *scanner) scanToken() bool { +func (s *Scanner) scanToken() bool { switch s.nextTokenID { case text: return s.readText() @@ -239,7 +257,7 @@ func (s *scanner) scanToken() bool { } } -func (s *scanner) readText() bool { +func (s *Scanner) readText() bool { s.t.init(text, s.line, s.pos()) ok := false for { @@ -247,7 +265,7 @@ func (s *scanner) readText() bool { ok = (len(s.t.Value) > 0) break } - if s.c != '{' { + if s.c != s.openingTag[0] { s.appendByte() continue } @@ -261,7 +279,7 @@ func (s *scanner) readText() bool { ok = true break } - s.unreadByte('{') + s.unreadByte(s.openingTag[0]) s.appendByte() } if s.stripSpaceDepth > 0 { @@ -272,7 +290,7 @@ func (s *scanner) readText() bool { return ok } -func (s *scanner) readTagName() bool { +func (s *Scanner) readTagName() bool { s.skipSpace() s.t.init(tagName, s.line, s.pos()) for { @@ -296,11 +314,11 @@ func (s *scanner) readTagName() bool { } } -func (s *scanner) readTagContents() bool { +func (s *Scanner) readTagContents() bool { s.skipSpace() s.t.init(tagContents, s.line, s.pos()) for { - if s.c != '%' { + if s.c != s.closingTag[0] { s.appendByte() if !s.nextByte() { return false @@ -311,7 +329,7 @@ func (s *scanner) readTagContents() bool { s.appendByte() return false } - if s.c == '}' { + if s.c == s.closingTag[1] { s.nextTokenID = text s.t.Value = stripTrailingSpace(s.t.Value) return true @@ -324,16 +342,16 @@ func (s *scanner) readTagContents() bool { } } -func (s *scanner) skipSpace() { +func (s *Scanner) skipSpace() { for s.nextByte() && s.isSpace() { } } -func (s *scanner) isSpace() bool { +func (s *Scanner) isSpace() bool { return isSpace(s.c) } -func (s *scanner) nextByte() bool { +func (s *Scanner) nextByte() bool { if s.err != nil { return false } @@ -358,23 +376,23 @@ func (s *scanner) nextByte() bool { return true } -func (s *scanner) startCapture() { +func (s *Scanner) startCapture() { s.capture = true s.capturedValue = s.capturedValue[:0] } -func (s *scanner) stopCapture() []byte { +func (s *Scanner) stopCapture() []byte { s.capture = false v := s.capturedValue s.capturedValue = s.capturedValue[:0] return v } -func (s *scanner) Token() *token { +func (s *Scanner) Token() *token { return &s.t } -func (s *scanner) LastError() error { +func (s *Scanner) LastError() error { if s.err == nil { return nil } @@ -392,11 +410,11 @@ func (s *scanner) LastError() error { tokenIDToStr(s.t.ID), s.Context(), s.err) } -func (s *scanner) appendByte() { +func (s *Scanner) appendByte() { s.t.Value = append(s.t.Value, s.c) } -func (s *scanner) unreadByte(c byte) { +func (s *Scanner) unreadByte(c byte) { if err := s.r.UnreadByte(); err != nil { panic(fmt.Sprintf("BUG: bufio.Reader.UnreadByte returned non-nil error: %s", err)) } @@ -412,17 +430,17 @@ func (s *scanner) unreadByte(c byte) { s.c = c } -func (s *scanner) pos() int { +func (s *Scanner) pos() int { return len(s.lineStr) } -func (s *scanner) Context() string { +func (s *Scanner) Context() string { t := s.Token() return fmt.Sprintf("file %q, line %d, pos %d, token %s, last line %s", s.filePath, t.line+1, t.pos, snippet(t.Value), snippet(s.lineStr)) } -func (s *scanner) WriteLineComment(w io.Writer) { +func (s *Scanner) WriteLineComment(w io.Writer) { fmt.Fprintf(w, "//line %s:%d\n", s.filePath, s.t.line+1) } From 47110c2eeb723d36e1049f575510ac85541f405f Mon Sep 17 00:00:00 2001 From: b3b00 Date: Wed, 17 Apr 2019 16:51:28 +0200 Subject: [PATCH 02/10] scanner configuration unit tests --- qtc/scanner.go | 5 +--- qtc/scanner_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/qtc/scanner.go b/qtc/scanner.go index f8b30e2..a19468b 100644 --- a/qtc/scanner.go +++ b/qtc/scanner.go @@ -88,10 +88,7 @@ func newScannerWithTagConf(r io.Reader, filePath string, openTag string, closeTa } func newScanner(r io.Reader, filePath string) *Scanner { - return &Scanner{ - r: bufio.NewReader(r), - filePath: filePath, - } + return newScannerWithTagConf(r, filePath, "{%", "%}") } func (s *Scanner) Rewind() { diff --git a/qtc/scanner_test.go b/qtc/scanner_test.go index 26f333a..6c99817 100644 --- a/qtc/scanner_test.go +++ b/qtc/scanner_test.go @@ -220,6 +220,63 @@ func testScannerSuccess(t *testing.T, str string, expectedTokens []tt) { } } +func TestConfigurationScannerSuccess(t *testing.T) { + testConfigurationScannerSuccess(t, "", "[%", "%]", nil) + testConfigurationScannerSuccess(t, "a%]{foo}bar", "[%", "%]", []tt{ + {ID: text, Value: "a%]{foo}bar"}, + }) + testConfigurationScannerSuccess(t, "[% foo bar baz(a, b, 123) %]", "[%", "%]", []tt{ + {ID: tagName, Value: "foo"}, + {ID: tagContents, Value: "bar baz(a, b, 123)"}, + }) + testConfigurationScannerSuccess(t, "foo[%bar%]baz", "[%", "%]", []tt{ + {ID: text, Value: "foo"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: ""}, + {ID: text, Value: "baz"}, + }) + testConfigurationScannerSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r %]}", "[%", "%]", []tt{ + {ID: text, Value: "{{"}, + {ID: tagName, Value: "foo"}, + {ID: tagContents, Value: "bar\n\rbaz%%"}, + {ID: text, Value: "}"}, + }) + testConfigurationScannerSuccess(t, "[%%]", "[%", "%]", []tt{ + {ID: tagName, Value: ""}, + {ID: tagContents, Value: ""}, + }) + testConfigurationScannerSuccess(t, "[%%aaa bb%]", "[%", "%]", []tt{ + {ID: tagName, Value: ""}, + {ID: tagContents, Value: "%aaa bb"}, + }) + testConfigurationScannerSuccess(t, "foo[% bar %][% baz aa (123)%]321", "[%", "%]", []tt{ + {ID: text, Value: "foo"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: ""}, + {ID: tagName, Value: "baz"}, + {ID: tagContents, Value: "aa (123)"}, + {ID: text, Value: "321"}, + }) +} + +func testConfigurationScannerSuccess(t *testing.T, str string, startTag string, endTag string, expectedTokens []tt) { + r := bytes.NewBufferString(str) + s := newScannerWithTagConf(r, "memory", startTag, endTag) + var tokens []tt + for s.Next() { + tokens = append(tokens, tt{ + ID: s.Token().ID, + Value: string(s.Token().Value), + }) + } + if err := s.LastError(); err != nil { + t.Fatalf("unexpected error: %s. str=%q", err, str) + } + if !reflect.DeepEqual(tokens, expectedTokens) { + t.Fatalf("unexpected tokens %v. Expecting %v. str=%q", tokens, expectedTokens, str) + } +} + type tt struct { ID int Value string From 8454b46f71e0f6e45636d2b07330d5f453dc9c92 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Wed, 17 Apr 2019 17:15:44 +0200 Subject: [PATCH 03/10] unit tests --- qtc/main.go | 41 +++++++++++++++++++++++++++----- qtc/parser.go | 8 +++---- qtc/scanner.go | 57 ++++++++++++++++++++------------------------- qtc/scanner_test.go | 8 +++++++ 4 files changed, 72 insertions(+), 42 deletions(-) diff --git a/qtc/main.go b/qtc/main.go index 8ab82d0..2abd644 100644 --- a/qtc/main.go +++ b/qtc/main.go @@ -29,23 +29,51 @@ var logger = log.New(os.Stderr, "qtc: ", log.LstdFlags) var filesCompiled int -type tt struct { +type myToken struct { ID int Value string } -func testIt() { +func testItBrace() { str := "header {%stripspace %} toto et tata {%endstripspace %} footer" r := bytes.NewBufferString(str) - s := NewScanWithTagConf(r, "memory", "{%", "%}") - var tokens []tt + s := newScanner(r, "memory") + var tokens []myToken i := 0 for s.Next() { tok := s.Token() id := tok.ID val := string(tok.Value) fmt.Printf("%d - %s\n", id, val) - tokens = append(tokens, tt{ + tokens = append(tokens, myToken{ + ID: s.Token().ID, + Value: string(s.Token().Value), + }) + fmt.Printf("token[%d] : %d - %s\n", i, s.Token().ID, string(s.Token().Value)) + i++ + } + count := len(tokens) + + fmt.Printf("found %d tokens when scanning %q. \n", count, str) +} + +func testItBracket() { + str := `header [%stripspace %] + toto + {% moustache %} + et + tata + [%endstripspace %] footer` + r := bytes.NewBufferString(str) + s := newScannerWithTagConf(r, "memory", "[%", "%]") + var tokens []myToken + i := 0 + for s.Next() { + tok := s.Token() + id := tok.ID + val := string(tok.Value) + fmt.Printf("%d - %s\n", id, val) + tokens = append(tokens, myToken{ ID: s.Token().ID, Value: string(s.Token().Value), }) @@ -59,7 +87,8 @@ func testIt() { func main() { - testIt() + //testItBrace() + testItBracket() // flag.Parse() diff --git a/qtc/parser.go b/qtc/parser.go index c65082e..e313205 100644 --- a/qtc/parser.go +++ b/qtc/parser.go @@ -13,7 +13,7 @@ import ( ) type parser struct { - s *Scanner + s *scanner w io.Writer packageName string prefix string @@ -805,7 +805,7 @@ func (p *parser) Printf(format string, args ...interface{}) { fmt.Fprintf(w, "\n") } -func skipTagContents(s *Scanner) error { +func skipTagContents(s *scanner) error { tagName := string(s.Token().Value) t, err := expectTagContents(s) if err != nil { @@ -817,11 +817,11 @@ func skipTagContents(s *Scanner) error { return err } -func expectTagContents(s *Scanner) (*token, error) { +func expectTagContents(s *scanner) (*token, error) { return expectToken(s, tagContents) } -func expectToken(s *Scanner, id int) (*token, error) { +func expectToken(s *scanner, id int) (*token, error) { if !s.Next() { return nil, fmt.Errorf("cannot find token %s: %v", tokenIDToStr(id), s.LastError()) } diff --git a/qtc/scanner.go b/qtc/scanner.go index a19468b..5b493ca 100644 --- a/qtc/scanner.go +++ b/qtc/scanner.go @@ -48,7 +48,7 @@ func (t *token) String() string { return fmt.Sprintf("Token %q, value %q", tokenIDToStr(t.ID), t.Value) } -type Scanner struct { +type scanner struct { openingTag []byte closingTag []byte r *bufio.Reader @@ -71,15 +71,8 @@ type Scanner struct { rewind bool } -/* -NewScanWithTagConf do something usefull -*/ -func NewScanWithTagConf(r io.Reader, filePath string, openTag string, closeTag string) *Scanner { - return newScannerWithTagConf(r, filePath, openTag, closeTag) -} - -func newScannerWithTagConf(r io.Reader, filePath string, openTag string, closeTag string) *Scanner { - return &Scanner{ +func newScannerWithTagConf(r io.Reader, filePath string, openTag string, closeTag string) *scanner { + return &scanner{ r: bufio.NewReader(r), filePath: filePath, openingTag: []byte(openTag), @@ -87,18 +80,18 @@ func newScannerWithTagConf(r io.Reader, filePath string, openTag string, closeTa } } -func newScanner(r io.Reader, filePath string) *Scanner { +func newScanner(r io.Reader, filePath string) *scanner { return newScannerWithTagConf(r, filePath, "{%", "%}") } -func (s *Scanner) Rewind() { +func (s *scanner) Rewind() { if s.rewind { panic("BUG: duplicate Rewind call") } s.rewind = true } -func (s *Scanner) Next() bool { +func (s *scanner) Next() bool { if s.rewind { s.rewind = false return true @@ -181,7 +174,7 @@ func (s *Scanner) Next() bool { } } -func (s *Scanner) readPlain() bool { +func (s *scanner) readPlain() bool { if !s.readTagContents() { return false } @@ -201,14 +194,14 @@ func (s *Scanner) readPlain() bool { //var strTagOpen = openingTag //[]byte("{%") -func (s *Scanner) skipComment() bool { +func (s *scanner) skipComment() bool { if !s.readTagContents() { return false } return s.skipUntilTag("endcomment") } -func (s *Scanner) skipUntilTag(tagName string) bool { +func (s *scanner) skipUntilTag(tagName string) bool { ok := false for { if !s.nextByte() { @@ -241,7 +234,7 @@ func (s *Scanner) skipUntilTag(tagName string) bool { return ok } -func (s *Scanner) scanToken() bool { +func (s *scanner) scanToken() bool { switch s.nextTokenID { case text: return s.readText() @@ -254,7 +247,7 @@ func (s *Scanner) scanToken() bool { } } -func (s *Scanner) readText() bool { +func (s *scanner) readText() bool { s.t.init(text, s.line, s.pos()) ok := false for { @@ -287,7 +280,7 @@ func (s *Scanner) readText() bool { return ok } -func (s *Scanner) readTagName() bool { +func (s *scanner) readTagName() bool { s.skipSpace() s.t.init(tagName, s.line, s.pos()) for { @@ -311,7 +304,7 @@ func (s *Scanner) readTagName() bool { } } -func (s *Scanner) readTagContents() bool { +func (s *scanner) readTagContents() bool { s.skipSpace() s.t.init(tagContents, s.line, s.pos()) for { @@ -339,16 +332,16 @@ func (s *Scanner) readTagContents() bool { } } -func (s *Scanner) skipSpace() { +func (s *scanner) skipSpace() { for s.nextByte() && s.isSpace() { } } -func (s *Scanner) isSpace() bool { +func (s *scanner) isSpace() bool { return isSpace(s.c) } -func (s *Scanner) nextByte() bool { +func (s *scanner) nextByte() bool { if s.err != nil { return false } @@ -373,23 +366,23 @@ func (s *Scanner) nextByte() bool { return true } -func (s *Scanner) startCapture() { +func (s *scanner) startCapture() { s.capture = true s.capturedValue = s.capturedValue[:0] } -func (s *Scanner) stopCapture() []byte { +func (s *scanner) stopCapture() []byte { s.capture = false v := s.capturedValue s.capturedValue = s.capturedValue[:0] return v } -func (s *Scanner) Token() *token { +func (s *scanner) Token() *token { return &s.t } -func (s *Scanner) LastError() error { +func (s *scanner) LastError() error { if s.err == nil { return nil } @@ -407,11 +400,11 @@ func (s *Scanner) LastError() error { tokenIDToStr(s.t.ID), s.Context(), s.err) } -func (s *Scanner) appendByte() { +func (s *scanner) appendByte() { s.t.Value = append(s.t.Value, s.c) } -func (s *Scanner) unreadByte(c byte) { +func (s *scanner) unreadByte(c byte) { if err := s.r.UnreadByte(); err != nil { panic(fmt.Sprintf("BUG: bufio.Reader.UnreadByte returned non-nil error: %s", err)) } @@ -427,17 +420,17 @@ func (s *Scanner) unreadByte(c byte) { s.c = c } -func (s *Scanner) pos() int { +func (s *scanner) pos() int { return len(s.lineStr) } -func (s *Scanner) Context() string { +func (s *scanner) Context() string { t := s.Token() return fmt.Sprintf("file %q, line %d, pos %d, token %s, last line %s", s.filePath, t.line+1, t.pos, snippet(t.Value), snippet(s.lineStr)) } -func (s *Scanner) WriteLineComment(w io.Writer) { +func (s *scanner) WriteLineComment(w io.Writer) { fmt.Fprintf(w, "//line %s:%d\n", s.filePath, s.t.line+1) } diff --git a/qtc/scanner_test.go b/qtc/scanner_test.go index 6c99817..03e7789 100644 --- a/qtc/scanner_test.go +++ b/qtc/scanner_test.go @@ -257,6 +257,14 @@ func TestConfigurationScannerSuccess(t *testing.T) { {ID: tagContents, Value: "aa (123)"}, {ID: text, Value: "321"}, }) + testConfigurationScannerSuccess(t, " aa\n\t [%stripspace%] \t\n f\too \n b ar \n\r\t [% bar baz asd %]\n\nbaz \n\t \taaa \n[%endstripspace%] bb ", "[%", "%]", []tt{ + {ID: text, Value: " aa\n\t "}, + {ID: text, Value: "f\toob ar"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: "baz asd"}, + {ID: text, Value: "bazaaa"}, + {ID: text, Value: " bb "}, + }) } func testConfigurationScannerSuccess(t *testing.T, str string, startTag string, endTag string, expectedTokens []tt) { From 6a21fa142237d6cfcaa34142bd6f07aa1e656189 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Thu, 18 Apr 2019 11:09:47 +0200 Subject: [PATCH 04/10] scanner unit tests refactoring --- qtc/main.go | 110 +++-------- qtc/parser.go | 24 ++- qtc/parser_test.go | 6 +- qtc/scanner.go | 2 +- qtc/scanner_test.go | 126 ++++++------ qtc/scanner_with_conf_test.go | 349 ++++++++++++++++++++++++++++++++++ 6 files changed, 463 insertions(+), 154 deletions(-) create mode 100644 qtc/scanner_with_conf_test.go diff --git a/qtc/main.go b/qtc/main.go index 2abd644..06b02ff 100644 --- a/qtc/main.go +++ b/qtc/main.go @@ -1,9 +1,7 @@ package main import ( - "bytes" "flag" - "fmt" "go/format" "io/ioutil" "log" @@ -22,94 +20,36 @@ var ( file = flag.String("file", "", "Path to template file to compile.\n"+ "Flags -dir and -ext are ignored if file is set.\n"+ "The compiled file will be placed near the original file with .go extension added.") - ext = flag.String("ext", "qtpl", "Only files with this extension are compiled") + ext = flag.String("ext", "qtpl", "Only files with this extension are compiled") + startTag = flag.String("sTag", "{%", "tag starting delimiter (2 chars)") + endTag = flag.String("eTag", "{%", "tag ending delimiter (2 chars)") ) var logger = log.New(os.Stderr, "qtc: ", log.LstdFlags) var filesCompiled int -type myToken struct { - ID int - Value string -} - -func testItBrace() { - str := "header {%stripspace %} toto et tata {%endstripspace %} footer" - r := bytes.NewBufferString(str) - s := newScanner(r, "memory") - var tokens []myToken - i := 0 - for s.Next() { - tok := s.Token() - id := tok.ID - val := string(tok.Value) - fmt.Printf("%d - %s\n", id, val) - tokens = append(tokens, myToken{ - ID: s.Token().ID, - Value: string(s.Token().Value), - }) - fmt.Printf("token[%d] : %d - %s\n", i, s.Token().ID, string(s.Token().Value)) - i++ - } - count := len(tokens) - - fmt.Printf("found %d tokens when scanning %q. \n", count, str) -} +func main() { + flag.Parse() -func testItBracket() { - str := `header [%stripspace %] - toto - {% moustache %} - et - tata - [%endstripspace %] footer` - r := bytes.NewBufferString(str) - s := newScannerWithTagConf(r, "memory", "[%", "%]") - var tokens []myToken - i := 0 - for s.Next() { - tok := s.Token() - id := tok.ID - val := string(tok.Value) - fmt.Printf("%d - %s\n", id, val) - tokens = append(tokens, myToken{ - ID: s.Token().ID, - Value: string(s.Token().Value), - }) - fmt.Printf("token[%d] : %d - %s\n", i, s.Token().ID, string(s.Token().Value)) - i++ - } - count := len(tokens) - - fmt.Printf("found %d tokens when scanning %q. \n", count, str) -} + if len(*file) > 0 { + compileSingleFile(*file) + return + } -func main() { + if len(*ext) == 0 { + logger.Fatalf("ext cannot be empty") + } + if len(*dir) == 0 { + *dir = "." + } + if (*ext)[0] != '.' { + *ext = "." + *ext + } - //testItBrace() - testItBracket() - - // flag.Parse() - - // if len(*file) > 0 { - // compileSingleFile(*file) - // return - // } - - // if len(*ext) == 0 { - // logger.Fatalf("ext cannot be empty") - // } - // if len(*dir) == 0 { - // *dir = "." - // } - // if (*ext)[0] != '.' { - // *ext = "." + *ext - // } - - // logger.Printf("Compiling *%s template files in directory %q", *ext, *dir) - // compileDir(*dir) - // logger.Printf("Total files compiled: %d", filesCompiled) + logger.Printf("Compiling *%s template files in directory %q", *ext, *dir) + compileDir(*dir) + logger.Printf("Total files compiled: %d", filesCompiled) } func compileSingleFile(filename string) { @@ -184,7 +124,13 @@ func compileFile(infile string) { if err != nil { logger.Fatalf("cannot determine package name for %q: %s", infile, err) } - if err = parse(outf, inf, infile, packageName); err != nil { + + var scannerConfig = &config{ + TagStartingDelimiter: *startTag, + TagEndingDelimiter: *endTag, + } + + if err = parse(outf, inf, infile, packageName, scannerConfig); err != nil { logger.Fatalf("error when parsing file %q: %s", infile, err) } if err = outf.Close(); err != nil { diff --git a/qtc/parser.go b/qtc/parser.go index e313205..648da84 100644 --- a/qtc/parser.go +++ b/qtc/parser.go @@ -25,11 +25,25 @@ type parser struct { packageNameEmitted bool } -func parse(w io.Writer, r io.Reader, filePath, packageName string) error { - p := &parser{ - s: newScanner(r, filePath), - w: w, - packageName: packageName, +type config struct { + TagStartingDelimiter string + TagEndingDelimiter string +} + +func parse(w io.Writer, r io.Reader, filePath, packageName string, parserConfig *config) error { + var p *parser + if parserConfig == nil { + p = &parser{ + s: newScanner(r, filePath), + w: w, + packageName: packageName, + } + } else { + p = &parser{ + s: newScannerWithTagConf(r, filePath, parserConfig.TagStartingDelimiter, parserConfig.TagEndingDelimiter), + w: w, + packageName: packageName, + } } return p.parseTemplate() } diff --git a/qtc/parser_test.go b/qtc/parser_test.go index b34cc0c..707270f 100644 --- a/qtc/parser_test.go +++ b/qtc/parser_test.go @@ -549,7 +549,7 @@ else func testParseFailure(t *testing.T, str string) { r := bytes.NewBufferString(str) w := &bytes.Buffer{} - if err := parse(w, r, "./foobar.tpl", "memory"); err == nil { + if err := parse(w, r, "./foobar.tpl", "memory", nil); err == nil { t.Fatalf("expecting error when parsing %q", str) } } @@ -557,7 +557,7 @@ func testParseFailure(t *testing.T, str string) { func testParseSuccess(t *testing.T, str string) { r := bytes.NewBufferString(str) w := &bytes.Buffer{} - if err := parse(w, r, "./foobar.tpl", "memory"); err != nil { + if err := parse(w, r, "./foobar.tpl", "memory", nil); err != nil { t.Fatalf("unexpected error when parsing %q: %s", str, err) } } @@ -576,7 +576,7 @@ func TestParseFile(t *testing.T) { } w := quicktemplate.AcquireByteBuffer() - if err := parse(w, f, filename, packageName); err != nil { + if err := parse(w, f, filename, packageName, nil); err != nil { t.Fatalf("unexpected error: %s", err) } code, err := format.Source(w.B) diff --git a/qtc/scanner.go b/qtc/scanner.go index 5b493ca..437d514 100644 --- a/qtc/scanner.go +++ b/qtc/scanner.go @@ -264,7 +264,7 @@ func (s *scanner) readText() bool { ok = true break } - if s.c == '%' { + if s.c == s.openingTag[1] { s.nextTokenID = tagName ok = true break diff --git a/qtc/scanner_test.go b/qtc/scanner_test.go index 03e7789..dea1943 100644 --- a/qtc/scanner_test.go +++ b/qtc/scanner_test.go @@ -220,70 +220,70 @@ func testScannerSuccess(t *testing.T, str string, expectedTokens []tt) { } } -func TestConfigurationScannerSuccess(t *testing.T) { - testConfigurationScannerSuccess(t, "", "[%", "%]", nil) - testConfigurationScannerSuccess(t, "a%]{foo}bar", "[%", "%]", []tt{ - {ID: text, Value: "a%]{foo}bar"}, - }) - testConfigurationScannerSuccess(t, "[% foo bar baz(a, b, 123) %]", "[%", "%]", []tt{ - {ID: tagName, Value: "foo"}, - {ID: tagContents, Value: "bar baz(a, b, 123)"}, - }) - testConfigurationScannerSuccess(t, "foo[%bar%]baz", "[%", "%]", []tt{ - {ID: text, Value: "foo"}, - {ID: tagName, Value: "bar"}, - {ID: tagContents, Value: ""}, - {ID: text, Value: "baz"}, - }) - testConfigurationScannerSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r %]}", "[%", "%]", []tt{ - {ID: text, Value: "{{"}, - {ID: tagName, Value: "foo"}, - {ID: tagContents, Value: "bar\n\rbaz%%"}, - {ID: text, Value: "}"}, - }) - testConfigurationScannerSuccess(t, "[%%]", "[%", "%]", []tt{ - {ID: tagName, Value: ""}, - {ID: tagContents, Value: ""}, - }) - testConfigurationScannerSuccess(t, "[%%aaa bb%]", "[%", "%]", []tt{ - {ID: tagName, Value: ""}, - {ID: tagContents, Value: "%aaa bb"}, - }) - testConfigurationScannerSuccess(t, "foo[% bar %][% baz aa (123)%]321", "[%", "%]", []tt{ - {ID: text, Value: "foo"}, - {ID: tagName, Value: "bar"}, - {ID: tagContents, Value: ""}, - {ID: tagName, Value: "baz"}, - {ID: tagContents, Value: "aa (123)"}, - {ID: text, Value: "321"}, - }) - testConfigurationScannerSuccess(t, " aa\n\t [%stripspace%] \t\n f\too \n b ar \n\r\t [% bar baz asd %]\n\nbaz \n\t \taaa \n[%endstripspace%] bb ", "[%", "%]", []tt{ - {ID: text, Value: " aa\n\t "}, - {ID: text, Value: "f\toob ar"}, - {ID: tagName, Value: "bar"}, - {ID: tagContents, Value: "baz asd"}, - {ID: text, Value: "bazaaa"}, - {ID: text, Value: " bb "}, - }) -} +// func TestConfigurationScannerSuccess(t *testing.T) { +// testConfigurationScannerSuccess(t, "", "[%", "%]", nil) +// testConfigurationScannerSuccess(t, "a%]{foo}bar", "[%", "%]", []tt{ +// {ID: text, Value: "a%]{foo}bar"}, +// }) +// testConfigurationScannerSuccess(t, "[% foo bar baz(a, b, 123) %]", "[%", "%]", []tt{ +// {ID: tagName, Value: "foo"}, +// {ID: tagContents, Value: "bar baz(a, b, 123)"}, +// }) +// testConfigurationScannerSuccess(t, "foo[%bar%]baz", "[%", "%]", []tt{ +// {ID: text, Value: "foo"}, +// {ID: tagName, Value: "bar"}, +// {ID: tagContents, Value: ""}, +// {ID: text, Value: "baz"}, +// }) +// testConfigurationScannerSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r %]}", "[%", "%]", []tt{ +// {ID: text, Value: "{{"}, +// {ID: tagName, Value: "foo"}, +// {ID: tagContents, Value: "bar\n\rbaz%%"}, +// {ID: text, Value: "}"}, +// }) +// testConfigurationScannerSuccess(t, "[%%]", "[%", "%]", []tt{ +// {ID: tagName, Value: ""}, +// {ID: tagContents, Value: ""}, +// }) +// testConfigurationScannerSuccess(t, "[%%aaa bb%]", "[%", "%]", []tt{ +// {ID: tagName, Value: ""}, +// {ID: tagContents, Value: "%aaa bb"}, +// }) +// testConfigurationScannerSuccess(t, "foo[% bar %][% baz aa (123)%]321", "[%", "%]", []tt{ +// {ID: text, Value: "foo"}, +// {ID: tagName, Value: "bar"}, +// {ID: tagContents, Value: ""}, +// {ID: tagName, Value: "baz"}, +// {ID: tagContents, Value: "aa (123)"}, +// {ID: text, Value: "321"}, +// }) +// testConfigurationScannerSuccess(t, " aa\n\t [%stripspace%] \t\n f\too \n b ar \n\r\t [% bar baz asd %]\n\nbaz \n\t \taaa \n[%endstripspace%] bb ", "[%", "%]", []tt{ +// {ID: text, Value: " aa\n\t "}, +// {ID: text, Value: "f\toob ar"}, +// {ID: tagName, Value: "bar"}, +// {ID: tagContents, Value: "baz asd"}, +// {ID: text, Value: "bazaaa"}, +// {ID: text, Value: " bb "}, +// }) +// } -func testConfigurationScannerSuccess(t *testing.T, str string, startTag string, endTag string, expectedTokens []tt) { - r := bytes.NewBufferString(str) - s := newScannerWithTagConf(r, "memory", startTag, endTag) - var tokens []tt - for s.Next() { - tokens = append(tokens, tt{ - ID: s.Token().ID, - Value: string(s.Token().Value), - }) - } - if err := s.LastError(); err != nil { - t.Fatalf("unexpected error: %s. str=%q", err, str) - } - if !reflect.DeepEqual(tokens, expectedTokens) { - t.Fatalf("unexpected tokens %v. Expecting %v. str=%q", tokens, expectedTokens, str) - } -} +// func testConfigurationScannerSuccess(t *testing.T, str string, startTag string, endTag string, expectedTokens []tt) { +// r := bytes.NewBufferString(str) +// s := newScannerWithTagConf(r, "memory", startTag, endTag) +// var tokens []tt +// for s.Next() { +// tokens = append(tokens, tt{ +// ID: s.Token().ID, +// Value: string(s.Token().Value), +// }) +// } +// if err := s.LastError(); err != nil { +// t.Fatalf("unexpected error: %s. str=%q", err, str) +// } +// if !reflect.DeepEqual(tokens, expectedTokens) { +// t.Fatalf("unexpected tokens %v. Expecting %v. str=%q", tokens, expectedTokens, str) +// } +// } type tt struct { ID int diff --git a/qtc/scanner_with_conf_test.go b/qtc/scanner_with_conf_test.go new file mode 100644 index 0000000..5250bbb --- /dev/null +++ b/qtc/scanner_with_conf_test.go @@ -0,0 +1,349 @@ +package main + +import ( + "bytes" + "fmt" + "reflect" + "testing" +) + +/*TestScannerConfigurationTagNameWithDotAndEqual ..." + */ +func TestScannerConfigurationTagNameWithDotAndEqual(t *testing.T) { + testScannerConfigurationSuccess(t, "[{foo.bar.34 baz aaa}] awer[{ aa= }]", + []confToken{ + {ID: tagName, Value: "foo.bar.34"}, + {ID: tagContents, Value: "baz aaa"}, + {ID: text, Value: " awer"}, + {ID: tagName, Value: "aa="}, + {ID: tagContents, Value: ""}, + }) +} + +/*TestScannerConfigurationStripspaceSuccess ... + */ +func TestScannerConfigurationStripspaceSuccess(t *testing.T) { + testScannerConfigurationSuccess(t, " aa\n\t [{stripspace}] \t\n f\too \n b ar \n\r\t [{ bar baz asd }]\n\nbaz \n\t \taaa \n[{endstripspace}] bb ", []confToken{ + {ID: text, Value: " aa\n\t "}, + {ID: text, Value: "f\toob ar"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: "baz asd"}, + {ID: text, Value: "bazaaa"}, + {ID: text, Value: " bb "}, + }) + testScannerConfigurationSuccess(t, "[{stripspace }][{ stripspace fobar }] [{space}] a\taa\n\r\t bb b [{endstripspace }] [{endstripspace baz}]", []confToken{ + {ID: text, Value: " "}, + {ID: text, Value: "a\taabb b"}, + }) + + // sripspace wins over collapsespace + testScannerConfigurationSuccess(t, "[{stripspace}] [{collapsespace}]foo\n\t bar[{endcollapsespace}] \r\n\t [{endstripspace}]", []confToken{ + {ID: text, Value: "foobar"}, + }) +} + +/*TestScannerConfigurationStripspaceFailure ... + */ +func TestScannerConfigurationStripspaceFailure(t *testing.T) { + // incomplete stripspace tag + testScannerConfigurationFailure(t, "[{stripspace ") + + // incomplete endstripspace tag + testScannerConfigurationFailure(t, "[{stripspace}]aaa[{endstripspace") + + // missing endstripspace + testScannerConfigurationFailure(t, "[{stripspace}] foobar") + + // missing stripspace + testScannerConfigurationFailure(t, "aaa[{endstripspace}]") + + // missing the second endstripspace + testScannerConfigurationFailure(t, "[{stripspace}][{stripspace}]aaaa[{endstripspace}]") +} + +/*TestScannerConfigurationCollapsespaceSuccess ... + */ +func TestScannerConfigurationCollapsespaceSuccess(t *testing.T) { + testScannerConfigurationSuccess(t, " aa\n\t [{collapsespace}] \t\n foo \n bar[{ bar baz asd }]\n\nbaz \n \n[{endcollapsespace}] bb ", []confToken{ + {ID: text, Value: " aa\n\t "}, + {ID: text, Value: " foo bar"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: "baz asd"}, + {ID: text, Value: " baz "}, + {ID: text, Value: " bb "}, + }) + testScannerConfigurationSuccess(t, "[{collapsespace }][{ collapsespace fobar }] [{space}] aaa\n\r\t bbb [{endcollapsespace }] [{endcollapsespace baz}]", []confToken{ + {ID: text, Value: " "}, + {ID: text, Value: " "}, + {ID: text, Value: " aaa bbb "}, + {ID: text, Value: " "}, + }) +} + +/*TestScannerCollapsespaceFailure ... + */ +func TestScannerConfigurationCollapsespaceFailure(t *testing.T) { + // incomplete collapsespace tag + testScannerConfigurationFailure(t, "[{collapsespace ") + + // incomplete endcollapsespace tag + testScannerConfigurationFailure(t, "[{collapsespace}]aaa[{endcollapsespace") + + // missing endcollapsespace + testScannerConfigurationFailure(t, "[{collapsespace}] foobar") + + // missing collapsespace + testScannerConfigurationFailure(t, "aaa[{endcollapsespace}]") + + // missing the second endcollapsespace + testScannerConfigurationFailure(t, "[{collapsespace}][{collapsespace}]aaaa[{endcollapsespace}]") +} + +/*TestScannerPlainSuccess ... + */ +func TestScannerConfigurationPlainSuccess(t *testing.T) { + testScannerConfigurationSuccess(t, "[{plain}][{endplain}]", nil) + testScannerConfigurationSuccess(t, "[{plain}][{foo bar}]asdf[{endplain}]", []confToken{ + {ID: text, Value: "[{foo bar}]asdf"}, + }) + testScannerConfigurationSuccess(t, "[{plain}][{foo[{endplain}]", []confToken{ + {ID: text, Value: "[{foo"}, + }) + testScannerConfigurationSuccess(t, "aa[{plain}]bbb[{cc}][{endplain}][{plain}]dsff[{endplain}]", []confToken{ + {ID: text, Value: "aa"}, + {ID: text, Value: "bbb[{cc}]"}, + {ID: text, Value: "dsff"}, + }) + testScannerConfigurationSuccess(t, "mmm[{plain}]aa[{ bar [{%% }baz[{endplain}]nnn", []confToken{ + {ID: text, Value: "mmm"}, + {ID: text, Value: "aa[{ bar [{%% }baz"}, + {ID: text, Value: "nnn"}, + }) + testScannerConfigurationSuccess(t, "[{ plain dsd }]0[{comment}]123[{endcomment}]45[{ endplain aaa }]", []confToken{ + {ID: text, Value: "0[{comment}]123[{endcomment}]45"}, + }) +} + +/*TestScannerPlainFailure ... + */ +func TestScannerConfigurationPlainFailure(t *testing.T) { + testScannerConfigurationFailure(t, "[{plain}]sdfds") + testScannerConfigurationFailure(t, "[{plain}]aaaa%[{endplain") + testScannerConfigurationFailure(t, "[{plain}][{endplain%") +} + +/*TestScannerCommentSuccess ... + */ +func TestScannerConfigurationCommentSuccess(t *testing.T) { + testScannerConfigurationSuccess(t, "[{comment}][{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}][{comment}]sss[{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]foo[{bar}][{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]foo[{bar [{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]foo[{bar&^[{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]foo[{ bar\n\rs%[{endcomment}]", nil) + testScannerConfigurationSuccess(t, "xx[{x}]www[{ comment aux data }]aaa[{ comment }][{ endcomment }]yy", []confToken{ + {ID: text, Value: "xx"}, + {ID: tagName, Value: "x"}, + {ID: tagContents, Value: ""}, + {ID: text, Value: "www"}, + {ID: text, Value: "yy"}, + }) +} + +/*TestScannerCommentFailure ... + */ +func TestScannerConfigurationCommentFailure(t *testing.T) { + testScannerConfigurationFailure(t, "[{comment}]...no endcomment") + testScannerConfigurationFailure(t, "[{ comment }]foobar[{ endcomment") +} + +func TestScannerConfigurationSuccess(t *testing.T) { + testScannerConfigurationSuccess(t, "", nil) + testScannerConfigurationSuccess(t, "a}]{foo}bar", []confToken{ + {ID: text, Value: "a}]{foo}bar"}, + }) + testScannerConfigurationSuccess(t, "[{ foo bar baz(a, b, 123) }]", []confToken{ + {ID: tagName, Value: "foo"}, + {ID: tagContents, Value: "bar baz(a, b, 123)"}, + }) + testScannerConfigurationSuccess(t, "foo[{bar}]baz", []confToken{ + {ID: text, Value: "foo"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: ""}, + {ID: text, Value: "baz"}, + }) + testScannerConfigurationSuccess(t, "{{[{\n\r\tfoo bar\n\rbaz%%\n \r }]}", []confToken{ + {ID: text, Value: "{{"}, + {ID: tagName, Value: "foo"}, + {ID: tagContents, Value: "bar\n\rbaz%%"}, + {ID: text, Value: "}"}, + }) + testScannerConfigurationSuccess(t, "[{}]", []confToken{ + {ID: tagName, Value: ""}, + {ID: tagContents, Value: ""}, + }) + testScannerConfigurationSuccess(t, "[{%aaa bb}]", []confToken{ + {ID: tagName, Value: ""}, + {ID: tagContents, Value: "%aaa bb"}, + }) + testScannerConfigurationSuccess(t, "foo[{ bar }][{ baz aa (123)}]321", []confToken{ + {ID: text, Value: "foo"}, + {ID: tagName, Value: "bar"}, + {ID: tagContents, Value: ""}, + {ID: tagName, Value: "baz"}, + {ID: tagContents, Value: "aa (123)"}, + {ID: text, Value: "321"}, + }) +} + +/*TestScannerConfigurationFailure ... + */ +func TestScannerConfigurationFailure(t *testing.T) { + testScannerConfigurationFailure(t, "a[{") + testScannerConfigurationFailure(t, "a[{foo") + testScannerConfigurationFailure(t, "a[{% }foo") + testScannerConfigurationFailure(t, "a[{ foo %") + testScannerConfigurationFailure(t, "b[{ fo() }]bar") + testScannerConfigurationFailure(t, "aa[{ foo bar") +} + +func testScannerConfigurationFailure(t *testing.T, str string) { + r := bytes.NewBufferString(str) + s := newScannerWithTagConf(r, "memory", "[{", "}]") + var tokens []confToken + for s.Next() { + id := s.Token().ID + val := string(s.Token().Value) + fmt.Printf("%d %s", id, val) + tokens = append(tokens, confToken{ + ID: s.Token().ID, + Value: string(s.Token().Value), + }) + } + if err := s.LastError(); err == nil { + t.Fatalf("expecting error when scanning %q. got tokens %v", str, tokens) + } +} + +func testScannerConfigurationSuccess(t *testing.T, str string, expectedTokens []confToken) { + r := bytes.NewBufferString(str) + s := newScannerWithTagConf(r, "memory", "[{", "}]") + var tokens []confToken + for s.Next() { + tokens = append(tokens, confToken{ + ID: s.Token().ID, + Value: string(s.Token().Value), + }) + } + if err := s.LastError(); err != nil { + t.Fatalf("unexpected error: %s. str=%q", err, str) + } + if !reflect.DeepEqual(tokens, expectedTokens) { + t.Fatalf("unexpected tokens %v. Expecting %v. str=%q", tokens, expectedTokens, str) + } +} + +// /*TestScannerConfigurationSuccessTest ... +// */ +// func TestScannerConfigurationSuccess(t *testing.T) { +// testScannerConfigurationSuccess(t, "", nil) +// testScannerConfigurationSuccess(t, "a%]{foo}bar", []confToken{ +// {ID: text, Value: "a%]{foo}bar"}, +// }) +// testScannerConfigurationSuccess(t, "[% foo bar baz(a, b, 123) %]", []confToken{ +// {ID: tagName, Value: "foo"}, +// {ID: tagContents, Value: "bar baz(a, b, 123)"}, +// }) +// testScannerConfigurationSuccess(t, "foo[%bar%]baz", []confToken{ +// {ID: text, Value: "foo"}, +// {ID: tagName, Value: "bar"}, +// {ID: tagContents, Value: ""}, +// {ID: text, Value: "baz"}, +// }) +// testScannerConfigurationSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r }]}", []confToken{ +// {ID: text, Value: "{{"}, +// {ID: tagName, Value: "foo"}, +// {ID: tagContents, Value: "bar\n\rbaz%%"}, +// {ID: text, Value: "}"}, +// }) +// testScannerConfigurationSuccess(t, "[%%]", []confToken{ +// {ID: tagName, Value: ""}, +// {ID: tagContents, Value: ""}, +// }) +// testScannerConfigurationSuccess(t, "[%%aaa bb%]", []confToken{ +// {ID: tagName, Value: ""}, +// {ID: tagContents, Value: "%aaa bb"}, +// }) +// testScannerConfigurationSuccess(t, "foo[% bar %][% baz aa (123)%]321", []confToken{ +// {ID: text, Value: "foo"}, +// {ID: tagName, Value: "bar"}, +// {ID: tagContents, Value: ""}, +// {ID: tagName, Value: "baz"}, +// {ID: tagContents, Value: "aa (123)"}, +// {ID: text, Value: "321"}, +// }) +// testScannerConfigurationSuccess(t, " aa\n\t [%stripspace%] \t\n f\too \n b ar \n\r\t [% bar baz asd %]\n\nbaz \n\t \taaa \n[%endstripspace%] bb ", []confToken{ +// {ID: text, Value: " aa\n\t "}, +// {ID: text, Value: "f\toob ar"}, +// {ID: tagName, Value: "bar"}, +// {ID: tagContents, Value: "baz asd"}, +// {ID: text, Value: "bazaaa"}, +// {ID: text, Value: " bb "}, +// }) +// } + +/*TestCrash ... + */ +func TestCrash(t *testing.T) { + + var source = `This is a base page template. All the other template pages implement this interface. + +{% interface +Page { + Title() + Body() +} +}] + + +Page prints a page implementing Page interface. +[{ func PageTemplate(p Page) }] + + + {%= p.Title() }] + + +
+ return to main page +
+ [{= p.Body() }] + + +[{ endfunc }] + + +Base page implementation. Other pages may inherit from it if they need +overriding only certain Page methods +[{ code type BasePage struct {} }] +[{ func (p *BasePage) Title() }]This is a base title[{ endfunc }] +[{ func (p *BasePage) Body() }]This is a base body[{ endfunc }] +}` + r := bytes.NewBufferString(source) + s := newScannerWithTagConf(r, "memory", "[{", "}]") + var tokens []confToken + for s.Next() { + tokens = append(tokens, confToken{ + ID: s.Token().ID, + Value: string(s.Token().Value), + }) + } + if err := s.LastError(); err != nil { + t.Fatalf("unexpected error: %s. str=%q", err, source) + } +} + +type confToken struct { + ID int + Value string +} From 56bbc74e7979aa068a740373566f763d76193468 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Thu, 18 Apr 2019 15:27:59 +0200 Subject: [PATCH 05/10] debugging --- qtc/scanner.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qtc/scanner.go b/qtc/scanner.go index 437d514..66a40a4 100644 --- a/qtc/scanner.go +++ b/qtc/scanner.go @@ -284,8 +284,8 @@ func (s *scanner) readTagName() bool { s.skipSpace() s.t.init(tagName, s.line, s.pos()) for { - if s.isSpace() || s.c == '%' { - if s.c == '%' { + if s.isSpace() || s.c == s.closingTag[0] { + if s.c == s.closingTag[0] { s.unreadByte('~') } s.nextTokenID = tagContents @@ -308,7 +308,7 @@ func (s *scanner) readTagContents() bool { s.skipSpace() s.t.init(tagContents, s.line, s.pos()) for { - if s.c != s.closingTag[0] { + if s.c != s.openingTag[0] { s.appendByte() if !s.nextByte() { return false @@ -319,7 +319,7 @@ func (s *scanner) readTagContents() bool { s.appendByte() return false } - if s.c == s.closingTag[1] { + if s.c == s.openingTag[1] { s.nextTokenID = text s.t.Value = stripTrailingSpace(s.t.Value) return true From 8ae2aaced93786e5f73cfb3ab74cc270dd029217 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Thu, 18 Apr 2019 16:12:01 +0200 Subject: [PATCH 06/10] UT --- qtc/scanner_with_conf_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtc/scanner_with_conf_test.go b/qtc/scanner_with_conf_test.go index 5250bbb..c0bb066 100644 --- a/qtc/scanner_with_conf_test.go +++ b/qtc/scanner_with_conf_test.go @@ -135,7 +135,7 @@ func TestScannerConfigurationPlainFailure(t *testing.T) { /*TestScannerCommentSuccess ... */ func TestScannerConfigurationCommentSuccess(t *testing.T) { - testScannerConfigurationSuccess(t, "[{comment}][{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}]groumpf[{endcomment}]", nil) testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}]", nil) testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}][{comment}]sss[{endcomment}]", nil) testScannerConfigurationSuccess(t, "[{comment}]foo[{bar}][{endcomment}]", nil) From dcc508bf113e3d43a8ff12c9f02398144f909824 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Thu, 18 Apr 2019 17:27:15 +0200 Subject: [PATCH 07/10] debugging --- qtc/scanner.go | 6 +++--- qtc/scanner_with_conf_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qtc/scanner.go b/qtc/scanner.go index 66a40a4..d3ee56a 100644 --- a/qtc/scanner.go +++ b/qtc/scanner.go @@ -308,7 +308,7 @@ func (s *scanner) readTagContents() bool { s.skipSpace() s.t.init(tagContents, s.line, s.pos()) for { - if s.c != s.openingTag[0] { + if s.c != s.closingTag[0] { s.appendByte() if !s.nextByte() { return false @@ -319,12 +319,12 @@ func (s *scanner) readTagContents() bool { s.appendByte() return false } - if s.c == s.openingTag[1] { + if s.c == s.closingTag[1] { s.nextTokenID = text s.t.Value = stripTrailingSpace(s.t.Value) return true } - s.unreadByte('%') + s.unreadByte(s.closingTag[0]) s.appendByte() if !s.nextByte() { return false diff --git a/qtc/scanner_with_conf_test.go b/qtc/scanner_with_conf_test.go index c0bb066..5250bbb 100644 --- a/qtc/scanner_with_conf_test.go +++ b/qtc/scanner_with_conf_test.go @@ -135,7 +135,7 @@ func TestScannerConfigurationPlainFailure(t *testing.T) { /*TestScannerCommentSuccess ... */ func TestScannerConfigurationCommentSuccess(t *testing.T) { - testScannerConfigurationSuccess(t, "[{comment}]groumpf[{endcomment}]", nil) + testScannerConfigurationSuccess(t, "[{comment}][{endcomment}]", nil) testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}]", nil) testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}][{comment}]sss[{endcomment}]", nil) testScannerConfigurationSuccess(t, "[{comment}]foo[{bar}][{endcomment}]", nil) From bbed6e16e2061f11d66c5e7b94228cde4678b165 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Thu, 18 Apr 2019 17:35:12 +0200 Subject: [PATCH 08/10] unit tests fixed. tag delimiters must be : - 2 characters - 2nd of start delimiter and 1st of end delimiter must be identical eg [% %] but not [{ }] where { <> } --- qtc/scanner_with_conf_test.go | 132 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/qtc/scanner_with_conf_test.go b/qtc/scanner_with_conf_test.go index 5250bbb..d3d8014 100644 --- a/qtc/scanner_with_conf_test.go +++ b/qtc/scanner_with_conf_test.go @@ -10,7 +10,7 @@ import ( /*TestScannerConfigurationTagNameWithDotAndEqual ..." */ func TestScannerConfigurationTagNameWithDotAndEqual(t *testing.T) { - testScannerConfigurationSuccess(t, "[{foo.bar.34 baz aaa}] awer[{ aa= }]", + testScannerConfigurationSuccess(t, "[%foo.bar.34 baz aaa%] awer[% aa= %]", []confToken{ {ID: tagName, Value: "foo.bar.34"}, {ID: tagContents, Value: "baz aaa"}, @@ -23,7 +23,7 @@ func TestScannerConfigurationTagNameWithDotAndEqual(t *testing.T) { /*TestScannerConfigurationStripspaceSuccess ... */ func TestScannerConfigurationStripspaceSuccess(t *testing.T) { - testScannerConfigurationSuccess(t, " aa\n\t [{stripspace}] \t\n f\too \n b ar \n\r\t [{ bar baz asd }]\n\nbaz \n\t \taaa \n[{endstripspace}] bb ", []confToken{ + testScannerConfigurationSuccess(t, " aa\n\t [%stripspace%] \t\n f\too \n b ar \n\r\t [% bar baz asd %]\n\nbaz \n\t \taaa \n[%endstripspace%] bb ", []confToken{ {ID: text, Value: " aa\n\t "}, {ID: text, Value: "f\toob ar"}, {ID: tagName, Value: "bar"}, @@ -31,13 +31,13 @@ func TestScannerConfigurationStripspaceSuccess(t *testing.T) { {ID: text, Value: "bazaaa"}, {ID: text, Value: " bb "}, }) - testScannerConfigurationSuccess(t, "[{stripspace }][{ stripspace fobar }] [{space}] a\taa\n\r\t bb b [{endstripspace }] [{endstripspace baz}]", []confToken{ + testScannerConfigurationSuccess(t, "[%stripspace %][% stripspace fobar %] [%space%] a\taa\n\r\t bb b [%endstripspace %] [%endstripspace baz%]", []confToken{ {ID: text, Value: " "}, {ID: text, Value: "a\taabb b"}, }) // sripspace wins over collapsespace - testScannerConfigurationSuccess(t, "[{stripspace}] [{collapsespace}]foo\n\t bar[{endcollapsespace}] \r\n\t [{endstripspace}]", []confToken{ + testScannerConfigurationSuccess(t, "[%stripspace%] [%collapsespace%]foo\n\t bar[%endcollapsespace%] \r\n\t [%endstripspace%]", []confToken{ {ID: text, Value: "foobar"}, }) } @@ -46,25 +46,25 @@ func TestScannerConfigurationStripspaceSuccess(t *testing.T) { */ func TestScannerConfigurationStripspaceFailure(t *testing.T) { // incomplete stripspace tag - testScannerConfigurationFailure(t, "[{stripspace ") + testScannerConfigurationFailure(t, "[%stripspace ") // incomplete endstripspace tag - testScannerConfigurationFailure(t, "[{stripspace}]aaa[{endstripspace") + testScannerConfigurationFailure(t, "[%stripspace%]aaa[%endstripspace") // missing endstripspace - testScannerConfigurationFailure(t, "[{stripspace}] foobar") + testScannerConfigurationFailure(t, "[%stripspace%] foobar") // missing stripspace - testScannerConfigurationFailure(t, "aaa[{endstripspace}]") + testScannerConfigurationFailure(t, "aaa[%endstripspace%]") // missing the second endstripspace - testScannerConfigurationFailure(t, "[{stripspace}][{stripspace}]aaaa[{endstripspace}]") + testScannerConfigurationFailure(t, "[%stripspace%][%stripspace%]aaaa[%endstripspace%]") } /*TestScannerConfigurationCollapsespaceSuccess ... */ func TestScannerConfigurationCollapsespaceSuccess(t *testing.T) { - testScannerConfigurationSuccess(t, " aa\n\t [{collapsespace}] \t\n foo \n bar[{ bar baz asd }]\n\nbaz \n \n[{endcollapsespace}] bb ", []confToken{ + testScannerConfigurationSuccess(t, " aa\n\t [%collapsespace%] \t\n foo \n bar[% bar baz asd %]\n\nbaz \n \n[%endcollapsespace%] bb ", []confToken{ {ID: text, Value: " aa\n\t "}, {ID: text, Value: " foo bar"}, {ID: tagName, Value: "bar"}, @@ -72,7 +72,7 @@ func TestScannerConfigurationCollapsespaceSuccess(t *testing.T) { {ID: text, Value: " baz "}, {ID: text, Value: " bb "}, }) - testScannerConfigurationSuccess(t, "[{collapsespace }][{ collapsespace fobar }] [{space}] aaa\n\r\t bbb [{endcollapsespace }] [{endcollapsespace baz}]", []confToken{ + testScannerConfigurationSuccess(t, "[%collapsespace %][% collapsespace fobar %] [%space%] aaa\n\r\t bbb [%endcollapsespace %] [%endcollapsespace baz%]", []confToken{ {ID: text, Value: " "}, {ID: text, Value: " "}, {ID: text, Value: " aaa bbb "}, @@ -84,65 +84,65 @@ func TestScannerConfigurationCollapsespaceSuccess(t *testing.T) { */ func TestScannerConfigurationCollapsespaceFailure(t *testing.T) { // incomplete collapsespace tag - testScannerConfigurationFailure(t, "[{collapsespace ") + testScannerConfigurationFailure(t, "[%collapsespace ") // incomplete endcollapsespace tag - testScannerConfigurationFailure(t, "[{collapsespace}]aaa[{endcollapsespace") + testScannerConfigurationFailure(t, "[%collapsespace%]aaa[%endcollapsespace") // missing endcollapsespace - testScannerConfigurationFailure(t, "[{collapsespace}] foobar") + testScannerConfigurationFailure(t, "[%collapsespace%] foobar") // missing collapsespace - testScannerConfigurationFailure(t, "aaa[{endcollapsespace}]") + testScannerConfigurationFailure(t, "aaa[%endcollapsespace%]") // missing the second endcollapsespace - testScannerConfigurationFailure(t, "[{collapsespace}][{collapsespace}]aaaa[{endcollapsespace}]") + testScannerConfigurationFailure(t, "[%collapsespace%][%collapsespace%]aaaa[%endcollapsespace%]") } /*TestScannerPlainSuccess ... */ func TestScannerConfigurationPlainSuccess(t *testing.T) { - testScannerConfigurationSuccess(t, "[{plain}][{endplain}]", nil) - testScannerConfigurationSuccess(t, "[{plain}][{foo bar}]asdf[{endplain}]", []confToken{ - {ID: text, Value: "[{foo bar}]asdf"}, + testScannerConfigurationSuccess(t, "[%plain%][%endplain%]", nil) + testScannerConfigurationSuccess(t, "[%plain%][%foo bar%]asdf[%endplain%]", []confToken{ + {ID: text, Value: "[%foo bar%]asdf"}, }) - testScannerConfigurationSuccess(t, "[{plain}][{foo[{endplain}]", []confToken{ - {ID: text, Value: "[{foo"}, + testScannerConfigurationSuccess(t, "[%plain%][%foo[%endplain%]", []confToken{ + {ID: text, Value: "[%foo"}, }) - testScannerConfigurationSuccess(t, "aa[{plain}]bbb[{cc}][{endplain}][{plain}]dsff[{endplain}]", []confToken{ + testScannerConfigurationSuccess(t, "aa[%plain%]bbb[%cc%][%endplain%][%plain%]dsff[%endplain%]", []confToken{ {ID: text, Value: "aa"}, - {ID: text, Value: "bbb[{cc}]"}, + {ID: text, Value: "bbb[%cc%]"}, {ID: text, Value: "dsff"}, }) - testScannerConfigurationSuccess(t, "mmm[{plain}]aa[{ bar [{%% }baz[{endplain}]nnn", []confToken{ + testScannerConfigurationSuccess(t, "mmm[%plain%]aa[% bar [%%% }baz[%endplain%]nnn", []confToken{ {ID: text, Value: "mmm"}, - {ID: text, Value: "aa[{ bar [{%% }baz"}, + {ID: text, Value: "aa[% bar [%%% }baz"}, {ID: text, Value: "nnn"}, }) - testScannerConfigurationSuccess(t, "[{ plain dsd }]0[{comment}]123[{endcomment}]45[{ endplain aaa }]", []confToken{ - {ID: text, Value: "0[{comment}]123[{endcomment}]45"}, + testScannerConfigurationSuccess(t, "[% plain dsd %]0[%comment%]123[%endcomment%]45[% endplain aaa %]", []confToken{ + {ID: text, Value: "0[%comment%]123[%endcomment%]45"}, }) } /*TestScannerPlainFailure ... */ func TestScannerConfigurationPlainFailure(t *testing.T) { - testScannerConfigurationFailure(t, "[{plain}]sdfds") - testScannerConfigurationFailure(t, "[{plain}]aaaa%[{endplain") - testScannerConfigurationFailure(t, "[{plain}][{endplain%") + testScannerConfigurationFailure(t, "[%plain%]sdfds") + testScannerConfigurationFailure(t, "[%plain%]aaaa%[%endplain") + testScannerConfigurationFailure(t, "[%plain%][%endplain%") } /*TestScannerCommentSuccess ... */ func TestScannerConfigurationCommentSuccess(t *testing.T) { - testScannerConfigurationSuccess(t, "[{comment}][{endcomment}]", nil) - testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}]", nil) - testScannerConfigurationSuccess(t, "[{comment}]foo[{endcomment}][{comment}]sss[{endcomment}]", nil) - testScannerConfigurationSuccess(t, "[{comment}]foo[{bar}][{endcomment}]", nil) - testScannerConfigurationSuccess(t, "[{comment}]foo[{bar [{endcomment}]", nil) - testScannerConfigurationSuccess(t, "[{comment}]foo[{bar&^[{endcomment}]", nil) - testScannerConfigurationSuccess(t, "[{comment}]foo[{ bar\n\rs%[{endcomment}]", nil) - testScannerConfigurationSuccess(t, "xx[{x}]www[{ comment aux data }]aaa[{ comment }][{ endcomment }]yy", []confToken{ + testScannerConfigurationSuccess(t, "[%comment%][%endcomment%]", nil) + testScannerConfigurationSuccess(t, "[%comment%]foo[%endcomment%]", nil) + testScannerConfigurationSuccess(t, "[%comment%]foo[%endcomment%][%comment%]sss[%endcomment%]", nil) + testScannerConfigurationSuccess(t, "[%comment%]foo[%bar%][%endcomment%]", nil) + testScannerConfigurationSuccess(t, "[%comment%]foo[%bar [%endcomment%]", nil) + testScannerConfigurationSuccess(t, "[%comment%]foo[%bar&^[%endcomment%]", nil) + testScannerConfigurationSuccess(t, "[%comment%]foo[% bar\n\rs%[%endcomment%]", nil) + testScannerConfigurationSuccess(t, "xx[%x%]www[% comment aux data %]aaa[% comment %][% endcomment %]yy", []confToken{ {ID: text, Value: "xx"}, {ID: tagName, Value: "x"}, {ID: tagContents, Value: ""}, @@ -154,40 +154,40 @@ func TestScannerConfigurationCommentSuccess(t *testing.T) { /*TestScannerCommentFailure ... */ func TestScannerConfigurationCommentFailure(t *testing.T) { - testScannerConfigurationFailure(t, "[{comment}]...no endcomment") - testScannerConfigurationFailure(t, "[{ comment }]foobar[{ endcomment") + testScannerConfigurationFailure(t, "[%comment%]...no endcomment") + testScannerConfigurationFailure(t, "[% comment %]foobar[% endcomment") } func TestScannerConfigurationSuccess(t *testing.T) { testScannerConfigurationSuccess(t, "", nil) - testScannerConfigurationSuccess(t, "a}]{foo}bar", []confToken{ - {ID: text, Value: "a}]{foo}bar"}, + testScannerConfigurationSuccess(t, "a%]{foo}bar", []confToken{ + {ID: text, Value: "a%]{foo}bar"}, }) - testScannerConfigurationSuccess(t, "[{ foo bar baz(a, b, 123) }]", []confToken{ + testScannerConfigurationSuccess(t, "[% foo bar baz(a, b, 123) %]", []confToken{ {ID: tagName, Value: "foo"}, {ID: tagContents, Value: "bar baz(a, b, 123)"}, }) - testScannerConfigurationSuccess(t, "foo[{bar}]baz", []confToken{ + testScannerConfigurationSuccess(t, "foo[%bar%]baz", []confToken{ {ID: text, Value: "foo"}, {ID: tagName, Value: "bar"}, {ID: tagContents, Value: ""}, {ID: text, Value: "baz"}, }) - testScannerConfigurationSuccess(t, "{{[{\n\r\tfoo bar\n\rbaz%%\n \r }]}", []confToken{ + testScannerConfigurationSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r %]}", []confToken{ {ID: text, Value: "{{"}, {ID: tagName, Value: "foo"}, {ID: tagContents, Value: "bar\n\rbaz%%"}, {ID: text, Value: "}"}, }) - testScannerConfigurationSuccess(t, "[{}]", []confToken{ + testScannerConfigurationSuccess(t, "[%%]", []confToken{ {ID: tagName, Value: ""}, {ID: tagContents, Value: ""}, }) - testScannerConfigurationSuccess(t, "[{%aaa bb}]", []confToken{ + testScannerConfigurationSuccess(t, "[%%aaa bb%]", []confToken{ {ID: tagName, Value: ""}, {ID: tagContents, Value: "%aaa bb"}, }) - testScannerConfigurationSuccess(t, "foo[{ bar }][{ baz aa (123)}]321", []confToken{ + testScannerConfigurationSuccess(t, "foo[% bar %][% baz aa (123)%]321", []confToken{ {ID: text, Value: "foo"}, {ID: tagName, Value: "bar"}, {ID: tagContents, Value: ""}, @@ -200,17 +200,17 @@ func TestScannerConfigurationSuccess(t *testing.T) { /*TestScannerConfigurationFailure ... */ func TestScannerConfigurationFailure(t *testing.T) { - testScannerConfigurationFailure(t, "a[{") - testScannerConfigurationFailure(t, "a[{foo") - testScannerConfigurationFailure(t, "a[{% }foo") - testScannerConfigurationFailure(t, "a[{ foo %") - testScannerConfigurationFailure(t, "b[{ fo() }]bar") - testScannerConfigurationFailure(t, "aa[{ foo bar") + testScannerConfigurationFailure(t, "a[%") + testScannerConfigurationFailure(t, "a[%foo") + testScannerConfigurationFailure(t, "a[%% }foo") + testScannerConfigurationFailure(t, "a[% foo %") + testScannerConfigurationFailure(t, "b[% fo() %]bar") + testScannerConfigurationFailure(t, "aa[% foo bar") } func testScannerConfigurationFailure(t *testing.T, str string) { r := bytes.NewBufferString(str) - s := newScannerWithTagConf(r, "memory", "[{", "}]") + s := newScannerWithTagConf(r, "memory", "[%", "%]") var tokens []confToken for s.Next() { id := s.Token().ID @@ -228,7 +228,7 @@ func testScannerConfigurationFailure(t *testing.T, str string) { func testScannerConfigurationSuccess(t *testing.T, str string, expectedTokens []confToken) { r := bytes.NewBufferString(str) - s := newScannerWithTagConf(r, "memory", "[{", "}]") + s := newScannerWithTagConf(r, "memory", "[%", "%]") var tokens []confToken for s.Next() { tokens = append(tokens, confToken{ @@ -261,7 +261,7 @@ func testScannerConfigurationSuccess(t *testing.T, str string, expectedTokens [] // {ID: tagContents, Value: ""}, // {ID: text, Value: "baz"}, // }) -// testScannerConfigurationSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r }]}", []confToken{ +// testScannerConfigurationSuccess(t, "{{[%\n\r\tfoo bar\n\rbaz%%\n \r %]}", []confToken{ // {ID: text, Value: "{{"}, // {ID: tagName, Value: "foo"}, // {ID: tagContents, Value: "bar\n\rbaz%%"}, @@ -304,33 +304,33 @@ Page { Title() Body() } -}] +%] Page prints a page implementing Page interface. -[{ func PageTemplate(p Page) }] +[% func PageTemplate(p Page) %] - {%= p.Title() }] + {%= p.Title() %] - [{= p.Body() }] + [%= p.Body() %] -[{ endfunc }] +[% endfunc %] Base page implementation. Other pages may inherit from it if they need overriding only certain Page methods -[{ code type BasePage struct {} }] -[{ func (p *BasePage) Title() }]This is a base title[{ endfunc }] -[{ func (p *BasePage) Body() }]This is a base body[{ endfunc }] +[% code type BasePage struct {} %] +[% func (p *BasePage) Title() %]This is a base title[% endfunc %] +[% func (p *BasePage) Body() %]This is a base body[% endfunc %] }` r := bytes.NewBufferString(source) - s := newScannerWithTagConf(r, "memory", "[{", "}]") + s := newScannerWithTagConf(r, "memory", "[%", "%]") var tokens []confToken for s.Next() { tokens = append(tokens, confToken{ From 7ad945f66d52e76e8e54c507ce3a06633471bdf9 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Fri, 19 Apr 2019 10:30:52 +0200 Subject: [PATCH 09/10] issuer #37 : add sTag (satring tag delimiter) and eTag (endingTagDelimiter) qtc arguments --- qtc/main.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/qtc/main.go b/qtc/main.go index 06b02ff..11030d3 100644 --- a/qtc/main.go +++ b/qtc/main.go @@ -21,17 +21,38 @@ var ( "Flags -dir and -ext are ignored if file is set.\n"+ "The compiled file will be placed near the original file with .go extension added.") ext = flag.String("ext", "qtpl", "Only files with this extension are compiled") + s = flag.String("s", "", "starting") startTag = flag.String("sTag", "{%", "tag starting delimiter (2 chars)") - endTag = flag.String("eTag", "{%", "tag ending delimiter (2 chars)") + endTag = flag.String("eTag", "%}", "tag ending delimiter (2 chars)") ) var logger = log.New(os.Stderr, "qtc: ", log.LstdFlags) var filesCompiled int +func checkDelimiters() { + start := *startTag + end := *endTag + + if len(start) != 2 { + logger.Fatalf("tag starting delimiter '%s' must be 2 chars length", start) + } + if len(end) != 2 { + logger.Fatalf("tag ending delimiter '%s' must be 2 chars length", end) + } + + if start[1] != end[0] { + logger.Fatalf("starting delimiter last char ('%s') and ending delimiter first char ('%s') must be the same", string(start[1]), string(end[0])) + } + +} + func main() { + flag.Parse() + checkDelimiters() + if len(*file) > 0 { compileSingleFile(*file) return From b2154b43959f4a03db05c5b41aa968a8c75ae083 Mon Sep 17 00:00:00 2001 From: b3b00 Date: Fri, 19 Apr 2019 17:21:44 +0200 Subject: [PATCH 10/10] cleaning --- qtc/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/qtc/main.go b/qtc/main.go index 11030d3..007f2ef 100644 --- a/qtc/main.go +++ b/qtc/main.go @@ -21,7 +21,6 @@ var ( "Flags -dir and -ext are ignored if file is set.\n"+ "The compiled file will be placed near the original file with .go extension added.") ext = flag.String("ext", "qtpl", "Only files with this extension are compiled") - s = flag.String("s", "", "starting") startTag = flag.String("sTag", "{%", "tag starting delimiter (2 chars)") endTag = flag.String("eTag", "%}", "tag ending delimiter (2 chars)") )