123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package metla
- import (
- "bytes"
- "fmt"
- "log"
- )
- type tokenType uint8
- const (
- tokenTypeUndefined tokenType = iota
- tokenTypeText
- tokenTypePrint
- tokenTypeComment
- tokenTypeExec
- tokenTypeLiteral
- )
- func (s tokenType) closeTag() byte {
- switch s {
- case tokenTypePrint:
- return '}'
- case tokenTypeExec:
- return '%'
- case tokenTypeComment:
- return '*'
- default:
- return 0
- }
- }
- func (s tokenType) String() string {
- switch s {
- case tokenTypeUndefined:
- return "Undefined"
- case tokenTypeText:
- return "Text"
- case tokenTypePrint:
- return "Print"
- case tokenTypeComment:
- return "Comment"
- case tokenTypeExec:
- return "Exec"
- case tokenTypeLiteral:
- return "Literal"
- default:
- return ""
- }
- }
- type tError struct {
- alias string
- line int
- pos int
- text string
- }
- func (s tError) Error() string {
- return fmt.Sprintf("%v :: Parse error [%v:%v] : %v", s.alias, s.line, s.pos, s.text)
- }
- func parseBytes(src []byte, alias string) (res []byte, err error) {
- log.Println("parse bytes")
- var rb bytes.Buffer
- lp, lastPos, lastLine := lineParser{src: src}, 0, 0
- flushTokenText := func(fromToken bool) {
- if lastPos != lp.Pos() {
- offset := -1
- if fromToken {
- offset = 1
- }
- rb.Write([]byte("flush('"))
- bl := lp.Block(lastPos, offset)
- rpl := bytes.ReplaceAll(bl, []byte("'"), []byte("\\'"))
- rpl = bytes.ReplaceAll(rpl, []byte{13}, []byte(""))
- rpl = bytes.ReplaceAll(rpl, []byte("\n"), []byte("\\n"))
- rb.Write(rpl)
- rb.Write([]byte("');"))
- lastPos, lastLine = lp.Pos(), lp.Line()
- }
- }
- initToken := func() error {
- val, tType := lp.Val(), tokenTypeUndefined
- switch val {
- case '{':
- tType = tokenTypePrint
- case '*':
- tType = tokenTypeComment
- case '%':
- tType = tokenTypeExec
- default:
- return nil
- }
- flushTokenText(true)
- for lp.FindNext(tType.closeTag()) {
- if lp.Next() && lp.Val() == '}' {
- switch tType {
- case tokenTypePrint:
- {
- rb.Write([]byte("flush("))
- rb.Write(lp.Block(lastPos+2, 2))
- rb.Write([]byte(");"))
- }
- case tokenTypeExec:
- rb.Write(lp.Block(lastPos+2, 2))
- rb.Write([]byte(";"))
- }
- lp.Next()
- lastPos, lastLine = lp.Pos(), lp.Line()
- return nil
- }
- }
- return tError{
- alias: alias,
- line: lastLine,
- pos: lastPos,
- text: fmt.Sprintf("Not found close token for '%v}'", string(tType.closeTag())),
- }
- }
- for lp.CheckNext() {
- if lp.FindNext('{') && lp.Next() {
- if err = initToken(); err != nil {
- return
- }
- }
- }
- flushTokenText(false)
- res = rb.Bytes()
- return
- }
- type lineParser struct {
- src []byte
- pos int
- line int
- }
- func (s *lineParser) CheckNext() bool {
- return s.pos < len(s.src)-1
- }
- func (s *lineParser) Next() bool {
- if s.CheckNext() {
- s.pos++
- if s.src[s.pos] == '\n' {
- s.line++
- }
- return true
- }
- return false
- }
- func (s *lineParser) Block(start int, offsetRight int) []byte {
- return s.src[start : s.pos-offsetRight]
- }
- func (s *lineParser) Line() int { return s.line }
- func (s *lineParser) Pos() int { return s.pos }
- func (s *lineParser) Val() byte { return s.src[s.pos] }
- func (s *lineParser) FindNext(val byte) bool {
- for {
- if s.Val() == val {
- return true
- }
- if !s.Next() {
- return false
- }
- }
- }
|