code: func (p *Parser) parseColumnIndexColumns(ctx *parseCtx, container interface {
  	AddColumns(...model.IndexColumn)
  }) error {
  
  	var cols []model.IndexColumn
  
  	ctx.skipWhiteSpaces()
  	if t := ctx.next(); t.Type != LPAREN {
  		return newParseError(ctx, t, "expected LPAREN while parsing index column: %s", t.Type)
  	}
  
  OUTER:
  	for {
  		ctx.skipWhiteSpaces()
  		t := ctx.next()
  		if !(t.Type == IDENT || t.Type == BACKTICK_IDENT) {
  			return newParseError(ctx, t, "should IDENT or BACKTICK_IDENT")
  		}
  
  		col := model.NewIndexColumn(t.Value)
  		cols = append(cols, col)
  
  		ctx.skipWhiteSpaces()
  		switch t = ctx.next(); t.Type {
  		case LPAREN:
  			t := ctx.next()
  			if t.Type != NUMBER {
  				return newParseError(ctx, t, "expected NUMBER")
  			}
  			tlen := t.Value
  			ctx.skipWhiteSpaces()
  			if t = ctx.next(); t.Type != RPAREN {
  				return newParseError(ctx, t, "expected RPAREN")
  			}
  			col.SetLength(tlen)
  		default:
  			ctx.rewind()
  		}
  
  		// optional sort direction
  		switch t = ctx.peek(); t.Type {
  		case ASC:
  			ctx.advance()
  			col.SetSortDirection(model.SortDirectionAscending)
  		case DESC:
  			ctx.advance()
  			col.SetSortDirection(model.SortDirectionDescending)
  		}
  
  		ctx.skipWhiteSpaces()
  		switch t = ctx.next(); t.Type {
  		case COMMA:
  			// search next
  			continue
  		case RPAREN:
  			break OUTER
  		default:
  			return newParseError(ctx, t, "expected COMMA or RPAREN")
  		}
  	}
  
  	container.AddColumns(cols...)
  	return nil
  }
docs: // TODO rename method name