github.com/ronaksoft/rony@v0.16.26-0.20230807065236-1743dbfe6959/internal/parser/parse.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package parse builds parse trees for templates as defined by text/template
     6  // and html/template. Clients should use those packages to construct templates
     7  // rather than this one, which provides shared internal data structures not
     8  // intended for general use.
     9  package parse
    10  
    11  import (
    12  	"fmt"
    13  	"runtime"
    14  )
    15  
    16  // Tree is the representation of a single parsed template.
    17  type Tree struct {
    18  	Name      string    // name of the template represented by the tree.
    19  	ParseName string    // name of the top-level template during parsing, for error messages.
    20  	Root      *ListNode // top-level root of the tree.
    21  	text      string    // text parsed to create the template (or its parent)
    22  	// Parsing only; cleared after parse.
    23  	lex       *lexer
    24  	token     [3]tokenItem // three-token lookahead for parser.
    25  	peekCount int
    26  }
    27  
    28  // Copy returns a copy of the Tree. Any parsing state is discarded.
    29  func (t *Tree) Copy() *Tree {
    30  	if t == nil {
    31  		return nil
    32  	}
    33  
    34  	return &Tree{
    35  		Name:      t.Name,
    36  		ParseName: t.ParseName,
    37  		Root:      t.Root.CopyList(),
    38  		text:      t.text,
    39  	}
    40  }
    41  
    42  // Parse returns a map from template name to parse.Tree, created by parsing the
    43  // templates described in the argument string. The top-level template will be
    44  // given the specified name. If an error is encountered, parsing stops and an
    45  // empty map is returned with the error.
    46  func Parse(name, text string) (*Tree, error) {
    47  	t := New(name)
    48  	t.text = text
    49  	_, err := t.Parse(text)
    50  
    51  	return t, err
    52  }
    53  
    54  // next returns the next token.
    55  func (t *Tree) next() tokenItem {
    56  	if t.peekCount > 0 {
    57  		t.peekCount--
    58  	} else {
    59  		t.token[0] = t.lex.nextItem()
    60  	}
    61  
    62  	return t.token[t.peekCount]
    63  }
    64  
    65  // backup backs the input stream up one token.
    66  func (t *Tree) backup() {
    67  	t.peekCount++
    68  }
    69  
    70  // peek returns but does not consume the next token.
    71  func (t *Tree) peek() tokenItem {
    72  	if t.peekCount > 0 {
    73  		return t.token[t.peekCount-1]
    74  	}
    75  	t.peekCount = 1
    76  	t.token[0] = t.lex.nextItem()
    77  
    78  	return t.token[0]
    79  }
    80  
    81  // nextNonSpace returns the next non-space token.
    82  func (t *Tree) nextNonSpace() (token tokenItem) {
    83  	for {
    84  		token = t.next()
    85  		if token.tok != SPACE {
    86  			break
    87  		}
    88  	}
    89  
    90  	return token
    91  }
    92  
    93  // New allocates a new parse tree with the given name.
    94  func New(name string) *Tree {
    95  	return &Tree{
    96  		Name: name,
    97  	}
    98  }
    99  
   100  // errorf formats the error and terminates processing.
   101  func (t *Tree) errorf(format string, args ...interface{}) {
   102  	t.Root = nil
   103  	format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
   104  	panic(fmt.Errorf(format, args...))
   105  }
   106  
   107  // unexpected complains about the token and terminates processing.
   108  func (t *Tree) unexpected(token tokenItem, context string) {
   109  	t.errorf("unexpected %s in %s", token, context)
   110  }
   111  
   112  // recover is the handler that turns panics into returns from the top level of Parse.
   113  func (t *Tree) recover(errp *error) {
   114  	e := recover()
   115  	if e != nil {
   116  		if _, ok := e.(runtime.Error); ok {
   117  			panic(e)
   118  		}
   119  		if t != nil {
   120  			t.lex.drain()
   121  			t.stopParse()
   122  		}
   123  		*errp = e.(error)
   124  	}
   125  }
   126  
   127  // startParse initializes the parser, using the lexer.
   128  func (t *Tree) startParse(lex *lexer) {
   129  	t.Root = nil
   130  	t.lex = lex
   131  }
   132  
   133  // stopParse terminates parsing.
   134  func (t *Tree) stopParse() {
   135  	t.lex = nil
   136  }
   137  
   138  // Parse parses the template definition string to construct a representation of
   139  // the template for execution. If either action delimiter string is empty, the
   140  // default ("{{" or "}}") is used. Embedded template definitions are added to
   141  // the treeSet map.
   142  func (t *Tree) Parse(text string) (tree *Tree, err error) {
   143  	defer t.recover(&err)
   144  	t.ParseName = t.Name
   145  	t.startParse(lex(t.Name, text))
   146  	t.text = text
   147  	t.parse()
   148  	t.stopParse()
   149  
   150  	return t, nil
   151  }
   152  
   153  // parse is the top-level parser for a template, essentially the same
   154  // as itemList except it also parses {{define}} actions.
   155  // It runs to EOF.
   156  func (t *Tree) parse() {
   157  	t.Root = t.newList(t.peek().pos)
   158  	for t.peek().tok != EOF {
   159  		switch item := t.nextNonSpace(); item.tok {
   160  		case TEXT:
   161  			t.Root.append(t.newText(item.pos, item.val))
   162  		case L_DELIM:
   163  			item = t.nextNonSpace()
   164  			t.Root.append(t.action())
   165  		default:
   166  			t.unexpected(item, "input")
   167  		}
   168  	}
   169  }
   170  
   171  // Action:
   172  //	model, table, view, counter , ...
   173  // Left delim is past. Now get actions.
   174  func (t *Tree) action() (n Node) {
   175  	switch item := t.nextNonSpace(); item.tok {
   176  	case MODEL:
   177  		n = t.model(item.pos)
   178  	case TABLE:
   179  		n = t.table(item.pos)
   180  	case VIEW:
   181  		n = t.view(item.pos)
   182  	case COUNTER:
   183  		n = t.counter(item.pos)
   184  	default:
   185  		t.unexpected(item, "action")
   186  	}
   187  	if item := t.nextNonSpace(); item.tok != R_DELIM {
   188  		t.unexpected(item, "action right delmic")
   189  	}
   190  
   191  	return
   192  }
   193  
   194  func (t *Tree) model(pos Pos) (n Node) {
   195  	switch item := t.nextNonSpace(); item.tok {
   196  	case IDENT:
   197  		return t.newModel(pos, item.val)
   198  	default:
   199  		t.unexpected(item, "model")
   200  	}
   201  
   202  	panic("unreachable code")
   203  }
   204  
   205  func (t *Tree) idents() []string {
   206  	var args []string
   207  Loop:
   208  	for {
   209  		item := t.nextNonSpace()
   210  		switch item.tok {
   211  		case IDENT:
   212  			args = append(args, item.val)
   213  		case COMMA:
   214  		case R_PAREN:
   215  			break Loop
   216  		default:
   217  			t.unexpected(item, "idents")
   218  		}
   219  	}
   220  
   221  	return args
   222  }
   223  
   224  func (t *Tree) table(pos Pos) (n Node) {
   225  	var (
   226  		pks, cks []string
   227  	)
   228  	// we must see at least one '('
   229  	if item := t.nextNonSpace(); item.tok != L_PAREN {
   230  		t.unexpected(item, "table")
   231  	}
   232  
   233  	// if we see second '(' then we have composed partition keys
   234  	switch item := t.nextNonSpace(); item.tok {
   235  	case L_PAREN:
   236  		pks = t.idents()
   237  		cks = t.idents()
   238  	default:
   239  		// put back to buffer, since we did not pick '('
   240  		t.backup()
   241  
   242  		ks := t.idents()
   243  		switch len(ks) {
   244  		case 0:
   245  			t.errorf("no primary key for table: (%d:%d)", item.line, item.pos)
   246  		case 1:
   247  			pks = append(pks, ks[0])
   248  		default:
   249  			pks = append(pks, ks[0])
   250  			cks = append(cks, ks[1:]...)
   251  		}
   252  	}
   253  
   254  	return t.newTable(pos, pks, cks)
   255  }
   256  
   257  func (t *Tree) view(pos Pos) (n Node) {
   258  	var (
   259  		pks, cks []string
   260  	)
   261  	// we must see at least one '('
   262  	if item := t.nextNonSpace(); item.tok != L_PAREN {
   263  		t.unexpected(item, "table")
   264  	}
   265  
   266  	// if we see second '(' then we have composed partition keys
   267  	switch item := t.nextNonSpace(); item.tok {
   268  	case L_PAREN:
   269  		pks = t.idents()
   270  		cks = t.idents()
   271  	default:
   272  		// put back to buffer, since we did not pick '('
   273  		t.backup()
   274  
   275  		ks := t.idents()
   276  		switch len(ks) {
   277  		case 0:
   278  			t.errorf("no primary key for view: (%d:%d)", item.line, item.pos)
   279  		case 1:
   280  			pks = append(pks, ks[0])
   281  		default:
   282  			pks = append(pks, ks[0])
   283  			cks = append(cks, ks[1:]...)
   284  		}
   285  	}
   286  
   287  	return t.newView(pos, pks, cks)
   288  }
   289  
   290  func (t *Tree) counter(pos Pos) (n Node) {
   291  	switch item := t.nextNonSpace(); item.tok {
   292  	case IDENT:
   293  		return t.newCounter(pos, item.val)
   294  	default:
   295  		t.unexpected(item, "counter")
   296  	}
   297  
   298  	panic("unreachable code")
   299  }